Bug 20821: Cache property transitions to speed up object initialization
[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 #include "Opcode.h"
32 #include "Opcode.h"
33 #include "RegisterFile.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 COMPILER(MSVC)
41 #define CTI_ARGS void** args
42 #define ARGS (args)
43 #else
44 #define CTI_ARGS void* args
45 #define ARGS (&args)
46 #endif
47
48 #define CTI_ARGS_2ndResult 0x08
49
50 #define CTI_ARGS_code 0x0C
51 #define CTI_ARGS_exec 0x0D
52 #define CTI_ARGS_registerFile 0x0E
53 #define CTI_ARGS_r 0x0F
54 #define CTI_ARGS_scopeChain 0x10
55 #define CTI_ARGS_codeBlock 0x11
56 #define CTI_ARGS_exception 0x12
57 #define CTI_ARGS_profilerReference 0x13
58 #define ARG_exec ((ExecState*)(ARGS)[CTI_ARGS_exec])
59 #define ARG_registerFile ((RegisterFile*)(ARGS)[CTI_ARGS_registerFile])
60 #define ARG_r ((Register*)(ARGS)[CTI_ARGS_r])
61 #define ARG_scopeChain ((ScopeChainNode*)(ARGS)[CTI_ARGS_scopeChain])
62 #define ARG_codeBlock ((CodeBlock*)(ARGS)[CTI_ARGS_codeBlock])
63 #define ARG_exception ((JSValue**)(ARGS)[CTI_ARGS_exception])
64 #define ARG_profilerReference ((Profiler**)(ARGS)[CTI_ARGS_profilerReference])
65
66 #define ARG_setScopeChain(newScopeChain) (*(volatile ScopeChainNode**)&(ARGS)[CTI_ARGS_scopeChain] = newScopeChain)
67 #define ARG_setCodeBlock(newCodeBlock) (*(volatile CodeBlock**)&(ARGS)[CTI_ARGS_codeBlock] = newCodeBlock)
68 #define ARG_setR(newR) (*(volatile Register**)&(ARGS)[CTI_ARGS_r] = newR)
69 #define ARG_set2ndResult(new2ndResult) (*(volatile JSValue**)&(ARGS)[CTI_ARGS_2ndResult] = new2ndResult)
70
71 #define ARG_src1 ((JSValue*)((ARGS)[1]))
72 #define ARG_src2 ((JSValue*)((ARGS)[2]))
73 #define ARG_src3 ((JSValue*)((ARGS)[3]))
74 #define ARG_src4 ((JSValue*)((ARGS)[4]))
75 #define ARG_id1 ((Identifier*)((ARGS)[1]))
76 #define ARG_id2 ((Identifier*)((ARGS)[2]))
77 #define ARG_id3 ((Identifier*)((ARGS)[3]))
78 #define ARG_id4 ((Identifier*)((ARGS)[4]))
79 #define ARG_int1 ((int)((ARGS)[1]))
80 #define ARG_int2 ((int)((ARGS)[2]))
81 #define ARG_int3 ((int)((ARGS)[3]))
82 #define ARG_int4 ((int)((ARGS)[4]))
83 #define ARG_func1 ((FuncDeclNode*)((ARGS)[1]))
84 #define ARG_funcexp1 ((FuncExprNode*)((ARGS)[1]))
85 #define ARG_registers1 ((Register*)((ARGS)[1]))
86 #define ARG_regexp1 ((RegExp*)((ARGS)[1]))
87 #define ARG_pni1 ((JSPropertyNameIterator*)((ARGS)[1]))
88 #define ARG_instr4 ((Instruction*)((ARGS)[4]))
89 #define ARG_instr5 ((Instruction*)((ARGS)[5]))
90
91 #define CTI_RETURN_ADDRESS ((ARGS)[-1])
92
93 namespace JSC {
94
95     class CodeBlock;
96     class ExecState;
97     class JSPropertyNameIterator;
98     class JSValue;
99     class Machine;
100     class Register;
101     class RegisterFile;
102     class ScopeChainNode;
103     class SimpleJumpTable;
104     class StringJumpTable;
105     class StructureIDChain;
106     struct Instruction;
107
108     typedef JSValue* (*CTIHelper_j)(CTI_ARGS);
109     typedef JSPropertyNameIterator* (*CTIHelper_p)(CTI_ARGS);
110     typedef void (*CTIHelper_v)(CTI_ARGS);
111     typedef void* (*CTIHelper_s)(CTI_ARGS);
112     typedef int (*CTIHelper_b)(CTI_ARGS);
113
114     extern OpcodeID what;
115
116     struct CallRecord {
117         X86Assembler::JmpSrc from;
118         void* to;
119         unsigned opcodeIndex;
120
121         CallRecord()
122         {
123         }
124
125         CallRecord(X86Assembler::JmpSrc f, CTIHelper_j t, unsigned i)
126             : from(f)
127             , to((void*)t)
128             , opcodeIndex(i)
129         {
130         }
131
132         CallRecord(X86Assembler::JmpSrc f, CTIHelper_p t, unsigned i)
133             : from(f)
134             , to((void*)t)
135             , opcodeIndex(i)
136         {
137         }
138         
139         CallRecord(X86Assembler::JmpSrc f, CTIHelper_v t, unsigned i)
140             : from(f)
141             , to((void*)t)
142             , opcodeIndex(i)
143         {
144         }
145         
146         CallRecord(X86Assembler::JmpSrc f, CTIHelper_s t, unsigned i)
147             : from(f)
148             , to((void*)t)
149             , opcodeIndex(i)
150         {
151         }
152         
153         CallRecord(X86Assembler::JmpSrc f, CTIHelper_b t, unsigned i)
154             : from(f)
155             , to((void*)t)
156             , opcodeIndex(i)
157         {
158         }
159     };
160
161     struct JmpTable {
162         X86Assembler::JmpSrc from;
163         unsigned to;
164         
165         JmpTable(X86Assembler::JmpSrc f, unsigned t)
166             : from(f)
167             , to(t)
168         {
169         }
170     };
171
172     struct SlowCaseEntry {
173         X86Assembler::JmpSrc from;
174         unsigned to;
175         unsigned hint;
176         
177         SlowCaseEntry(X86Assembler::JmpSrc f, unsigned t, unsigned h = 0)
178             : from(f)
179             , to(t)
180             , hint(h)
181         {
182         }
183     };
184
185     struct SwitchRecord {
186         enum Type {
187             Immediate,
188             Character,
189             String
190         };
191
192         Type m_type;
193
194         union {
195             SimpleJumpTable* m_simpleJumpTable;
196             StringJumpTable* m_stringJumpTable;
197         } m_jumpTable;
198
199         unsigned m_opcodeIndex;
200         unsigned m_defaultOffset;
201
202         SwitchRecord(SimpleJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset, Type type)
203             : m_type(type)
204             , m_opcodeIndex(opcodeIndex)
205             , m_defaultOffset(defaultOffset)
206         {
207             m_jumpTable.m_simpleJumpTable = jumpTable;
208         }
209
210         SwitchRecord(StringJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset)
211             : m_type(String)
212             , m_opcodeIndex(opcodeIndex)
213             , m_defaultOffset(defaultOffset)
214         {
215             m_jumpTable.m_stringJumpTable = jumpTable;
216         }
217     };
218
219     extern "C" {
220         JSValue* ctiTrampoline(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception, Profiler**);
221         void ctiVMThrowTrampoline();
222     };
223
224     void ctiSetReturnAddress(void** where, void* what);
225     void ctiRepatchCallByReturnAddress(void* where, void* what);
226
227     class CTI {
228     public:
229         static void compile(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
230         {
231             CTI cti(machine, exec, codeBlock);
232             cti.privateCompile();
233         }
234
235 #if ENABLE(WREC)
236         static void* compileRegExp(ExecState* exec, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase = false, bool multiline = false);
237 #endif
238
239         static void* compileGetByIdSelf(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset)
240         {
241             CTI cti(machine, exec, codeBlock);
242             return cti.privateCompileGetByIdSelf(structureID, cachedOffset);
243         }
244
245         static void* compileGetByIdProto(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset)
246         {
247             CTI cti(machine, exec, codeBlock);
248             return cti.privateCompileGetByIdProto(exec, structureID, prototypeStructureID, cachedOffset);
249         }
250
251         static void* compileGetByIdChain(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset)
252         {
253             CTI cti(machine, exec, codeBlock);
254             return cti.privateCompileGetByIdChain(exec, structureID, chain, count, cachedOffset);
255         }
256
257         static void* compilePutByIdReplace(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset)
258         {
259             CTI cti(machine, exec, codeBlock);
260             return cti.privateCompilePutByIdReplace(structureID, cachedOffset);
261         }
262         
263         static void* compilePutByIdTransition(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* oldStructureID, StructureID* newStructureID, size_t cachedOffset, StructureIDChain* sIDC)
264         {
265             CTI cti(machine, exec, codeBlock);
266             return cti.privateCompilePutByIdTransition(oldStructureID, newStructureID, cachedOffset, sIDC);
267         }
268
269         static void* compileArrayLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
270         {
271             CTI cti(machine, exec, codeBlock);
272             return cti.privateArrayLengthTrampoline();
273         }
274
275         static void* compileStringLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
276         {
277             CTI cti(machine, exec, codeBlock);
278             return cti.privateStringLengthTrampoline();
279         }
280
281         inline static JSValue* execute(void* code, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
282         {
283             JSValue* value = ctiTrampoline(code, exec, registerFile, r, scopeChain, codeBlock, exception, Profiler::enabledProfilerReference());
284 #if ENABLE(SAMPLING_TOOL)
285             what = static_cast<OpcodeID>(-1);
286 #endif
287             return value;
288         }
289
290     private:
291         CTI(Machine*, ExecState*, CodeBlock*);
292         void privateCompileMainPass();
293         void privateCompileLinkPass();
294         void privateCompileSlowCases();
295         void privateCompile();
296         void* privateCompileGetByIdSelf(StructureID*, size_t cachedOffset);
297         void* privateCompileGetByIdProto(ExecState*, StructureID*, StructureID* prototypeStructureID, size_t cachedOffset);
298         void* privateCompileGetByIdChain(ExecState*, StructureID*, StructureIDChain*, size_t count, size_t cachedOffset);
299         void* privateCompilePutByIdReplace(StructureID*, size_t cachedOffset);
300         void* privateCompilePutByIdTransition(StructureID*, StructureID*, size_t cachedOffset, StructureIDChain*);
301         void* privateArrayLengthTrampoline();
302         void* privateStringLengthTrampoline();
303
304         enum CompileOpCallType { OpCallNormal, OpCallEval, OpConstruct };
305         void compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type = OpCallNormal);
306
307         void emitGetArg(unsigned src, X86Assembler::RegisterID dst);
308         void emitGetPutArg(unsigned src, unsigned offset, X86Assembler::RegisterID scratch);
309         void emitPutArg(X86Assembler::RegisterID src, unsigned offset);
310         void emitPutArgConstant(unsigned value, unsigned offset);
311         void emitPutResult(unsigned dst, X86Assembler::RegisterID from = X86::eax);
312
313         void emitPutCTIParam(X86Assembler::RegisterID from, unsigned name);
314         void emitGetCTIParam(unsigned name, X86Assembler::RegisterID to);
315
316         void emitPutToCallFrameHeader(X86Assembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry);
317         void emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, X86Assembler::RegisterID to);
318
319         JSValue* getConstantImmediateNumericArg(unsigned src);
320         unsigned getDeTaggedConstantImmediate(JSValue* imm);
321
322         void emitJumpSlowCaseIfNotImm(X86Assembler::RegisterID, unsigned opcodeIndex);
323         void emitJumpSlowCaseIfNotImms(X86Assembler::RegisterID, X86Assembler::RegisterID, unsigned opcodeIndex);
324
325         void emitFastArithDeTagImmediate(X86Assembler::RegisterID);
326         void emitFastArithReTagImmediate(X86Assembler::RegisterID);
327         void emitFastArithPotentiallyReTagImmediate(X86Assembler::RegisterID);
328         void emitFastArithImmToInt(X86Assembler::RegisterID);
329         void emitFastArithIntToImmOrSlowCase(X86Assembler::RegisterID, unsigned opcodeIndex);
330         void emitFastArithIntToImmNoCheck(X86Assembler::RegisterID);
331
332         void emitDebugExceptionCheck();
333
334         void emitCall(unsigned opcodeIndex, CTIHelper_j);
335         void emitCall(unsigned opcodeIndex, CTIHelper_p);
336         void emitCall(unsigned opcodeIndex, CTIHelper_b);
337         void emitCall(unsigned opcodeIndex, CTIHelper_v);
338         void emitCall(unsigned opcodeIndex, CTIHelper_s);
339         
340         void emitGetVariableObjectRegister(X86Assembler::RegisterID variableObject, int index, X86Assembler::RegisterID dst);
341         void emitPutVariableObjectRegister(X86Assembler::RegisterID src, X86Assembler::RegisterID variableObject, int index);
342         
343         void emitSlowScriptCheck(unsigned opcodeIndex);
344 #ifndef NDEBUG
345         void printOpcodeOperandTypes(unsigned src1, unsigned src2);
346 #endif
347
348         X86Assembler m_jit;
349         Machine* m_machine;
350         ExecState* m_exec;
351         CodeBlock* m_codeBlock;
352
353         Vector<CallRecord> m_calls;
354         Vector<X86Assembler::JmpDst> m_labels;
355         Vector<JmpTable> m_jmpTable;
356
357         struct JSRInfo {
358             X86Assembler::JmpDst addrPosition;
359             X86Assembler::JmpDst target;
360
361             JSRInfo(const X86Assembler::JmpDst& storeLocation, const X86Assembler::JmpDst& targetLocation)
362                 : addrPosition(storeLocation)
363                 , target(targetLocation)
364             {
365             }
366         };
367
368         Vector<JSRInfo> m_jsrSites;
369         Vector<SlowCaseEntry> m_slowCases;
370         Vector<SwitchRecord> m_switches;
371
372         // This limit comes from the limit set in PCRE
373         static const int MaxPatternSize = (1 << 16);
374
375     };
376 }
377
378 #endif // ENABLE(CTI)
379
380 #endif // CTI_h