diff options
Diffstat (limited to 'JavaScriptCore/VM/CTI.h')
-rw-r--r-- | JavaScriptCore/VM/CTI.h | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/JavaScriptCore/VM/CTI.h b/JavaScriptCore/VM/CTI.h new file mode 100644 index 0000000..04bb6ca --- /dev/null +++ b/JavaScriptCore/VM/CTI.h @@ -0,0 +1,475 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CTI_h +#define CTI_h + +#if ENABLE(CTI) + +#define WTF_USE_CTI_REPATCH_PIC 1 + +#include "Machine.h" +#include "Opcode.h" +#include "RegisterFile.h" +#include <masm/X86Assembler.h> +#include <profiler/Profiler.h> +#include <wtf/AlwaysInline.h> +#include <wtf/Vector.h> + +#define CTI_ARGS_code 0x0C +#define CTI_ARGS_registerFile 0x0D +#define CTI_ARGS_callFrame 0x0E +#define CTI_ARGS_exception 0x0F +#define CTI_ARGS_profilerReference 0x10 +#define CTI_ARGS_globalData 0x11 + +#define ARG_callFrame static_cast<CallFrame*>(ARGS[CTI_ARGS_callFrame]) +#define ARG_registerFile static_cast<RegisterFile*>(ARGS[CTI_ARGS_registerFile]) +#define ARG_exception static_cast<JSValue**>(ARGS[CTI_ARGS_exception]) +#define ARG_profilerReference static_cast<Profiler**>(ARGS[CTI_ARGS_profilerReference]) +#define ARG_globalData static_cast<JSGlobalData*>(ARGS[CTI_ARGS_globalData]) + +#define ARG_setCallFrame(newCallFrame) (ARGS[CTI_ARGS_callFrame] = (newCallFrame)) + +#define ARG_src1 static_cast<JSValue*>(ARGS[1]) +#define ARG_src2 static_cast<JSValue*>(ARGS[2]) +#define ARG_src3 static_cast<JSValue*>(ARGS[3]) +#define ARG_src4 static_cast<JSValue*>(ARGS[4]) +#define ARG_src5 static_cast<JSValue*>(ARGS[5]) +#define ARG_id1 static_cast<Identifier*>(ARGS[1]) +#define ARG_id2 static_cast<Identifier*>(ARGS[2]) +#define ARG_id3 static_cast<Identifier*>(ARGS[3]) +#define ARG_id4 static_cast<Identifier*>(ARGS[4]) +#define ARG_int1 reinterpret_cast<intptr_t>(ARGS[1]) +#define ARG_int2 reinterpret_cast<intptr_t>(ARGS[2]) +#define ARG_int3 reinterpret_cast<intptr_t>(ARGS[3]) +#define ARG_int4 reinterpret_cast<intptr_t>(ARGS[4]) +#define ARG_int5 reinterpret_cast<intptr_t>(ARGS[5]) +#define ARG_int6 reinterpret_cast<intptr_t>(ARGS[6]) +#define ARG_func1 static_cast<FuncDeclNode*>(ARGS[1]) +#define ARG_funcexp1 static_cast<FuncExprNode*>(ARGS[1]) +#define ARG_registers1 static_cast<Register*>(ARGS[1]) +#define ARG_regexp1 static_cast<RegExp*>(ARGS[1]) +#define ARG_pni1 static_cast<JSPropertyNameIterator*>(ARGS[1]) +#define ARG_instr1 static_cast<Instruction*>(ARGS[1]) +#define ARG_instr2 static_cast<Instruction*>(ARGS[2]) +#define ARG_instr3 static_cast<Instruction*>(ARGS[3]) +#define ARG_instr4 static_cast<Instruction*>(ARGS[4]) +#define ARG_instr5 static_cast<Instruction*>(ARGS[5]) +#define ARG_instr6 static_cast<Instruction*>(ARGS[6]) +#define ARG_linkInfo2 static_cast<CallLinkInfo*>(ARGS[2]) + +#define CTI_RETURN_ADDRESS_SLOT (ARGS[-1]) + +#if COMPILER(MSVC) +#define FASTCALL __fastcall +#elif COMPILER(GCC) +#define FASTCALL __attribute__ ((fastcall)) +#else +#error Need to support fastcall calling convention in this compiler +#endif + +namespace JSC { + + class CodeBlock; + class JSPropertyNameIterator; + class Machine; + class Register; + class RegisterFile; + class ScopeChainNode; + class SimpleJumpTable; + class StringJumpTable; + class StructureIDChain; + + struct CallLinkInfo; + struct Instruction; + struct OperandTypes; + + typedef JSValue* (SFX_CALL *CTIHelper_j)(CTI_ARGS); + typedef JSObject* (SFX_CALL *CTIHelper_o)(CTI_ARGS); + typedef JSPropertyNameIterator* (SFX_CALL *CTIHelper_p)(CTI_ARGS); + typedef void (SFX_CALL *CTIHelper_v)(CTI_ARGS); + typedef void* (SFX_CALL *CTIHelper_s)(CTI_ARGS); + typedef int (SFX_CALL *CTIHelper_b)(CTI_ARGS); + typedef VoidPtrPair (SFX_CALL *CTIHelper_2)(CTI_ARGS); + + struct CallRecord { + X86Assembler::JmpSrc from; + void* to; + unsigned opcodeIndex; + + CallRecord() + { + } + + CallRecord(X86Assembler::JmpSrc f, CTIHelper_j t, unsigned i) + : from(f) + , to(reinterpret_cast<void*>(t)) + , opcodeIndex(i) + { + } + + CallRecord(X86Assembler::JmpSrc f, CTIHelper_o t, unsigned i) + : from(f) + , to(reinterpret_cast<void*>(t)) + , opcodeIndex(i) + { + } + + CallRecord(X86Assembler::JmpSrc f, CTIHelper_p t, unsigned i) + : from(f) + , to(reinterpret_cast<void*>(t)) + , opcodeIndex(i) + { + } + + CallRecord(X86Assembler::JmpSrc f, CTIHelper_v t, unsigned i) + : from(f) + , to(reinterpret_cast<void*>(t)) + , opcodeIndex(i) + { + } + + CallRecord(X86Assembler::JmpSrc f, CTIHelper_s t, unsigned i) + : from(f) + , to(reinterpret_cast<void*>(t)) + , opcodeIndex(i) + { + } + + CallRecord(X86Assembler::JmpSrc f, CTIHelper_b t, unsigned i) + : from(f) + , to(reinterpret_cast<void*>(t)) + , opcodeIndex(i) + { + } + + CallRecord(X86Assembler::JmpSrc f, CTIHelper_2 t, unsigned i) + : from(f) + , to(reinterpret_cast<void*>(t)) + , opcodeIndex(i) + { + } + + CallRecord(X86Assembler::JmpSrc f, unsigned i) + : from(f) + , to(0) + , opcodeIndex(i) + { + } + }; + + struct JmpTable { + X86Assembler::JmpSrc from; + unsigned to; + + JmpTable(X86Assembler::JmpSrc f, unsigned t) + : from(f) + , to(t) + { + } + }; + + struct SlowCaseEntry { + X86Assembler::JmpSrc from; + unsigned to; + unsigned hint; + + SlowCaseEntry(X86Assembler::JmpSrc f, unsigned t, unsigned h = 0) + : from(f) + , to(t) + , hint(h) + { + } + }; + + struct SwitchRecord { + enum Type { + Immediate, + Character, + String + }; + + Type m_type; + + union { + SimpleJumpTable* m_simpleJumpTable; + StringJumpTable* m_stringJumpTable; + } m_jumpTable; + + unsigned m_opcodeIndex; + unsigned m_defaultOffset; + + SwitchRecord(SimpleJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset, Type type) + : m_type(type) + , m_opcodeIndex(opcodeIndex) + , m_defaultOffset(defaultOffset) + { + m_jumpTable.m_simpleJumpTable = jumpTable; + } + + SwitchRecord(StringJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset) + : m_type(String) + , m_opcodeIndex(opcodeIndex) + , m_defaultOffset(defaultOffset) + { + m_jumpTable.m_stringJumpTable = jumpTable; + } + }; + + struct StructureStubCompilationInfo { + X86Assembler::JmpSrc callReturnLocation; + X86Assembler::JmpDst hotPathBegin; + X86Assembler::JmpSrc hotPathOther; + X86Assembler::JmpDst coldPathOther; + }; + + extern "C" { + JSValue* ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue** exception, Profiler**, JSGlobalData*); + void ctiVMThrowTrampoline(); + }; + + void ctiSetReturnAddress(void** where, void* what); + void ctiRepatchCallByReturnAddress(void* where, void* what); + + class CTI { + static const int repatchGetByIdDefaultStructureID = -1; + // Magic number - initial offset cannot be representable as a signed 8bit value, or the X86Assembler + // will compress the displacement, and we may not be able to fit a repatched offset. + static const int repatchGetByIdDefaultOffset = 256; + +#if USE(FAST_CALL_CTI_ARGUMENT) + static const int ctiArgumentInitSize = 2; +#elif USE(CTI_ARGUMENT) + static const int ctiArgumentInitSize = 4; +#else + static const int ctiArgumentInitSize = 0; +#endif + // These architecture specific value are used to enable repatching - see comment on op_put_by_id. + static const int repatchOffsetPutByIdStructureID = 19; + static const int repatchOffsetPutByIdPropertyMapOffset = 34; + // These architecture specific value are used to enable repatching - see comment on op_get_by_id. + static const int repatchOffsetGetByIdStructureID = 19; + static const int repatchOffsetGetByIdBranchToSlowCase = 25; + static const int repatchOffsetGetByIdPropertyMapOffset = 34; +#if ENABLE(OPCODE_SAMPLING) + static const int repatchOffsetGetByIdSlowCaseCall = 27 + 4 + ctiArgumentInitSize; +#else + static const int repatchOffsetGetByIdSlowCaseCall = 17 + 4 + ctiArgumentInitSize; +#endif + static const int repatchOffsetOpCallCall = 6; + + public: + static void compile(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock) + { + CTI cti(machine, callFrame, codeBlock); + cti.privateCompile(); + } + +#if ENABLE(WREC) + static void* compileRegExp(Machine*, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase = false, bool multiline = false); +#endif + + static void compileGetByIdSelf(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress) + { + CTI cti(machine, callFrame, codeBlock); + cti.privateCompileGetByIdSelf(structureID, cachedOffset, returnAddress); + } + + static void compileGetByIdProto(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset, void* returnAddress) + { + CTI cti(machine, callFrame, codeBlock); + cti.privateCompileGetByIdProto(structureID, prototypeStructureID, cachedOffset, returnAddress); + } + + static void compileGetByIdChain(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset, void* returnAddress) + { + CTI cti(machine, callFrame, codeBlock); + cti.privateCompileGetByIdChain(structureID, chain, count, cachedOffset, returnAddress); + } + + static void compilePutByIdReplace(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress) + { + CTI cti(machine, callFrame, codeBlock); + cti.privateCompilePutByIdReplace(structureID, cachedOffset, returnAddress); + } + + static void compilePutByIdTransition(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock, StructureID* oldStructureID, StructureID* newStructureID, size_t cachedOffset, StructureIDChain* sIDC, void* returnAddress) + { + CTI cti(machine, callFrame, codeBlock); + cti.privateCompilePutByIdTransition(oldStructureID, newStructureID, cachedOffset, sIDC, returnAddress); + } + + static void* compileArrayLengthTrampoline(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock) + { + CTI cti(machine, callFrame, codeBlock); + return cti.privateCompileArrayLengthTrampoline(); + } + + static void* compileStringLengthTrampoline(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock) + { + CTI cti(machine, callFrame, codeBlock); + return cti.privateCompileStringLengthTrampoline(); + } + + static void patchGetByIdSelf(CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress); + static void patchPutByIdReplace(CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress); + + static void compilePatchGetArrayLength(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock, void* returnAddress) + { + CTI cti(machine, callFrame, codeBlock); + return cti.privateCompilePatchGetArrayLength(returnAddress); + } + + static void linkCall(JSFunction* callee, CodeBlock* calleeCodeBlock, void* ctiCode, CallLinkInfo* callLinkInfo, int callerArgCount); + static void unlinkCall(CallLinkInfo*); + + inline static JSValue* execute(void* code, RegisterFile* registerFile, CallFrame* callFrame, JSGlobalData* globalData, JSValue** exception) + { + return ctiTrampoline(code, registerFile, callFrame, exception, Profiler::enabledProfilerReference(), globalData); + } + + private: + CTI(Machine*, CallFrame*, CodeBlock*); + + static uintptr_t asInteger(JSValue*); + + bool isConstant(int src); + JSValue* getConstant(CallFrame*, int src); + + void privateCompileMainPass(); + void privateCompileLinkPass(); + void privateCompileSlowCases(); + void privateCompile(); + void privateCompileGetByIdSelf(StructureID*, size_t cachedOffset, void* returnAddress); + void privateCompileGetByIdProto(StructureID*, StructureID* prototypeStructureID, size_t cachedOffset, void* returnAddress); + void privateCompileGetByIdChain(StructureID*, StructureIDChain*, size_t count, size_t cachedOffset, void* returnAddress); + void privateCompilePutByIdReplace(StructureID*, size_t cachedOffset, void* returnAddress); + void privateCompilePutByIdTransition(StructureID*, StructureID*, size_t cachedOffset, StructureIDChain*, void* returnAddress); + + void* privateCompileArrayLengthTrampoline(); + void* privateCompileStringLengthTrampoline(); + void privateCompilePatchGetArrayLength(void* returnAddress); + + void compileOpCall(OpcodeID, Instruction* instruction, unsigned i, unsigned callLinkInfoIndex); + void compileOpCallInitializeCallFrame(unsigned callee, unsigned argCount); + void compileOpCallSetupArgs(Instruction* instruction, bool isConstruct, bool isEval); + enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq }; + void compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStrictEqType type); + void putDoubleResultToJSNumberCellOrJSImmediate(X86::XMMRegisterID xmmSource, X86::RegisterID jsNumberCell, unsigned dst, X86Assembler::JmpSrc* wroteJSNumberCell, X86::XMMRegisterID tempXmm, X86::RegisterID tempReg1, X86::RegisterID tempReg2); + void compileBinaryArithOp(OpcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi, unsigned i); + void compileBinaryArithOpSlowCase(Instruction*, OpcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi, unsigned i); + + void emitGetArg(int src, X86Assembler::RegisterID dst); + void emitGetPutArg(unsigned src, unsigned offset, X86Assembler::RegisterID scratch); + void emitPutArg(X86Assembler::RegisterID src, unsigned offset); + void emitPutArgConstant(unsigned value, unsigned offset); + void emitPutResult(unsigned dst, X86Assembler::RegisterID from = X86::eax); + + void emitInitRegister(unsigned dst); + + void emitPutCTIParam(void* value, unsigned name); + void emitPutCTIParam(X86Assembler::RegisterID from, unsigned name); + void emitGetCTIParam(unsigned name, X86Assembler::RegisterID to); + + void emitPutToCallFrameHeader(X86Assembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry); + void emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, X86Assembler::RegisterID to); + + JSValue* getConstantImmediateNumericArg(unsigned src); + unsigned getDeTaggedConstantImmediate(JSValue* imm); + + void emitJumpSlowCaseIfIsJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex); + void emitJumpSlowCaseIfNotJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex); + + void emitJumpSlowCaseIfNotImmNum(X86Assembler::RegisterID, unsigned opcodeIndex); + void emitJumpSlowCaseIfNotImmNums(X86Assembler::RegisterID, X86Assembler::RegisterID, unsigned opcodeIndex); + + void emitFastArithDeTagImmediate(X86Assembler::RegisterID); + X86Assembler::JmpSrc emitFastArithDeTagImmediateJumpIfZero(X86Assembler::RegisterID); + void emitFastArithReTagImmediate(X86Assembler::RegisterID); + void emitFastArithPotentiallyReTagImmediate(X86Assembler::RegisterID); + void emitFastArithImmToInt(X86Assembler::RegisterID); + void emitFastArithIntToImmOrSlowCase(X86Assembler::RegisterID, unsigned opcodeIndex); + void emitFastArithIntToImmNoCheck(X86Assembler::RegisterID); + X86Assembler::JmpSrc emitArithIntToImmWithJump(X86Assembler::RegisterID reg); + + void emitTagAsBoolImmediate(X86Assembler::RegisterID reg); + + void emitAllocateNumber(JSGlobalData*, unsigned); + + X86Assembler::JmpSrc emitNakedCall(unsigned opcodeIndex, X86::RegisterID); + X86Assembler::JmpSrc emitNakedCall(unsigned opcodeIndex, void(*function)()); + X86Assembler::JmpSrc emitNakedFastCall(unsigned opcodeIndex, void*); + X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_j); + X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_o); + X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_p); + X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_v); + X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_s); + X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_b); + X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_2); + + void emitGetVariableObjectRegister(X86Assembler::RegisterID variableObject, int index, X86Assembler::RegisterID dst); + void emitPutVariableObjectRegister(X86Assembler::RegisterID src, X86Assembler::RegisterID variableObject, int index); + + void emitSlowScriptCheck(Instruction*, unsigned opcodeIndex); +#ifndef NDEBUG + void printOpcodeOperandTypes(unsigned src1, unsigned src2); +#endif + + X86Assembler m_jit; + Machine* m_machine; + CallFrame* m_callFrame; + CodeBlock* m_codeBlock; + + Vector<CallRecord> m_calls; + Vector<X86Assembler::JmpDst> m_labels; + Vector<StructureStubCompilationInfo> m_propertyAccessCompilationInfo; + Vector<StructureStubCompilationInfo> m_callStructureStubCompilationInfo; + Vector<JmpTable> m_jmpTable; + + struct JSRInfo { + X86Assembler::JmpDst addrPosition; + X86Assembler::JmpDst target; + + JSRInfo(const X86Assembler::JmpDst& storeLocation, const X86Assembler::JmpDst& targetLocation) + : addrPosition(storeLocation) + , target(targetLocation) + { + } + }; + + Vector<JSRInfo> m_jsrSites; + Vector<SlowCaseEntry> m_slowCases; + Vector<SwitchRecord> m_switches; + + // This limit comes from the limit set in PCRE + static const int MaxPatternSize = (1 << 16); + + }; +} + +#endif // ENABLE(CTI) + +#endif // CTI_h |