blob: bec8ad9bf46c3d13d9008879b1ead46334804e01 [file] [log] [blame]
/*
* 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 "Opcode.h"
#include "RegisterFile.h"
#include <masm/X86Assembler.h>
#include <profiler/Profiler.h>
#include <wtf/AlwaysInline.h>
#include <wtf/Vector.h>
#if ENABLE(SAMPLING_TOOL)
#include "SamplingTool.h"
#endif
#if COMPILER(MSVC)
#define CTI_ARGS void** args
#define ARGS (args)
#else
#define CTI_ARGS void* args
#define ARGS (&args)
#endif
#define CTI_ARGS_2ndResult 0x08
#define CTI_ARGS_code 0x0C
#define CTI_ARGS_exec 0x0D
#define CTI_ARGS_registerFile 0x0E
#define CTI_ARGS_r 0x0F
#define CTI_ARGS_scopeChain 0x10
#define CTI_ARGS_codeBlock 0x11
#define CTI_ARGS_exception 0x12
#define CTI_ARGS_profilerReference 0x13
#define ARG_exec ((ExecState*)(ARGS)[CTI_ARGS_exec])
#define ARG_registerFile ((RegisterFile*)(ARGS)[CTI_ARGS_registerFile])
#define ARG_r ((Register*)(ARGS)[CTI_ARGS_r])
#define ARG_scopeChain ((ScopeChainNode*)(ARGS)[CTI_ARGS_scopeChain])
#define ARG_codeBlock ((CodeBlock*)(ARGS)[CTI_ARGS_codeBlock])
#define ARG_exception ((JSValue**)(ARGS)[CTI_ARGS_exception])
#define ARG_profilerReference ((Profiler**)(ARGS)[CTI_ARGS_profilerReference])
#define ARG_setScopeChain(newScopeChain) (*(volatile ScopeChainNode**)&(ARGS)[CTI_ARGS_scopeChain] = newScopeChain)
#define ARG_setCodeBlock(newCodeBlock) (*(volatile CodeBlock**)&(ARGS)[CTI_ARGS_codeBlock] = newCodeBlock)
#define ARG_setR(newR) (*(volatile Register**)&(ARGS)[CTI_ARGS_r] = newR)
#define ARG_set2ndResult(new2ndResult) (*(volatile JSValue**)&(ARGS)[CTI_ARGS_2ndResult] = new2ndResult)
#define ARG_src1 ((JSValue*)((ARGS)[1]))
#define ARG_src2 ((JSValue*)((ARGS)[2]))
#define ARG_src3 ((JSValue*)((ARGS)[3]))
#define ARG_src4 ((JSValue*)((ARGS)[4]))
#define ARG_src5 ((JSValue*)((ARGS)[5]))
#define ARG_id1 ((Identifier*)((ARGS)[1]))
#define ARG_id2 ((Identifier*)((ARGS)[2]))
#define ARG_id3 ((Identifier*)((ARGS)[3]))
#define ARG_id4 ((Identifier*)((ARGS)[4]))
#define ARG_int1 ((int)((ARGS)[1]))
#define ARG_int2 ((int)((ARGS)[2]))
#define ARG_int3 ((int)((ARGS)[3]))
#define ARG_int4 ((int)((ARGS)[4]))
#define ARG_int5 ((int)((ARGS)[5]))
#define ARG_func1 ((FuncDeclNode*)((ARGS)[1]))
#define ARG_funcexp1 ((FuncExprNode*)((ARGS)[1]))
#define ARG_registers1 ((Register*)((ARGS)[1]))
#define ARG_regexp1 ((RegExp*)((ARGS)[1]))
#define ARG_pni1 ((JSPropertyNameIterator*)((ARGS)[1]))
#define ARG_instr1 ((Instruction*)((ARGS)[1]))
#define ARG_instr2 ((Instruction*)((ARGS)[2]))
#define ARG_instr3 ((Instruction*)((ARGS)[3]))
#define ARG_instr4 ((Instruction*)((ARGS)[4]))
#define ARG_instr5 ((Instruction*)((ARGS)[5]))
#define ARG_instr6 ((Instruction*)((ARGS)[6]))
#define CTI_RETURN_ADDRESS ((ARGS)[-1])
namespace JSC {
class CodeBlock;
class ExecState;
class JSPropertyNameIterator;
class JSValue;
class Machine;
class Register;
class RegisterFile;
class ScopeChainNode;
class SimpleJumpTable;
class StringJumpTable;
class StructureIDChain;
struct Instruction;
typedef JSValue* (*CTIHelper_j)(CTI_ARGS);
typedef JSPropertyNameIterator* (*CTIHelper_p)(CTI_ARGS);
typedef void (*CTIHelper_v)(CTI_ARGS);
typedef void* (*CTIHelper_s)(CTI_ARGS);
typedef int (*CTIHelper_b)(CTI_ARGS);
struct CallRecord {
X86Assembler::JmpSrc from;
void* to;
unsigned opcodeIndex;
CallRecord()
{
}
CallRecord(X86Assembler::JmpSrc f, CTIHelper_j t, unsigned i)
: from(f)
, to((void*)t)
, opcodeIndex(i)
{
}
CallRecord(X86Assembler::JmpSrc f, CTIHelper_p t, unsigned i)
: from(f)
, to((void*)t)
, opcodeIndex(i)
{
}
CallRecord(X86Assembler::JmpSrc f, CTIHelper_v t, unsigned i)
: from(f)
, to((void*)t)
, opcodeIndex(i)
{
}
CallRecord(X86Assembler::JmpSrc f, CTIHelper_s t, unsigned i)
: from(f)
, to((void*)t)
, opcodeIndex(i)
{
}
CallRecord(X86Assembler::JmpSrc f, CTIHelper_b t, unsigned i)
: from(f)
, to((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;
};
extern "C" {
JSValue* ctiTrampoline(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception, Profiler**);
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;
// 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;
static const int repatchOffsetGetByIdSlowCaseCall = 17;
public:
static void compile(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
{
CTI cti(machine, exec, codeBlock);
cti.privateCompile();
}
#if ENABLE(WREC)
static void* compileRegExp(ExecState* exec, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase = false, bool multiline = false);
#endif
static void compileGetByIdSelf(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
{
CTI cti(machine, exec, codeBlock);
cti.privateCompileGetByIdSelf(structureID, cachedOffset, returnAddress);
}
static void compileGetByIdProto(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset, void* returnAddress)
{
CTI cti(machine, exec, codeBlock);
cti.privateCompileGetByIdProto(structureID, prototypeStructureID, cachedOffset, returnAddress);
}
static void compileGetByIdChain(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset, void* returnAddress)
{
CTI cti(machine, exec, codeBlock);
cti.privateCompileGetByIdChain(structureID, chain, count, cachedOffset, returnAddress);
}
static void compilePutByIdReplace(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
{
CTI cti(machine, exec, codeBlock);
cti.privateCompilePutByIdReplace(structureID, cachedOffset, returnAddress);
}
static void compilePutByIdTransition(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* oldStructureID, StructureID* newStructureID, size_t cachedOffset, StructureIDChain* sIDC, void* returnAddress)
{
CTI cti(machine, exec, codeBlock);
cti.privateCompilePutByIdTransition(oldStructureID, newStructureID, cachedOffset, sIDC, returnAddress);
}
static void* compileArrayLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
{
CTI cti(machine, exec, codeBlock);
return cti.privateCompileArrayLengthTrampoline();
}
static void* compileStringLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
{
CTI cti(machine, exec, 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, ExecState* exec, CodeBlock* codeBlock, void* returnAddress)
{
CTI cti(machine, exec, codeBlock);
return cti.privateCompilePatchGetArrayLength(returnAddress);
}
inline static JSValue* execute(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
{
JSValue* value = ctiTrampoline(code, exec, registerFile, r, scopeChain, codeBlock, exception, Profiler::enabledProfilerReference());
#if ENABLE(SAMPLING_TOOL)
currentOpcodeID = static_cast<OpcodeID>(-1);
#endif
return value;
}
private:
CTI(Machine*, ExecState*, CodeBlock*);
bool isConstant(int src);
JSValue* getConstant(ExecState*, 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);
enum CompileOpCallType { OpCallNormal, OpCallEval, OpConstruct };
void compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type = OpCallNormal);
enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
void compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStrictEqType type);
void emitGetArg(unsigned 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);
void emitFastArithReTagImmediate(X86Assembler::RegisterID);
void emitFastArithPotentiallyReTagImmediate(X86Assembler::RegisterID);
void emitFastArithImmToInt(X86Assembler::RegisterID);
void emitFastArithIntToImmOrSlowCase(X86Assembler::RegisterID, unsigned opcodeIndex);
void emitFastArithIntToImmNoCheck(X86Assembler::RegisterID);
void emitTagAsBoolImmediate(X86Assembler::RegisterID reg);
void emitDebugExceptionCheck();
X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, X86::RegisterID);
X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_j);
X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_p);
X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_b);
X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_v);
X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_s);
void emitGetVariableObjectRegister(X86Assembler::RegisterID variableObject, int index, X86Assembler::RegisterID dst);
void emitPutVariableObjectRegister(X86Assembler::RegisterID src, X86Assembler::RegisterID variableObject, int index);
void emitSlowScriptCheck(unsigned opcodeIndex);
#ifndef NDEBUG
void printOpcodeOperandTypes(unsigned src1, unsigned src2);
#endif
X86Assembler m_jit;
Machine* m_machine;
ExecState* m_exec;
CodeBlock* m_codeBlock;
Vector<CallRecord> m_calls;
Vector<X86Assembler::JmpDst> m_labels;
Vector<StructureStubCompilationInfo> m_structureStubCompilationInfo;
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