2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #define WTF_USE_CTI_REPATCH_PIC 1
34 #include "RegisterFile.h"
35 #include <masm/X86Assembler.h>
36 #include <profiler/Profiler.h>
37 #include <wtf/AlwaysInline.h>
38 #include <wtf/Vector.h>
40 #if ENABLE(SAMPLING_TOOL)
41 #include "SamplingTool.h"
45 #define CTI_ARGS void** args
48 #define CTI_ARGS void* args
52 #define CTI_ARGS_2ndResult 0x08
54 #define CTI_ARGS_code 0x0C
55 #define CTI_ARGS_exec 0x0D
56 #define CTI_ARGS_registerFile 0x0E
57 #define CTI_ARGS_r 0x0F
58 #define CTI_ARGS_scopeChain 0x10
59 #define CTI_ARGS_codeBlock 0x11
60 #define CTI_ARGS_exception 0x12
61 #define CTI_ARGS_profilerReference 0x13
62 #define ARG_exec ((ExecState*)(ARGS)[CTI_ARGS_exec])
63 #define ARG_registerFile ((RegisterFile*)(ARGS)[CTI_ARGS_registerFile])
64 #define ARG_r ((Register*)(ARGS)[CTI_ARGS_r])
65 #define ARG_scopeChain ((ScopeChainNode*)(ARGS)[CTI_ARGS_scopeChain])
66 #define ARG_codeBlock ((CodeBlock*)(ARGS)[CTI_ARGS_codeBlock])
67 #define ARG_exception ((JSValue**)(ARGS)[CTI_ARGS_exception])
68 #define ARG_profilerReference ((Profiler**)(ARGS)[CTI_ARGS_profilerReference])
70 #define ARG_setScopeChain(newScopeChain) (*(volatile ScopeChainNode**)&(ARGS)[CTI_ARGS_scopeChain] = newScopeChain)
71 #define ARG_setCodeBlock(newCodeBlock) (*(volatile CodeBlock**)&(ARGS)[CTI_ARGS_codeBlock] = newCodeBlock)
72 #define ARG_setR(newR) (*(volatile Register**)&(ARGS)[CTI_ARGS_r] = newR)
73 #define ARG_set2ndResult(new2ndResult) (*(volatile JSValue**)&(ARGS)[CTI_ARGS_2ndResult] = new2ndResult)
75 #define ARG_src1 ((JSValue*)((ARGS)[1]))
76 #define ARG_src2 ((JSValue*)((ARGS)[2]))
77 #define ARG_src3 ((JSValue*)((ARGS)[3]))
78 #define ARG_src4 ((JSValue*)((ARGS)[4]))
79 #define ARG_id1 ((Identifier*)((ARGS)[1]))
80 #define ARG_id2 ((Identifier*)((ARGS)[2]))
81 #define ARG_id3 ((Identifier*)((ARGS)[3]))
82 #define ARG_id4 ((Identifier*)((ARGS)[4]))
83 #define ARG_int1 ((int)((ARGS)[1]))
84 #define ARG_int2 ((int)((ARGS)[2]))
85 #define ARG_int3 ((int)((ARGS)[3]))
86 #define ARG_int4 ((int)((ARGS)[4]))
87 #define ARG_func1 ((FuncDeclNode*)((ARGS)[1]))
88 #define ARG_funcexp1 ((FuncExprNode*)((ARGS)[1]))
89 #define ARG_registers1 ((Register*)((ARGS)[1]))
90 #define ARG_regexp1 ((RegExp*)((ARGS)[1]))
91 #define ARG_pni1 ((JSPropertyNameIterator*)((ARGS)[1]))
92 #define ARG_instr1 ((Instruction*)((ARGS)[1]))
93 #define ARG_instr2 ((Instruction*)((ARGS)[2]))
94 #define ARG_instr3 ((Instruction*)((ARGS)[3]))
95 #define ARG_instr4 ((Instruction*)((ARGS)[4]))
96 #define ARG_instr5 ((Instruction*)((ARGS)[5]))
98 #define CTI_RETURN_ADDRESS ((ARGS)[-1])
104 class JSPropertyNameIterator;
109 class ScopeChainNode;
110 class SimpleJumpTable;
111 class StringJumpTable;
112 class StructureIDChain;
115 typedef JSValue* (*CTIHelper_j)(CTI_ARGS);
116 typedef JSPropertyNameIterator* (*CTIHelper_p)(CTI_ARGS);
117 typedef void (*CTIHelper_v)(CTI_ARGS);
118 typedef void* (*CTIHelper_s)(CTI_ARGS);
119 typedef int (*CTIHelper_b)(CTI_ARGS);
122 X86Assembler::JmpSrc from;
124 unsigned opcodeIndex;
130 CallRecord(X86Assembler::JmpSrc f, CTIHelper_j t, unsigned i)
137 CallRecord(X86Assembler::JmpSrc f, CTIHelper_p t, unsigned i)
144 CallRecord(X86Assembler::JmpSrc f, CTIHelper_v t, unsigned i)
151 CallRecord(X86Assembler::JmpSrc f, CTIHelper_s t, unsigned i)
158 CallRecord(X86Assembler::JmpSrc f, CTIHelper_b t, unsigned i)
167 X86Assembler::JmpSrc from;
170 JmpTable(X86Assembler::JmpSrc f, unsigned t)
177 struct SlowCaseEntry {
178 X86Assembler::JmpSrc from;
182 SlowCaseEntry(X86Assembler::JmpSrc f, unsigned t, unsigned h = 0)
190 struct SwitchRecord {
200 SimpleJumpTable* m_simpleJumpTable;
201 StringJumpTable* m_stringJumpTable;
204 unsigned m_opcodeIndex;
205 unsigned m_defaultOffset;
207 SwitchRecord(SimpleJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset, Type type)
209 , m_opcodeIndex(opcodeIndex)
210 , m_defaultOffset(defaultOffset)
212 m_jumpTable.m_simpleJumpTable = jumpTable;
215 SwitchRecord(StringJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset)
217 , m_opcodeIndex(opcodeIndex)
218 , m_defaultOffset(defaultOffset)
220 m_jumpTable.m_stringJumpTable = jumpTable;
224 struct StructureStubCompilationInfo {
225 X86Assembler::JmpSrc callReturnLocation;
226 X86Assembler::JmpDst hotPathBegin;
230 JSValue* ctiTrampoline(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception, Profiler**);
231 void ctiVMThrowTrampoline();
234 void ctiSetReturnAddress(void** where, void* what);
235 void ctiRepatchCallByReturnAddress(void* where, void* what);
238 static const int repatchGetByIdDefaultStructureID = -1;
239 // Magic number - initial offset cannot be representable as a signed 8bit value, or the X86Assembler
240 // will compress the displacement, and we may not be able to fit a repatched offset.
241 static const int repatchGetByIdDefaultOffset = 256;
243 // These architecture specific value are used to enable repatching - see comment on op_put_by_id.
244 static const int repatchOffsetPutByIdStructureID = 19;
245 static const int repatchOffsetPutByIdPropertyMapOffset = 34;
246 // These architecture specific value are used to enable repatching - see comment on op_get_by_id.
247 static const int repatchOffsetGetByIdStructureID = 19;
248 static const int repatchOffsetGetByIdBranchToSlowCase = 25;
249 static const int repatchOffsetGetByIdPropertyMapOffset = 34;
250 static const int repatchOffsetGetByIdSlowCaseCall = 17;
253 static void compile(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
255 CTI cti(machine, exec, codeBlock);
256 cti.privateCompile();
260 static void* compileRegExp(ExecState* exec, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase = false, bool multiline = false);
263 static void compileGetByIdSelf(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
265 CTI cti(machine, exec, codeBlock);
266 cti.privateCompileGetByIdSelf(structureID, cachedOffset, returnAddress);
269 static void compileGetByIdProto(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset, void* returnAddress)
271 CTI cti(machine, exec, codeBlock);
272 cti.privateCompileGetByIdProto(structureID, prototypeStructureID, cachedOffset, returnAddress);
275 static void compileGetByIdChain(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset, void* returnAddress)
277 CTI cti(machine, exec, codeBlock);
278 cti.privateCompileGetByIdChain(structureID, chain, count, cachedOffset, returnAddress);
281 static void compilePutByIdReplace(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
283 CTI cti(machine, exec, codeBlock);
284 cti.privateCompilePutByIdReplace(structureID, cachedOffset, returnAddress);
287 static void compilePutByIdTransition(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* oldStructureID, StructureID* newStructureID, size_t cachedOffset, StructureIDChain* sIDC, void* returnAddress)
289 CTI cti(machine, exec, codeBlock);
290 cti.privateCompilePutByIdTransition(oldStructureID, newStructureID, cachedOffset, sIDC, returnAddress);
293 static void* compileArrayLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
295 CTI cti(machine, exec, codeBlock);
296 return cti.privateCompileArrayLengthTrampoline();
299 static void* compileStringLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
301 CTI cti(machine, exec, codeBlock);
302 return cti.privateCompileStringLengthTrampoline();
305 static void patchGetByIdSelf(CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress);
306 static void patchPutByIdReplace(CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress);
308 static void compilePatchGetArrayLength(Machine* machine, ExecState* exec, CodeBlock* codeBlock, void* returnAddress)
310 CTI cti(machine, exec, codeBlock);
311 return cti.privateCompilePatchGetArrayLength(returnAddress);
314 inline static JSValue* execute(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
316 JSValue* value = ctiTrampoline(code, exec, registerFile, r, scopeChain, codeBlock, exception, Profiler::enabledProfilerReference());
317 #if ENABLE(SAMPLING_TOOL)
318 currentOpcodeID = static_cast<OpcodeID>(-1);
324 CTI(Machine*, ExecState*, CodeBlock*);
325 void privateCompileMainPass();
326 void privateCompileLinkPass();
327 void privateCompileSlowCases();
328 void privateCompile();
329 void privateCompileGetByIdSelf(StructureID*, size_t cachedOffset, void* returnAddress);
330 void privateCompileGetByIdProto(StructureID*, StructureID* prototypeStructureID, size_t cachedOffset, void* returnAddress);
331 void privateCompileGetByIdChain(StructureID*, StructureIDChain*, size_t count, size_t cachedOffset, void* returnAddress);
332 void privateCompilePutByIdReplace(StructureID*, size_t cachedOffset, void* returnAddress);
333 void privateCompilePutByIdTransition(StructureID*, StructureID*, size_t cachedOffset, StructureIDChain*, void* returnAddress);
335 void* privateCompileArrayLengthTrampoline();
336 void* privateCompileStringLengthTrampoline();
337 void privateCompilePatchGetArrayLength(void* returnAddress);
339 enum CompileOpCallType { OpCallNormal, OpCallEval, OpConstruct };
340 void compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type = OpCallNormal);
342 void emitGetArg(unsigned src, X86Assembler::RegisterID dst);
343 void emitGetPutArg(unsigned src, unsigned offset, X86Assembler::RegisterID scratch);
344 void emitPutArg(X86Assembler::RegisterID src, unsigned offset);
345 void emitPutArgConstant(unsigned value, unsigned offset);
346 void emitPutResult(unsigned dst, X86Assembler::RegisterID from = X86::eax);
348 void emitPutCTIParam(void* value, unsigned name);
349 void emitPutCTIParam(X86Assembler::RegisterID from, unsigned name);
350 void emitGetCTIParam(unsigned name, X86Assembler::RegisterID to);
352 void emitPutToCallFrameHeader(X86Assembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry);
353 void emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, X86Assembler::RegisterID to);
355 JSValue* getConstantImmediateNumericArg(unsigned src);
356 unsigned getDeTaggedConstantImmediate(JSValue* imm);
358 void emitJumpSlowCaseIfIsJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
359 void emitJumpSlowCaseIfNotJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
361 void emitJumpSlowCaseIfNotImm(X86Assembler::RegisterID, unsigned opcodeIndex);
362 void emitJumpSlowCaseIfNotImms(X86Assembler::RegisterID, X86Assembler::RegisterID, unsigned opcodeIndex);
364 void emitFastArithDeTagImmediate(X86Assembler::RegisterID);
365 void emitFastArithReTagImmediate(X86Assembler::RegisterID);
366 void emitFastArithPotentiallyReTagImmediate(X86Assembler::RegisterID);
367 void emitFastArithImmToInt(X86Assembler::RegisterID);
368 void emitFastArithIntToImmOrSlowCase(X86Assembler::RegisterID, unsigned opcodeIndex);
369 void emitFastArithIntToImmNoCheck(X86Assembler::RegisterID);
371 void emitDebugExceptionCheck();
373 X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_j);
374 X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_p);
375 X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_b);
376 X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_v);
377 X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_s);
379 void emitGetVariableObjectRegister(X86Assembler::RegisterID variableObject, int index, X86Assembler::RegisterID dst);
380 void emitPutVariableObjectRegister(X86Assembler::RegisterID src, X86Assembler::RegisterID variableObject, int index);
382 void emitSlowScriptCheck(unsigned opcodeIndex);
384 void printOpcodeOperandTypes(unsigned src1, unsigned src2);
390 CodeBlock* m_codeBlock;
392 Vector<CallRecord> m_calls;
393 Vector<X86Assembler::JmpDst> m_labels;
394 Vector<StructureStubCompilationInfo> m_structureStubCompilationInfo;
395 Vector<JmpTable> m_jmpTable;
398 X86Assembler::JmpDst addrPosition;
399 X86Assembler::JmpDst target;
401 JSRInfo(const X86Assembler::JmpDst& storeLocation, const X86Assembler::JmpDst& targetLocation)
402 : addrPosition(storeLocation)
403 , target(targetLocation)
408 Vector<JSRInfo> m_jsrSites;
409 Vector<SlowCaseEntry> m_slowCases;
410 Vector<SwitchRecord> m_switches;
412 // This limit comes from the limit set in PCRE
413 static const int MaxPatternSize = (1 << 16);
418 #endif // ENABLE(CTI)