Switch CTI runtime calls to the fastcall calling convention
[WebKit-https.git] / JavaScriptCore / VM / Machine.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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #ifndef Machine_h
30 #define Machine_h
31
32 #include "ArgList.h"
33 #include "JSCell.h"
34 #include "JSValue.h"
35 #include "Opcode.h"
36 #include "RegisterFile.h"
37 #include <wtf/HashMap.h>
38
39 #if ENABLE(CTI)
40 #include "CTI.h"
41 #endif
42
43 namespace JSC {
44
45     class CodeBlock;
46     class EvalNode;
47     class ExecState;
48     class FunctionBodyNode;
49     class Instruction;
50     class InternalFunction;
51     class JSFunction;
52     class JSGlobalObject;
53     class ProgramNode;
54     class Register;
55     class ScopeChainNode;
56     class SamplingTool;
57
58     enum DebugHookID {
59         WillExecuteProgram,
60         DidExecuteProgram,
61         DidEnterCallFrame,
62         DidReachBreakpoint,
63         WillLeaveCallFrame,
64         WillExecuteStatement
65     };
66
67     enum { MaxReentryDepth = 128 };
68
69     class Machine {
70         friend class CTI;
71     public:
72         Machine();
73         ~Machine();
74         
75         RegisterFile& registerFile() { return m_registerFile; }
76         
77         Opcode getOpcode(OpcodeID id)
78         {
79             #if HAVE(COMPUTED_GOTO)
80                 return m_opcodeTable[id];
81             #else
82                 return id;
83             #endif
84         }
85
86         OpcodeID getOpcodeID(Opcode opcode)
87         {
88             #if HAVE(COMPUTED_GOTO)
89                 ASSERT(isOpcode(opcode));
90                 return m_opcodeIDTable.get(opcode);
91             #else
92                 return opcode;
93             #endif
94         }
95
96         bool isOpcode(Opcode opcode);
97         
98         JSValue* execute(ProgramNode*, ExecState*, ScopeChainNode*, JSObject* thisObj, JSValue** exception);
99         JSValue* execute(FunctionBodyNode*, ExecState*, JSFunction*, JSObject* thisObj, const ArgList& args, ScopeChainNode*, JSValue** exception);
100         JSValue* execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception);
101
102         JSValue* retrieveArguments(ExecState*, JSFunction*) const;
103         JSValue* retrieveCaller(ExecState*, InternalFunction*) const;
104         void retrieveLastCaller(ExecState* exec, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue*& function) const;
105         
106         static ScopeChainNode* scopeChain(const Register* r) { return r[RegisterFile::ScopeChain].scopeChain(); }
107         static CodeBlock* codeBlock(const Register* r) { return r[RegisterFile::CodeBlock].codeBlock(); }
108
109         void getArgumentsData(Register* callFrame, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
110         void setTimeoutTime(unsigned timeoutTime) { m_timeoutTime = timeoutTime; }
111         
112         void startTimeoutCheck()
113         {
114             if (!m_timeoutCheckCount)
115                 resetTimeoutCheck();
116             
117             ++m_timeoutCheckCount;
118         }
119         
120         void stopTimeoutCheck()
121         {
122             ASSERT(m_timeoutCheckCount);
123             --m_timeoutCheckCount;
124         }
125
126         inline void initTimeout()
127         {
128             ASSERT(!m_timeoutCheckCount);
129             resetTimeoutCheck();
130             m_timeoutTime = 0;
131             m_timeoutCheckCount = 0;
132         }
133
134         SamplingTool* m_sampler;
135
136 #if ENABLE(CTI)
137
138         static void SFX_CALL cti_timeout_check(CTI_ARGS);
139
140         static JSValue* SFX_CALL cti_op_convert_this(CTI_ARGS);
141         static void SFX_CALL cti_op_end(CTI_ARGS);
142         static JSValue* SFX_CALL cti_op_add(CTI_ARGS);
143         static JSValue* SFX_CALL cti_op_pre_inc(CTI_ARGS);
144         static int SFX_CALL cti_op_loop_if_less(CTI_ARGS);
145         static int SFX_CALL cti_op_loop_if_lesseq(CTI_ARGS);
146         static JSValue* SFX_CALL cti_op_new_object(CTI_ARGS);
147         static void SFX_CALL cti_op_put_by_id(CTI_ARGS);
148         static void SFX_CALL cti_op_put_by_id_second(CTI_ARGS);
149         static void SFX_CALL cti_op_put_by_id_generic(CTI_ARGS);
150         static void SFX_CALL cti_op_put_by_id_fail(CTI_ARGS);
151         static JSValue* SFX_CALL cti_op_get_by_id(CTI_ARGS);
152         static JSValue* SFX_CALL cti_op_get_by_id_second(CTI_ARGS);
153         static JSValue* SFX_CALL cti_op_get_by_id_generic(CTI_ARGS);
154         static JSValue* SFX_CALL cti_op_get_by_id_fail(CTI_ARGS);
155         static JSValue* SFX_CALL cti_op_del_by_id(CTI_ARGS);
156         static JSValue* SFX_CALL cti_op_instanceof(CTI_ARGS);
157         static JSValue* SFX_CALL cti_op_mul(CTI_ARGS);
158         static JSValue* SFX_CALL cti_op_new_func(CTI_ARGS);
159         static VoidPtrPair SFX_CALL cti_op_call_JSFunction(CTI_ARGS);
160         static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
161         static void SFX_CALL cti_op_create_arguments(CTI_ARGS);
162         static void SFX_CALL cti_op_tear_off_activation(CTI_ARGS);
163         static void SFX_CALL cti_op_tear_off_arguments(CTI_ARGS);
164         static void SFX_CALL cti_op_ret_profiler(CTI_ARGS);
165         static void SFX_CALL cti_op_ret_scopeChain(CTI_ARGS);
166         static JSValue* SFX_CALL cti_op_new_array(CTI_ARGS);
167         static JSValue* SFX_CALL cti_op_resolve(CTI_ARGS);
168         static JSValue* SFX_CALL cti_op_resolve_global(CTI_ARGS);
169         static VoidPtrPair SFX_CALL cti_op_construct_JSConstruct(CTI_ARGS);
170         static JSValue* SFX_CALL cti_op_construct_NotJSConstruct(CTI_ARGS);
171         static JSValue* SFX_CALL cti_op_get_by_val(CTI_ARGS);
172         static VoidPtrPair SFX_CALL cti_op_resolve_func(CTI_ARGS);
173         static JSValue* SFX_CALL cti_op_sub(CTI_ARGS);
174         static void SFX_CALL cti_op_put_by_val(CTI_ARGS);
175         static void SFX_CALL cti_op_put_by_val_array(CTI_ARGS);
176         static JSValue* SFX_CALL cti_op_lesseq(CTI_ARGS);
177         static int SFX_CALL cti_op_loop_if_true(CTI_ARGS);
178         static JSValue* SFX_CALL cti_op_resolve_base(CTI_ARGS);
179         static JSValue* SFX_CALL cti_op_negate(CTI_ARGS);
180         static JSValue* SFX_CALL cti_op_resolve_skip(CTI_ARGS);
181         static JSValue* SFX_CALL cti_op_div(CTI_ARGS);
182         static JSValue* SFX_CALL cti_op_pre_dec(CTI_ARGS);
183         static int SFX_CALL cti_op_jless(CTI_ARGS);
184         static JSValue* SFX_CALL cti_op_not(CTI_ARGS);
185         static int SFX_CALL cti_op_jtrue(CTI_ARGS);
186         static VoidPtrPair SFX_CALL cti_op_post_inc(CTI_ARGS);
187         static JSValue* SFX_CALL cti_op_eq(CTI_ARGS);
188         static JSValue* SFX_CALL cti_op_lshift(CTI_ARGS);
189         static JSValue* SFX_CALL cti_op_bitand(CTI_ARGS);
190         static JSValue* SFX_CALL cti_op_rshift(CTI_ARGS);
191         static JSValue* SFX_CALL cti_op_bitnot(CTI_ARGS);
192         static VoidPtrPair SFX_CALL cti_op_resolve_with_base(CTI_ARGS);
193         static JSValue* SFX_CALL cti_op_new_func_exp(CTI_ARGS);
194         static JSValue* SFX_CALL cti_op_mod(CTI_ARGS);
195         static JSValue* SFX_CALL cti_op_less(CTI_ARGS);
196         static JSValue* SFX_CALL cti_op_neq(CTI_ARGS);
197         static VoidPtrPair SFX_CALL cti_op_post_dec(CTI_ARGS);
198         static JSValue* SFX_CALL cti_op_urshift(CTI_ARGS);
199         static JSValue* SFX_CALL cti_op_bitxor(CTI_ARGS);
200         static JSValue* SFX_CALL cti_op_new_regexp(CTI_ARGS);
201         static JSValue* SFX_CALL cti_op_bitor(CTI_ARGS);
202         static JSValue* SFX_CALL cti_op_call_eval(CTI_ARGS);
203         static void* SFX_CALL cti_op_throw(CTI_ARGS);
204         static JSPropertyNameIterator* SFX_CALL cti_op_get_pnames(CTI_ARGS);
205         static JSValue* SFX_CALL cti_op_next_pname(CTI_ARGS);
206         static void SFX_CALL cti_op_push_scope(CTI_ARGS);
207         static void SFX_CALL cti_op_pop_scope(CTI_ARGS);
208         static JSValue* SFX_CALL cti_op_typeof(CTI_ARGS);
209         static JSValue* SFX_CALL cti_op_is_undefined(CTI_ARGS);
210         static JSValue* SFX_CALL cti_op_is_boolean(CTI_ARGS);
211         static JSValue* SFX_CALL cti_op_is_number(CTI_ARGS);
212         static JSValue* SFX_CALL cti_op_is_string(CTI_ARGS);
213         static JSValue* SFX_CALL cti_op_is_object(CTI_ARGS);
214         static JSValue* SFX_CALL cti_op_is_function(CTI_ARGS);
215         static JSValue* SFX_CALL cti_op_stricteq(CTI_ARGS);
216         static JSValue* SFX_CALL cti_op_nstricteq(CTI_ARGS);
217         static JSValue* SFX_CALL cti_op_to_jsnumber(CTI_ARGS);
218         static JSValue* SFX_CALL cti_op_in(CTI_ARGS);
219         static JSValue* SFX_CALL cti_op_push_new_scope(CTI_ARGS);
220         static void SFX_CALL cti_op_jmp_scopes(CTI_ARGS);
221         static void SFX_CALL cti_op_put_by_index(CTI_ARGS);
222         static void* SFX_CALL cti_op_switch_imm(CTI_ARGS);
223         static void* SFX_CALL cti_op_switch_char(CTI_ARGS);
224         static void* SFX_CALL cti_op_switch_string(CTI_ARGS);
225         static JSValue* SFX_CALL cti_op_del_by_val(CTI_ARGS);
226         static void SFX_CALL cti_op_put_getter(CTI_ARGS);
227         static void SFX_CALL cti_op_put_setter(CTI_ARGS);
228         static JSValue* SFX_CALL cti_op_new_error(CTI_ARGS);
229         static void SFX_CALL cti_op_debug(CTI_ARGS);
230
231         static void* SFX_CALL cti_vm_throw(CTI_ARGS);
232         static void* SFX_CALL cti_vm_compile(CTI_ARGS);
233         static JSValue* SFX_CALL cti_op_push_activation(CTI_ARGS);
234         
235 #endif // ENABLE(CTI)
236
237         // Default number of ticks before a timeout check should be done.
238         static const int initialTickCountThreshold = 1024;
239
240         bool isJSArray(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsArrayVptr; }
241         bool isJSString(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringVptr; }
242         
243         ALWAYS_INLINE static void initializeCallFrame(Register* callFrame, CodeBlock*, Instruction*, ScopeChainNode*, Register* r, int returnValueRegister, int argc, JSValue* function);
244
245     private:
246         enum ExecutionFlag { Normal, InitializeAndReturn };
247
248         NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile*, Register* r, int argv, int argc, JSValue*& exceptionValue);
249         JSValue* execute(EvalNode*, ExecState*, JSObject* thisObj, int registerOffset, ScopeChainNode*, JSValue** exception);
250
251         NEVER_INLINE void debug(ExecState*, Register*, DebugHookID, int firstLine, int lastLine);
252
253         NEVER_INLINE bool resolve(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
254         NEVER_INLINE bool resolveSkip(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
255         NEVER_INLINE bool resolveGlobal(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
256         NEVER_INLINE void resolveBase(ExecState* exec, Instruction* vPC, Register* r);
257         NEVER_INLINE bool resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
258         NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, const Instruction* vPC, Register* r);
259
260         NEVER_INLINE bool unwindCallFrame(ExecState*&, JSValue*, const Instruction*&, CodeBlock*&, Register*&);
261         NEVER_INLINE Instruction* throwException(ExecState*, JSValue*&, const Instruction*, Register*&, bool);
262         NEVER_INLINE bool resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
263
264         Register* callFrame(ExecState*, InternalFunction*) const;
265
266         JSValue* privateExecute(ExecutionFlag, RegisterFile*, Register*, JSValue** exception);
267
268         void dumpCallFrame(const RegisterFile*, const Register*);
269         void dumpRegisters(const RegisterFile*, const Register*);
270
271         JSValue* checkTimeout(JSGlobalObject*);
272         void resetTimeoutCheck();
273
274         void tryCacheGetByID(ExecState*, CodeBlock*, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
275         void uncacheGetByID(CodeBlock*, Instruction* vPC);
276         void tryCachePutByID(ExecState* exec, CodeBlock*, Instruction* vPC, JSValue* baseValue, const PutPropertySlot&);
277         void uncachePutByID(CodeBlock*, Instruction* vPC);
278
279 #if ENABLE(CTI)
280         void tryCTICacheGetByID(ExecState*, CodeBlock*, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
281         void tryCTICachePutByID(ExecState*, CodeBlock*, void* returnAddress, JSValue* baseValue, const PutPropertySlot&);
282
283         void* getCTIArrayLengthTrampoline(ExecState*, CodeBlock*);
284         void* getCTIStringLengthTrampoline(ExecState*, CodeBlock*);
285
286         void* m_ctiArrayLengthTrampoline;
287         void* m_ctiStringLengthTrampoline;
288
289         OwnPtr<JITCodeBuffer> m_jitCodeBuffer;
290         JITCodeBuffer* jitCodeBuffer() const { return m_jitCodeBuffer.get(); }
291 #endif
292
293         int m_reentryDepth;
294         unsigned m_timeoutTime;
295         unsigned m_timeAtLastCheckTimeout;
296         unsigned m_timeExecuting;
297         unsigned m_timeoutCheckCount;
298         unsigned m_ticksUntilNextTimeoutCheck;
299
300         RegisterFile m_registerFile;
301         
302         void* m_jsArrayVptr;
303         void* m_jsStringVptr;
304         void* m_jsFunctionVptr;
305
306 #if HAVE(COMPUTED_GOTO)
307         Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
308         HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
309 #endif
310     };
311
312     ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argc, JSValue* function)
313     {
314         ASSERT(r); // use makeHostCallFramePointer(0) to create a host call frame sentinel.
315         callFrame[RegisterFile::CodeBlock] = codeBlock;
316         callFrame[RegisterFile::ScopeChain] = scopeChain;
317         callFrame[RegisterFile::CallerRegisters] = r;
318         callFrame[RegisterFile::ReturnPC] = vPC;
319         callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
320         callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
321         callFrame[RegisterFile::Callee] = function;
322         callFrame[RegisterFile::OptionalCalleeArguments] = nullJSValue;
323     }
324
325     const intptr_t HostCallFrameMask = 1;
326
327     inline Register* makeHostCallFramePointer(Register* callFrame)
328     {
329         return reinterpret_cast<Register*>(reinterpret_cast<intptr_t>(callFrame) | HostCallFrameMask);
330     }
331
332     inline bool isHostCallFrame(Register* callFrame)
333     {
334         return reinterpret_cast<intptr_t>(callFrame) & HostCallFrameMask;
335     }
336
337     inline Register* stripHostCallFrameBit(Register* callFrame)
338     {
339         return reinterpret_cast<Register*>(reinterpret_cast<intptr_t>(callFrame) & ~HostCallFrameMask);
340     }
341
342 } // namespace JSC
343
344 #endif // Machine_h