2008-10-16 Maciej Stachowiak <mjs@apple.com>
[WebKit.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 namespace JSC {
40
41     class CodeBlock;
42     class EvalNode;
43     class FunctionBodyNode;
44     class Instruction;
45     class InternalFunction;
46     class JITCodeBuffer;
47     class JSFunction;
48     class JSGlobalObject;
49     class ProgramNode;
50     class Register;
51     class ScopeChainNode;
52     class SamplingTool;
53
54 #if ENABLE(CTI)
55
56 #if USE(CTI_ARGUMENT)
57 #define CTI_ARGS void** args
58 #define ARGS (args)
59 #else
60 #define CTI_ARGS void* args, ...
61 #define ARGS (&args)
62 #endif
63
64 #if USE(FAST_CALL_CTI_ARGUMENT)
65
66 #if COMPILER(MSVC)
67 #define SFX_CALL __fastcall
68 #elif COMPILER(GCC)
69 #define SFX_CALL  __attribute__ ((fastcall))
70 #else
71 #error Need to support fastcall calling convention in this compiler
72 #endif
73
74 #else
75
76 #if COMPILER(MSVC)
77 #define SFX_CALL __cdecl
78 #else
79 #define SFX_CALL
80 #endif
81
82 #endif
83
84     struct VoidPtrPair { void* first; void* second; };
85 #endif
86
87     enum DebugHookID {
88         WillExecuteProgram,
89         DidExecuteProgram,
90         DidEnterCallFrame,
91         DidReachBreakpoint,
92         WillLeaveCallFrame,
93         WillExecuteStatement
94     };
95
96     enum { MaxReentryDepth = 128 };
97
98     class Machine {
99         friend class CTI;
100     public:
101         Machine();
102         ~Machine();
103         
104         RegisterFile& registerFile() { return m_registerFile; }
105         
106         Opcode getOpcode(OpcodeID id)
107         {
108             #if HAVE(COMPUTED_GOTO)
109                 return m_opcodeTable[id];
110             #else
111                 return id;
112             #endif
113         }
114
115         OpcodeID getOpcodeID(Opcode opcode)
116         {
117             #if HAVE(COMPUTED_GOTO)
118                 ASSERT(isOpcode(opcode));
119                 return m_opcodeIDTable.get(opcode);
120             #else
121                 return opcode;
122             #endif
123         }
124
125         bool isOpcode(Opcode opcode);
126         
127         JSValue* execute(ProgramNode*, CallFrame*, ScopeChainNode*, JSObject* thisObj, JSValue** exception);
128         JSValue* execute(FunctionBodyNode*, CallFrame*, JSFunction*, JSObject* thisObj, const ArgList& args, ScopeChainNode*, JSValue** exception);
129         JSValue* execute(EvalNode* evalNode, CallFrame* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception);
130
131         JSValue* retrieveArguments(CallFrame*, JSFunction*) const;
132         JSValue* retrieveCaller(CallFrame*, InternalFunction*) const;
133         void retrieveLastCaller(CallFrame*, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue*& function) const;
134         
135         void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
136         void setTimeoutTime(unsigned timeoutTime) { m_timeoutTime = timeoutTime; }
137         
138         void startTimeoutCheck()
139         {
140             if (!m_timeoutCheckCount)
141                 resetTimeoutCheck();
142             
143             ++m_timeoutCheckCount;
144         }
145         
146         void stopTimeoutCheck()
147         {
148             ASSERT(m_timeoutCheckCount);
149             --m_timeoutCheckCount;
150         }
151
152         inline void initTimeout()
153         {
154             ASSERT(!m_timeoutCheckCount);
155             resetTimeoutCheck();
156             m_timeoutTime = 0;
157             m_timeoutCheckCount = 0;
158         }
159
160         SamplingTool* m_sampler;
161
162 #if ENABLE(CTI)
163
164         static void SFX_CALL cti_timeout_check(CTI_ARGS);
165         static void SFX_CALL cti_register_file_check(CTI_ARGS);
166
167         static JSValue* SFX_CALL cti_op_convert_this(CTI_ARGS);
168         static void SFX_CALL cti_op_end(CTI_ARGS);
169         static JSValue* SFX_CALL cti_op_add(CTI_ARGS);
170         static JSValue* SFX_CALL cti_op_pre_inc(CTI_ARGS);
171         static int SFX_CALL cti_op_loop_if_less(CTI_ARGS);
172         static int SFX_CALL cti_op_loop_if_lesseq(CTI_ARGS);
173         static JSValue* SFX_CALL cti_op_new_object(CTI_ARGS);
174         static void SFX_CALL cti_op_put_by_id(CTI_ARGS);
175         static void SFX_CALL cti_op_put_by_id_second(CTI_ARGS);
176         static void SFX_CALL cti_op_put_by_id_generic(CTI_ARGS);
177         static void SFX_CALL cti_op_put_by_id_fail(CTI_ARGS);
178         static JSValue* SFX_CALL cti_op_get_by_id(CTI_ARGS);
179         static JSValue* SFX_CALL cti_op_get_by_id_second(CTI_ARGS);
180         static JSValue* SFX_CALL cti_op_get_by_id_generic(CTI_ARGS);
181         static JSValue* SFX_CALL cti_op_get_by_id_fail(CTI_ARGS);
182         static JSValue* SFX_CALL cti_op_del_by_id(CTI_ARGS);
183         static JSValue* SFX_CALL cti_op_instanceof(CTI_ARGS);
184         static JSValue* SFX_CALL cti_op_mul(CTI_ARGS);
185         static JSValue* SFX_CALL cti_op_new_func(CTI_ARGS);
186         static VoidPtrPair SFX_CALL cti_op_call_JSFunction(CTI_ARGS);
187         static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
188         static void SFX_CALL cti_op_create_arguments(CTI_ARGS);
189         static void SFX_CALL cti_op_tear_off_activation(CTI_ARGS);
190         static void SFX_CALL cti_op_tear_off_arguments(CTI_ARGS);
191         static void SFX_CALL cti_op_ret_profiler(CTI_ARGS);
192         static void SFX_CALL cti_op_ret_scopeChain(CTI_ARGS);
193         static JSValue* SFX_CALL cti_op_new_array(CTI_ARGS);
194         static JSValue* SFX_CALL cti_op_resolve(CTI_ARGS);
195         static JSValue* SFX_CALL cti_op_resolve_global(CTI_ARGS);
196         static VoidPtrPair SFX_CALL cti_op_construct_JSConstruct(CTI_ARGS);
197         static JSValue* SFX_CALL cti_op_construct_NotJSConstruct(CTI_ARGS);
198         static JSValue* SFX_CALL cti_op_get_by_val(CTI_ARGS);
199         static VoidPtrPair SFX_CALL cti_op_resolve_func(CTI_ARGS);
200         static JSValue* SFX_CALL cti_op_sub(CTI_ARGS);
201         static void SFX_CALL cti_op_put_by_val(CTI_ARGS);
202         static void SFX_CALL cti_op_put_by_val_array(CTI_ARGS);
203         static JSValue* SFX_CALL cti_op_lesseq(CTI_ARGS);
204         static int SFX_CALL cti_op_loop_if_true(CTI_ARGS);
205         static JSValue* SFX_CALL cti_op_resolve_base(CTI_ARGS);
206         static JSValue* SFX_CALL cti_op_negate(CTI_ARGS);
207         static JSValue* SFX_CALL cti_op_resolve_skip(CTI_ARGS);
208         static JSValue* SFX_CALL cti_op_div(CTI_ARGS);
209         static JSValue* SFX_CALL cti_op_pre_dec(CTI_ARGS);
210         static int SFX_CALL cti_op_jless(CTI_ARGS);
211         static JSValue* SFX_CALL cti_op_not(CTI_ARGS);
212         static int SFX_CALL cti_op_jtrue(CTI_ARGS);
213         static VoidPtrPair SFX_CALL cti_op_post_inc(CTI_ARGS);
214         static JSValue* SFX_CALL cti_op_eq(CTI_ARGS);
215         static JSValue* SFX_CALL cti_op_lshift(CTI_ARGS);
216         static JSValue* SFX_CALL cti_op_bitand(CTI_ARGS);
217         static JSValue* SFX_CALL cti_op_rshift(CTI_ARGS);
218         static JSValue* SFX_CALL cti_op_bitnot(CTI_ARGS);
219         static VoidPtrPair SFX_CALL cti_op_resolve_with_base(CTI_ARGS);
220         static JSValue* SFX_CALL cti_op_new_func_exp(CTI_ARGS);
221         static JSValue* SFX_CALL cti_op_mod(CTI_ARGS);
222         static JSValue* SFX_CALL cti_op_less(CTI_ARGS);
223         static JSValue* SFX_CALL cti_op_neq(CTI_ARGS);
224         static VoidPtrPair SFX_CALL cti_op_post_dec(CTI_ARGS);
225         static JSValue* SFX_CALL cti_op_urshift(CTI_ARGS);
226         static JSValue* SFX_CALL cti_op_bitxor(CTI_ARGS);
227         static JSValue* SFX_CALL cti_op_new_regexp(CTI_ARGS);
228         static JSValue* SFX_CALL cti_op_bitor(CTI_ARGS);
229         static JSValue* SFX_CALL cti_op_call_eval(CTI_ARGS);
230         static void* SFX_CALL cti_op_throw(CTI_ARGS);
231         static JSPropertyNameIterator* SFX_CALL cti_op_get_pnames(CTI_ARGS);
232         static JSValue* SFX_CALL cti_op_next_pname(CTI_ARGS);
233         static void SFX_CALL cti_op_push_scope(CTI_ARGS);
234         static void SFX_CALL cti_op_pop_scope(CTI_ARGS);
235         static JSValue* SFX_CALL cti_op_typeof(CTI_ARGS);
236         static JSValue* SFX_CALL cti_op_is_undefined(CTI_ARGS);
237         static JSValue* SFX_CALL cti_op_is_boolean(CTI_ARGS);
238         static JSValue* SFX_CALL cti_op_is_number(CTI_ARGS);
239         static JSValue* SFX_CALL cti_op_is_string(CTI_ARGS);
240         static JSValue* SFX_CALL cti_op_is_object(CTI_ARGS);
241         static JSValue* SFX_CALL cti_op_is_function(CTI_ARGS);
242         static JSValue* SFX_CALL cti_op_stricteq(CTI_ARGS);
243         static JSValue* SFX_CALL cti_op_nstricteq(CTI_ARGS);
244         static JSValue* SFX_CALL cti_op_to_jsnumber(CTI_ARGS);
245         static JSValue* SFX_CALL cti_op_in(CTI_ARGS);
246         static JSValue* SFX_CALL cti_op_push_new_scope(CTI_ARGS);
247         static void SFX_CALL cti_op_jmp_scopes(CTI_ARGS);
248         static void SFX_CALL cti_op_put_by_index(CTI_ARGS);
249         static void* SFX_CALL cti_op_switch_imm(CTI_ARGS);
250         static void* SFX_CALL cti_op_switch_char(CTI_ARGS);
251         static void* SFX_CALL cti_op_switch_string(CTI_ARGS);
252         static JSValue* SFX_CALL cti_op_del_by_val(CTI_ARGS);
253         static void SFX_CALL cti_op_put_getter(CTI_ARGS);
254         static void SFX_CALL cti_op_put_setter(CTI_ARGS);
255         static JSValue* SFX_CALL cti_op_new_error(CTI_ARGS);
256         static void SFX_CALL cti_op_debug(CTI_ARGS);
257
258         static void* SFX_CALL cti_vm_throw(CTI_ARGS);
259         static void* SFX_CALL cti_vm_compile(CTI_ARGS);
260         static JSValue* SFX_CALL cti_op_push_activation(CTI_ARGS);
261         
262 #endif // ENABLE(CTI)
263
264         // Default number of ticks before a timeout check should be done.
265         static const int initialTickCountThreshold = 1024;
266
267         bool isJSArray(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsArrayVptr; }
268         bool isJSString(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringVptr; }
269
270     private:
271         enum ExecutionFlag { Normal, InitializeAndReturn };
272
273         NEVER_INLINE JSValue* callEval(CallFrame*, JSObject* thisObject, ScopeChainNode*, RegisterFile*, int argv, int argc, JSValue*& exceptionValue);
274         JSValue* execute(EvalNode*, CallFrame*, JSObject* thisObject, int registerOffset, ScopeChainNode*, JSValue** exception);
275
276         NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine);
277
278         NEVER_INLINE bool resolve(CallFrame*, Instruction*, JSValue*& exceptionValue);
279         NEVER_INLINE bool resolveSkip(CallFrame*, Instruction*, JSValue*& exceptionValue);
280         NEVER_INLINE bool resolveGlobal(CallFrame*, Instruction*, JSValue*& exceptionValue);
281         NEVER_INLINE void resolveBase(CallFrame*, Instruction* vPC);
282         NEVER_INLINE bool resolveBaseAndProperty(CallFrame*, Instruction*, JSValue*& exceptionValue);
283         NEVER_INLINE ScopeChainNode* createExceptionScope(CallFrame*, const Instruction* vPC);
284
285         NEVER_INLINE bool unwindCallFrame(CallFrame*&, JSValue*, const Instruction*&, CodeBlock*&);
286         NEVER_INLINE Instruction* throwException(CallFrame*&, JSValue*&, const Instruction*, bool);
287         NEVER_INLINE bool resolveBaseAndFunc(CallFrame*, Instruction*, JSValue*& exceptionValue);
288
289         static ALWAYS_INLINE CallFrame* slideRegisterWindowForCall(CodeBlock*, RegisterFile*, CallFrame*, size_t registerOffset, int argc);
290
291         static CallFrame* findFunctionCallFrame(CallFrame*, InternalFunction*);
292
293         JSValue* privateExecute(ExecutionFlag, RegisterFile*, CallFrame*, JSValue** exception);
294
295         void dumpCallFrame(const RegisterFile*, CallFrame*);
296         void dumpRegisters(const RegisterFile*, CallFrame*);
297
298         JSValue* checkTimeout(JSGlobalObject*);
299         void resetTimeoutCheck();
300
301         void tryCacheGetByID(CallFrame*, CodeBlock*, Instruction*, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
302         void uncacheGetByID(CodeBlock*, Instruction* vPC);
303         void tryCachePutByID(CallFrame*, CodeBlock*, Instruction*, JSValue* baseValue, const PutPropertySlot&);
304         void uncachePutByID(CodeBlock*, Instruction* vPC);
305
306 #if ENABLE(CTI)
307         void tryCTICacheGetByID(CallFrame*, CodeBlock*, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
308         void tryCTICachePutByID(CallFrame*, CodeBlock*, void* returnAddress, JSValue* baseValue, const PutPropertySlot&);
309
310         void* getCTIArrayLengthTrampoline(CallFrame*, CodeBlock*);
311         void* getCTIStringLengthTrampoline(CallFrame*, CodeBlock*);
312
313         void* m_ctiArrayLengthTrampoline;
314         void* m_ctiStringLengthTrampoline;
315
316         OwnPtr<JITCodeBuffer> m_jitCodeBuffer;
317         JITCodeBuffer* jitCodeBuffer() const { return m_jitCodeBuffer.get(); }
318 #endif
319
320         int m_reentryDepth;
321         unsigned m_timeoutTime;
322         unsigned m_timeAtLastCheckTimeout;
323         unsigned m_timeExecuting;
324         unsigned m_timeoutCheckCount;
325         unsigned m_ticksUntilNextTimeoutCheck;
326
327         RegisterFile m_registerFile;
328         
329         void* m_jsArrayVptr;
330         void* m_jsStringVptr;
331         void* m_jsFunctionVptr;
332
333 #if HAVE(COMPUTED_GOTO)
334         Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
335         HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
336 #endif
337     };
338
339 } // namespace JSC
340
341 #endif // Machine_h