Switch CTI runtime calls to the fastcall calling convention
[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 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_code 0x0C
49 #define CTI_ARGS_registerFile 0x0D
50 #define CTI_ARGS_r 0x0E
51 #define CTI_ARGS_exception 0x0F
52 #define CTI_ARGS_profilerReference 0x10
53 #define CTI_ARGS_globalData 0x11
54 #define ARG_registerFile ((RegisterFile*)(ARGS)[CTI_ARGS_registerFile])
55 #define ARG_r ((Register*)(ARGS)[CTI_ARGS_r])
56 #define ARG_exception ((JSValue**)(ARGS)[CTI_ARGS_exception])
57 #define ARG_profilerReference ((Profiler**)(ARGS)[CTI_ARGS_profilerReference])
58 #define ARG_globalData ((JSGlobalData*)(ARGS)[CTI_ARGS_globalData])
59
60 #define ARG_exec CallFrame::create(ARG_r)
61
62 #define ARG_setR(newR) (*(Register**)&(ARGS)[CTI_ARGS_r] = newR)
63
64 #define ARG_src1 ((JSValue*)((ARGS)[1]))
65 #define ARG_src2 ((JSValue*)((ARGS)[2]))
66 #define ARG_src3 ((JSValue*)((ARGS)[3]))
67 #define ARG_src4 ((JSValue*)((ARGS)[4]))
68 #define ARG_src5 ((JSValue*)((ARGS)[5]))
69 #define ARG_id1 ((Identifier*)((ARGS)[1]))
70 #define ARG_id2 ((Identifier*)((ARGS)[2]))
71 #define ARG_id3 ((Identifier*)((ARGS)[3]))
72 #define ARG_id4 ((Identifier*)((ARGS)[4]))
73 #define ARG_int1 ((int)((ARGS)[1]))
74 #define ARG_int2 ((int)((ARGS)[2]))
75 #define ARG_int3 ((int)((ARGS)[3]))
76 #define ARG_int4 ((int)((ARGS)[4]))
77 #define ARG_int5 ((int)((ARGS)[5]))
78 #define ARG_func1 ((FuncDeclNode*)((ARGS)[1]))
79 #define ARG_funcexp1 ((FuncExprNode*)((ARGS)[1]))
80 #define ARG_registers1 ((Register*)((ARGS)[1]))
81 #define ARG_regexp1 ((RegExp*)((ARGS)[1]))
82 #define ARG_pni1 ((JSPropertyNameIterator*)((ARGS)[1]))
83 #define ARG_instr1 ((Instruction*)((ARGS)[1]))
84 #define ARG_instr2 ((Instruction*)((ARGS)[2]))
85 #define ARG_instr3 ((Instruction*)((ARGS)[3]))
86 #define ARG_instr4 ((Instruction*)((ARGS)[4]))
87 #define ARG_instr5 ((Instruction*)((ARGS)[5]))
88 #define ARG_instr6 ((Instruction*)((ARGS)[6]))
89
90 #define CTI_RETURN_ADDRESS ((ARGS)[-1])
91
92 namespace JSC {
93
94     class CodeBlock;
95     class ExecState;
96     class JSPropertyNameIterator;
97     class JSValue;
98     class Machine;
99     class Register;
100     class RegisterFile;
101     class ScopeChainNode;
102     class SimpleJumpTable;
103     class StringJumpTable;
104     class StructureIDChain;
105     struct Instruction;
106     struct OperandTypes;
107
108     struct VoidPtrPair { void* first; void* second; };
109
110 #if COMPILER(MSVC)
111
112 #if USE(FAST_CALL_CTI_ARGUMENT)
113 #define SFX_CALL __fastcall
114 #else
115 #define SFX_CALL __cdecl
116 #endif
117
118 #else
119 #define SFX_CALL
120 #endif
121
122     typedef JSValue* (SFX_CALL *CTIHelper_j)(CTI_ARGS);
123     typedef JSPropertyNameIterator* (SFX_CALL *CTIHelper_p)(CTI_ARGS);
124     typedef void (SFX_CALL *CTIHelper_v)(CTI_ARGS);
125     typedef void* (SFX_CALL *CTIHelper_s)(CTI_ARGS);
126     typedef int (SFX_CALL *CTIHelper_b)(CTI_ARGS);
127     typedef VoidPtrPair (SFX_CALL *CTIHelper_2)(CTI_ARGS);
128
129     struct CallRecord {
130         X86Assembler::JmpSrc from;
131         void* to;
132         unsigned opcodeIndex;
133
134         CallRecord()
135         {
136         }
137
138         CallRecord(X86Assembler::JmpSrc f, CTIHelper_j t, unsigned i)
139             : from(f)
140             , to((void*)t)
141             , opcodeIndex(i)
142         {
143         }
144
145         CallRecord(X86Assembler::JmpSrc f, CTIHelper_p t, unsigned i)
146             : from(f)
147             , to((void*)t)
148             , opcodeIndex(i)
149         {
150         }
151         
152         CallRecord(X86Assembler::JmpSrc f, CTIHelper_v t, unsigned i)
153             : from(f)
154             , to((void*)t)
155             , opcodeIndex(i)
156         {
157         }
158         
159         CallRecord(X86Assembler::JmpSrc f, CTIHelper_s t, unsigned i)
160             : from(f)
161             , to((void*)t)
162             , opcodeIndex(i)
163         {
164         }
165         
166         CallRecord(X86Assembler::JmpSrc f, CTIHelper_b t, unsigned i)
167             : from(f)
168             , to((void*)t)
169             , opcodeIndex(i)
170         {
171         }
172
173         CallRecord(X86Assembler::JmpSrc f, CTIHelper_2 t, unsigned i)
174             : from(f)
175             , to((void*)t)
176             , opcodeIndex(i)
177         {
178         }
179
180         CallRecord(X86Assembler::JmpSrc f, unsigned i)
181             : from(f)
182             , to(0)
183             , opcodeIndex(i)
184         {
185         }
186     };
187
188     struct JmpTable {
189         X86Assembler::JmpSrc from;
190         unsigned to;
191         
192         JmpTable(X86Assembler::JmpSrc f, unsigned t)
193             : from(f)
194             , to(t)
195         {
196         }
197     };
198
199     struct SlowCaseEntry {
200         X86Assembler::JmpSrc from;
201         unsigned to;
202         unsigned hint;
203         
204         SlowCaseEntry(X86Assembler::JmpSrc f, unsigned t, unsigned h = 0)
205             : from(f)
206             , to(t)
207             , hint(h)
208         {
209         }
210     };
211
212     struct SwitchRecord {
213         enum Type {
214             Immediate,
215             Character,
216             String
217         };
218
219         Type m_type;
220
221         union {
222             SimpleJumpTable* m_simpleJumpTable;
223             StringJumpTable* m_stringJumpTable;
224         } m_jumpTable;
225
226         unsigned m_opcodeIndex;
227         unsigned m_defaultOffset;
228
229         SwitchRecord(SimpleJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset, Type type)
230             : m_type(type)
231             , m_opcodeIndex(opcodeIndex)
232             , m_defaultOffset(defaultOffset)
233         {
234             m_jumpTable.m_simpleJumpTable = jumpTable;
235         }
236
237         SwitchRecord(StringJumpTable* jumpTable, unsigned opcodeIndex, unsigned defaultOffset)
238             : m_type(String)
239             , m_opcodeIndex(opcodeIndex)
240             , m_defaultOffset(defaultOffset)
241         {
242             m_jumpTable.m_stringJumpTable = jumpTable;
243         }
244     };
245
246     struct StructureStubCompilationInfo {
247         X86Assembler::JmpSrc callReturnLocation;
248         X86Assembler::JmpDst hotPathBegin;
249     };
250
251     extern "C" {
252         JSValue* ctiTrampoline(void* code, RegisterFile*, Register* callFrame, JSValue** exception, Profiler**, JSGlobalData*);
253         void ctiVMThrowTrampoline();
254     };
255
256     void ctiSetReturnAddress(void** where, void* what);
257     void ctiRepatchCallByReturnAddress(void* where, void* what);
258
259     class CTI {
260         static const int repatchGetByIdDefaultStructureID = -1;
261         // Magic number - initial offset cannot be representable as a signed 8bit value, or the X86Assembler
262         // will compress the displacement, and we may not be able to fit a repatched offset.
263         static const int repatchGetByIdDefaultOffset = 256;
264
265 #if USE(FAST_CALL_CTI_ARGUMENT)
266         static const int ctiArgumentInitSize = 2;
267 #elif USE(CTI_ARGUMENT)
268         static const int ctiArgumentInitSize = 4;
269 #else
270         static const int ctiArgumentInitSize = 0;
271 #endif
272         // These architecture specific value are used to enable repatching - see comment on op_put_by_id.
273         static const int repatchOffsetPutByIdStructureID = 19;
274         static const int repatchOffsetPutByIdPropertyMapOffset = 34;
275         // These architecture specific value are used to enable repatching - see comment on op_get_by_id.
276         static const int repatchOffsetGetByIdStructureID = 19;
277         static const int repatchOffsetGetByIdBranchToSlowCase = 25;
278         static const int repatchOffsetGetByIdPropertyMapOffset = 34;
279 #if ENABLE(SAMPLING_TOOL)
280         static const int repatchOffsetGetByIdSlowCaseCall = 27 + ctiArgumentInitSize;
281 #else
282         static const int repatchOffsetGetByIdSlowCaseCall = 17 + ctiArgumentInitSize;
283 #endif
284
285     public:
286         static void compile(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
287         {
288             CTI cti(machine, exec, codeBlock);
289             cti.privateCompile();
290         }
291
292 #if ENABLE(WREC)
293         static void* compileRegExp(ExecState* exec, const UString& pattern, unsigned* numSubpatterns_ptr, const char** error_ptr, bool ignoreCase = false, bool multiline = false);
294 #endif
295
296         static void compileGetByIdSelf(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
297         {
298             CTI cti(machine, exec, codeBlock);
299             cti.privateCompileGetByIdSelf(structureID, cachedOffset, returnAddress);
300         }
301
302         static void compileGetByIdProto(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureID* prototypeStructureID, size_t cachedOffset, void* returnAddress)
303         {
304             CTI cti(machine, exec, codeBlock);
305             cti.privateCompileGetByIdProto(structureID, prototypeStructureID, cachedOffset, returnAddress);
306         }
307
308         static void compileGetByIdChain(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, StructureIDChain* chain, size_t count, size_t cachedOffset, void* returnAddress)
309         {
310             CTI cti(machine, exec, codeBlock);
311             cti.privateCompileGetByIdChain(structureID, chain, count, cachedOffset, returnAddress);
312         }
313
314         static void compilePutByIdReplace(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress)
315         {
316             CTI cti(machine, exec, codeBlock);
317             cti.privateCompilePutByIdReplace(structureID, cachedOffset, returnAddress);
318         }
319         
320         static void compilePutByIdTransition(Machine* machine, ExecState* exec, CodeBlock* codeBlock, StructureID* oldStructureID, StructureID* newStructureID, size_t cachedOffset, StructureIDChain* sIDC, void* returnAddress)
321         {
322             CTI cti(machine, exec, codeBlock);
323             cti.privateCompilePutByIdTransition(oldStructureID, newStructureID, cachedOffset, sIDC, returnAddress);
324         }
325
326         static void* compileArrayLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
327         {
328             CTI cti(machine, exec, codeBlock);
329             return cti.privateCompileArrayLengthTrampoline();
330         }
331
332         static void* compileStringLengthTrampoline(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
333         {
334             CTI cti(machine, exec, codeBlock);
335             return cti.privateCompileStringLengthTrampoline();
336         }
337
338         static void patchGetByIdSelf(CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress);
339         static void patchPutByIdReplace(CodeBlock* codeBlock, StructureID* structureID, size_t cachedOffset, void* returnAddress);
340
341         static void compilePatchGetArrayLength(Machine* machine, ExecState* exec, CodeBlock* codeBlock, void* returnAddress)
342         {
343             CTI cti(machine, exec, codeBlock);
344             return cti.privateCompilePatchGetArrayLength(returnAddress);
345         }
346
347         inline static JSValue* execute(void* code, RegisterFile* registerFile, Register* r, JSGlobalData* globalData, JSValue** exception)
348         {
349             return ctiTrampoline(code, registerFile, r, exception, Profiler::enabledProfilerReference(), globalData);
350         }
351
352     private:
353         CTI(Machine*, ExecState*, CodeBlock*);
354         
355         bool isConstant(int src);
356         JSValue* getConstant(ExecState*, int src);
357
358         void privateCompileMainPass();
359         void privateCompileLinkPass();
360         void privateCompileSlowCases();
361         void privateCompile();
362         void privateCompileGetByIdSelf(StructureID*, size_t cachedOffset, void* returnAddress);
363         void privateCompileGetByIdProto(StructureID*, StructureID* prototypeStructureID, size_t cachedOffset, void* returnAddress);
364         void privateCompileGetByIdChain(StructureID*, StructureIDChain*, size_t count, size_t cachedOffset, void* returnAddress);
365         void privateCompilePutByIdReplace(StructureID*, size_t cachedOffset, void* returnAddress);
366         void privateCompilePutByIdTransition(StructureID*, StructureID*, size_t cachedOffset, StructureIDChain*, void* returnAddress);
367
368         void* privateCompileArrayLengthTrampoline();
369         void* privateCompileStringLengthTrampoline();
370         void privateCompilePatchGetArrayLength(void* returnAddress);
371
372         enum CompileOpCallType { OpCallNormal, OpCallEval, OpConstruct };
373         void compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type = OpCallNormal);
374         void compileOpCallInitializeCallFrame(unsigned callee, unsigned argCount);
375         enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
376         void compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStrictEqType type);
377         void putDoubleResultToJSNumberCellOrJSImmediate(X86::XMMRegisterID xmmSource, X86::RegisterID jsNumberCell, unsigned dst, X86Assembler::JmpSrc* wroteJSNumberCell,  X86::XMMRegisterID tempXmm, X86::RegisterID tempReg1, X86::RegisterID tempReg2);
378         void compileBinaryArithOp(OpcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi, unsigned i);
379         void compileBinaryArithOpSlowCase(OpcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi, unsigned i);
380
381         void emitGetArg(int src, X86Assembler::RegisterID dst);
382         void emitGetPutArg(unsigned src, unsigned offset, X86Assembler::RegisterID scratch);
383         void emitPutArg(X86Assembler::RegisterID src, unsigned offset);
384         void emitPutArgConstant(unsigned value, unsigned offset);
385         void emitPutResult(unsigned dst, X86Assembler::RegisterID from = X86::eax);
386
387         void emitInitRegister(unsigned dst);
388
389         void emitPutCTIParam(void* value, unsigned name);
390         void emitPutCTIParam(X86Assembler::RegisterID from, unsigned name);
391         void emitGetCTIParam(unsigned name, X86Assembler::RegisterID to);
392
393         void emitPutToCallFrameHeader(X86Assembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry);
394         void emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, X86Assembler::RegisterID to);
395
396         JSValue* getConstantImmediateNumericArg(unsigned src);
397         unsigned getDeTaggedConstantImmediate(JSValue* imm);
398
399         void emitJumpSlowCaseIfIsJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
400         void emitJumpSlowCaseIfNotJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
401
402         void emitJumpSlowCaseIfNotImmNum(X86Assembler::RegisterID, unsigned opcodeIndex);
403         void emitJumpSlowCaseIfNotImmNums(X86Assembler::RegisterID, X86Assembler::RegisterID, unsigned opcodeIndex);
404
405         void emitFastArithDeTagImmediate(X86Assembler::RegisterID);
406         void emitFastArithReTagImmediate(X86Assembler::RegisterID);
407         void emitFastArithPotentiallyReTagImmediate(X86Assembler::RegisterID);
408         void emitFastArithImmToInt(X86Assembler::RegisterID);
409         void emitFastArithIntToImmOrSlowCase(X86Assembler::RegisterID, unsigned opcodeIndex);
410         void emitFastArithIntToImmNoCheck(X86Assembler::RegisterID);
411
412         void emitTagAsBoolImmediate(X86Assembler::RegisterID reg);
413
414         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, X86::RegisterID);
415         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_j);
416         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_p);
417         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_v);
418         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_s);
419         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_b);
420         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_2);
421
422         void emitGetVariableObjectRegister(X86Assembler::RegisterID variableObject, int index, X86Assembler::RegisterID dst);
423         void emitPutVariableObjectRegister(X86Assembler::RegisterID src, X86Assembler::RegisterID variableObject, int index);
424         
425         void emitSlowScriptCheck(unsigned opcodeIndex);
426 #ifndef NDEBUG
427         void printOpcodeOperandTypes(unsigned src1, unsigned src2);
428 #endif
429
430         X86Assembler m_jit;
431         Machine* m_machine;
432         ExecState* m_exec;
433         CodeBlock* m_codeBlock;
434
435         Vector<CallRecord> m_calls;
436         Vector<X86Assembler::JmpDst> m_labels;
437         Vector<StructureStubCompilationInfo> m_structureStubCompilationInfo;
438         Vector<JmpTable> m_jmpTable;
439
440         struct JSRInfo {
441             X86Assembler::JmpDst addrPosition;
442             X86Assembler::JmpDst target;
443
444             JSRInfo(const X86Assembler::JmpDst& storeLocation, const X86Assembler::JmpDst& targetLocation)
445                 : addrPosition(storeLocation)
446                 , target(targetLocation)
447             {
448             }
449         };
450
451         Vector<JSRInfo> m_jsrSites;
452         Vector<SlowCaseEntry> m_slowCases;
453         Vector<SwitchRecord> m_switches;
454
455         // This limit comes from the limit set in PCRE
456         static const int MaxPatternSize = (1 << 16);
457
458     };
459 }
460
461 #endif // ENABLE(CTI)
462
463 #endif // CTI_h