657a65dc240e1f2acb5cd2bfd57a6c0d434fad3c
[WebKit-https.git] / JavaScriptCore / VM / CTI.h
1 /*
2  * Copyright (C) 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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. 
24  */
25
26 #ifndef CTI_h
27 #define CTI_h
28
29 #if ENABLE(CTI)
30
31 #define WTF_USE_CTI_REPATCH_PIC 1
32
33 #include "Opcode.h"
34 #include "RegisterFile.h"
35 #include <masm/X86Assembler.h>
36 #include <profiler/Profiler.h>
37 #include <wtf/AlwaysInline.h>
38 #include <wtf/Vector.h>
39
40 #if ENABLE(SAMPLING_TOOL)
41 #include "SamplingTool.h"
42 #endif
43
44 #if COMPILER(MSVC)
45 #define CTI_ARGS void** args
46 #define ARGS (args)
47 #else
48 #define CTI_ARGS void* args
49 #define ARGS (&args)
50 #endif
51
52 #define CTI_ARGS_2ndResult 0x08
53
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])
69
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)
74
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]))
97
98 #define CTI_RETURN_ADDRESS ((ARGS)[-1])
99
100 namespace JSC {
101
102     class CodeBlock;
103     class ExecState;
104     class JSPropertyNameIterator;
105     class JSValue;
106     class Machine;
107     class Register;
108     class RegisterFile;
109     class ScopeChainNode;
110     class SimpleJumpTable;
111     class StringJumpTable;
112     class StructureIDChain;
113     struct Instruction;
114
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);
120
121     struct CallRecord {
122         X86Assembler::JmpSrc from;
123         void* to;
124         unsigned opcodeIndex;
125
126         CallRecord()
127         {
128         }
129
130         CallRecord(X86Assembler::JmpSrc f, CTIHelper_j t, unsigned i)
131             : from(f)
132             , to((void*)t)
133             , opcodeIndex(i)
134         {
135         }
136
137         CallRecord(X86Assembler::JmpSrc f, CTIHelper_p t, unsigned i)
138             : from(f)
139             , to((void*)t)
140             , opcodeIndex(i)
141         {
142         }
143         
144         CallRecord(X86Assembler::JmpSrc f, CTIHelper_v t, unsigned i)
145             : from(f)
146             , to((void*)t)
147             , opcodeIndex(i)
148         {
149         }
150         
151         CallRecord(X86Assembler::JmpSrc f, CTIHelper_s t, unsigned i)
152             : from(f)
153             , to((void*)t)
154             , opcodeIndex(i)
155         {
156         }
157         
158         CallRecord(X86Assembler::JmpSrc f, CTIHelper_b t, unsigned i)
159             : from(f)
160             , to((void*)t)
161             , opcodeIndex(i)
162         {
163         }
164     };
165
166     struct JmpTable {
167         X86Assembler::JmpSrc from;
168         unsigned to;
169         
170         JmpTable(X86Assembler::JmpSrc f, unsigned t)
171             : from(f)
172             , to(t)
173         {
174         }
175     };
176
177     struct SlowCaseEntry {
178         X86Assembler::JmpSrc from;
179         unsigned to;
180         unsigned hint;
181         
182         SlowCaseEntry(X86Assembler::JmpSrc f, unsigned t, unsigned h = 0)
183             : from(f)
184             , to(t)
185             , hint(h)
186         {
187         }
188     };
189
190     struct SwitchRecord {
191         enum Type {
192             Immediate,
193             Character,
194             String
195         };
196
197         Type m_type;
198
199         union {
200             SimpleJumpTable* m_simpleJumpTable;
201             StringJumpTable* m_stringJumpTable;
202         } m_jumpTable;
203
204         unsigned m_opcodeIndex;
205         unsigned m_defaultOffset;
206
207         SwitchRecord(SimpleJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset, Type type)
208             : m_type(type)
209             , m_opcodeIndex(opcodeIndex)
210             , m_defaultOffset(defaultOffset)
211         {
212             m_jumpTable.m_simpleJumpTable = jumpTable;
213         }
214
215         SwitchRecord(StringJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset)
216             : m_type(String)
217             , m_opcodeIndex(opcodeIndex)
218             , m_defaultOffset(defaultOffset)
219         {
220             m_jumpTable.m_stringJumpTable = jumpTable;
221         }
222     };
223
224     struct StructureStubCompilationInfo {
225         X86Assembler::JmpSrc callReturnLocation;
226         X86Assembler::JmpDst hotPathBegin;
227     };
228
229     extern "C" {
230         JSValue* ctiTrampoline(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception, Profiler**);
231         void ctiVMThrowTrampoline();
232     };
233
234     void ctiSetReturnAddress(void** where, void* what);
235     void ctiRepatchCallByReturnAddress(void* where, void* what);
236
237     class CTI {
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;
242
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;
251
252     public:
253         static void compile(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
254         {
255             CTI cti(machine, exec, codeBlock);
256             cti.privateCompile();
257         }
258
259 #if ENABLE(WREC)
260         static void* compileRegExp(ExecState* exec, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase = false, bool multiline = false);
261 #endif
262
263         static void compileGetByIdSelf(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
264         {
265             CTI cti(machine, exec, codeBlock);
266             cti.privateCompileGetByIdSelf(structureID, cachedOffset, returnAddress);
267         }
268
269         static void compileGetByIdProto(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset, void* returnAddress)
270         {
271             CTI cti(machine, exec, codeBlock);
272             cti.privateCompileGetByIdProto(structureID, prototypeStructureID, cachedOffset, returnAddress);
273         }
274
275         static void compileGetByIdChain(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset, void* returnAddress)
276         {
277             CTI cti(machine, exec, codeBlock);
278             cti.privateCompileGetByIdChain(structureID, chain, count, cachedOffset, returnAddress);
279         }
280
281         static void compilePutByIdReplace(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
282         {
283             CTI cti(machine, exec, codeBlock);
284             cti.privateCompilePutByIdReplace(structureID, cachedOffset, returnAddress);
285         }
286         
287         static void compilePutByIdTransition(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* oldStructureID, StructureID* newStructureID, size_t cachedOffset, StructureIDChain* sIDC, void* returnAddress)
288         {
289             CTI cti(machine, exec, codeBlock);
290             cti.privateCompilePutByIdTransition(oldStructureID, newStructureID, cachedOffset, sIDC, returnAddress);
291         }
292
293         static void* compileArrayLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
294         {
295             CTI cti(machine, exec, codeBlock);
296             return cti.privateCompileArrayLengthTrampoline();
297         }
298
299         static void* compileStringLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
300         {
301             CTI cti(machine, exec, codeBlock);
302             return cti.privateCompileStringLengthTrampoline();
303         }
304
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);
307
308         static void compilePatchGetArrayLength(Machine* machine, ExecState* exec, CodeBlock* codeBlock, void* returnAddress)
309         {
310             CTI cti(machine, exec, codeBlock);
311             return cti.privateCompilePatchGetArrayLength(returnAddress);
312         }
313
314         inline static JSValue* execute(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
315         {
316             JSValue* value = ctiTrampoline(code, exec, registerFile, r, scopeChain, codeBlock, exception, Profiler::enabledProfilerReference());
317 #if ENABLE(SAMPLING_TOOL)
318             currentOpcodeID = static_cast<OpcodeID>(-1);
319 #endif
320             return value;
321         }
322
323     private:
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);
334
335         void* privateCompileArrayLengthTrampoline();
336         void* privateCompileStringLengthTrampoline();
337         void privateCompilePatchGetArrayLength(void* returnAddress);
338
339         enum CompileOpCallType { OpCallNormal, OpCallEval, OpConstruct };
340         void compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type = OpCallNormal);
341
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);
347
348         void emitPutCTIParam(void* value, unsigned name);
349         void emitPutCTIParam(X86Assembler::RegisterID from, unsigned name);
350         void emitGetCTIParam(unsigned name, X86Assembler::RegisterID to);
351
352         void emitPutToCallFrameHeader(X86Assembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry);
353         void emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, X86Assembler::RegisterID to);
354
355         JSValue* getConstantImmediateNumericArg(unsigned src);
356         unsigned getDeTaggedConstantImmediate(JSValue* imm);
357
358         void emitJumpSlowCaseIfIsJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
359         void emitJumpSlowCaseIfNotJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
360
361         void emitJumpSlowCaseIfNotImm(X86Assembler::RegisterID, unsigned opcodeIndex);
362         void emitJumpSlowCaseIfNotImms(X86Assembler::RegisterID, X86Assembler::RegisterID, unsigned opcodeIndex);
363
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);
370
371         void emitDebugExceptionCheck();
372
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);
378         
379         void emitGetVariableObjectRegister(X86Assembler::RegisterID variableObject, int index, X86Assembler::RegisterID dst);
380         void emitPutVariableObjectRegister(X86Assembler::RegisterID src, X86Assembler::RegisterID variableObject, int index);
381         
382         void emitSlowScriptCheck(unsigned opcodeIndex);
383 #ifndef NDEBUG
384         void printOpcodeOperandTypes(unsigned src1, unsigned src2);
385 #endif
386
387         X86Assembler m_jit;
388         Machine* m_machine;
389         ExecState* m_exec;
390         CodeBlock* m_codeBlock;
391
392         Vector<CallRecord> m_calls;
393         Vector<X86Assembler::JmpDst> m_labels;
394         Vector<StructureStubCompilationInfo> m_structureStubCompilationInfo;
395         Vector<JmpTable> m_jmpTable;
396
397         struct JSRInfo {
398             X86Assembler::JmpDst addrPosition;
399             X86Assembler::JmpDst target;
400
401             JSRInfo(const X86Assembler::JmpDst& storeLocation, const X86Assembler::JmpDst& targetLocation)
402                 : addrPosition(storeLocation)
403                 , target(targetLocation)
404             {
405             }
406         };
407
408         Vector<JSRInfo> m_jsrSites;
409         Vector<SlowCaseEntry> m_slowCases;
410         Vector<SwitchRecord> m_switches;
411
412         // This limit comes from the limit set in PCRE
413         static const int MaxPatternSize = (1 << 16);
414
415     };
416 }
417
418 #endif // ENABLE(CTI)
419
420 #endif // CTI_h