Bug 20874: op_resolve does not do any form of caching
[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             return execute(evalNode, exec, thisObj, m_registerFile.size(), scopeChain, exception);
103         }
104
105         JSValue* retrieveArguments(ExecState*, JSFunction*) const;
106         JSValue* retrieveCaller(ExecState*, InternalFunction*) const;
107         void retrieveLastCaller(ExecState* exec, int& lineNumber, int& sourceId, UString& sourceURL, JSValue*& function) const;
108
109         void getArgumentsData(Register* callFrame, JSFunction*&, 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             --m_timeoutCheckCount;
123         }
124
125         inline void initTimeout()
126         {
127             resetTimeoutCheck();
128             m_timeoutTime = 0;
129             m_timeoutCheckCount = 0;
130         }
131
132         SamplingTool* m_sampler;
133
134 #if ENABLE(CTI)
135 #if COMPILER(MSVC)
136 #define SFX_CALL __cdecl
137 #else
138 #define SFX_CALL
139 #endif
140
141         static void SFX_CALL cti_timeout_check(CTI_ARGS);
142
143         static void SFX_CALL cti_op_end(CTI_ARGS);
144         static JSValue* SFX_CALL cti_op_add(CTI_ARGS);
145         static JSValue* SFX_CALL cti_op_pre_inc(CTI_ARGS);
146         static int SFX_CALL cti_op_loop_if_less(CTI_ARGS);
147         static int SFX_CALL cti_op_loop_if_lesseq(CTI_ARGS);
148         static JSValue* SFX_CALL cti_op_new_object(CTI_ARGS);
149         static void SFX_CALL cti_op_put_by_id(CTI_ARGS);
150         static void SFX_CALL cti_op_put_by_id_second(CTI_ARGS);
151         static void SFX_CALL cti_op_put_by_id_generic(CTI_ARGS);
152         static void SFX_CALL cti_op_put_by_id_fail(CTI_ARGS);
153         static JSValue* SFX_CALL cti_op_get_by_id(CTI_ARGS);
154         static JSValue* SFX_CALL cti_op_get_by_id_second(CTI_ARGS);
155         static JSValue* SFX_CALL cti_op_get_by_id_generic(CTI_ARGS);
156         static JSValue* SFX_CALL cti_op_get_by_id_fail(CTI_ARGS);
157         static JSValue* SFX_CALL cti_op_del_by_id(CTI_ARGS);
158         static JSValue* SFX_CALL cti_op_instanceof(CTI_ARGS);
159         static JSValue* SFX_CALL cti_op_mul(CTI_ARGS);
160         static JSValue* SFX_CALL cti_op_new_func(CTI_ARGS);
161         static void* SFX_CALL cti_op_call_JSFunction(CTI_ARGS);
162         static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
163         static JSValue* SFX_CALL cti_op_ret(CTI_ARGS);
164         static JSValue* SFX_CALL cti_op_new_array(CTI_ARGS);
165         static JSValue* SFX_CALL cti_op_resolve(CTI_ARGS);
166         static JSValue* SFX_CALL cti_op_resolve_global(CTI_ARGS);
167         static void* SFX_CALL cti_op_construct_JSConstruct(CTI_ARGS);
168         static JSValue* SFX_CALL cti_op_construct_NotJSConstruct(CTI_ARGS);
169         static void SFX_CALL cti_op_construct_verify(CTI_ARGS);
170         static JSValue* SFX_CALL cti_op_get_by_val(CTI_ARGS);
171         static JSValue* SFX_CALL cti_op_resolve_func(CTI_ARGS);
172         static JSValue* SFX_CALL cti_op_sub(CTI_ARGS);
173         static void SFX_CALL cti_op_put_by_val(CTI_ARGS);
174         static void SFX_CALL cti_op_put_by_val_array(CTI_ARGS);
175         static JSValue* SFX_CALL cti_op_lesseq(CTI_ARGS);
176         static int SFX_CALL cti_op_loop_if_true(CTI_ARGS);
177         static JSValue* SFX_CALL cti_op_resolve_base(CTI_ARGS);
178         static JSValue* SFX_CALL cti_op_negate(CTI_ARGS);
179         static JSValue* SFX_CALL cti_op_resolve_skip(CTI_ARGS);
180         static JSValue* SFX_CALL cti_op_div(CTI_ARGS);
181         static JSValue* SFX_CALL cti_op_pre_dec(CTI_ARGS);
182         static int SFX_CALL cti_op_jless(CTI_ARGS);
183         static JSValue* SFX_CALL cti_op_not(CTI_ARGS);
184         static int SFX_CALL cti_op_jtrue(CTI_ARGS);
185         static JSValue* SFX_CALL cti_op_post_inc(CTI_ARGS);
186         static JSValue* SFX_CALL cti_op_eq(CTI_ARGS);
187         static JSValue* SFX_CALL cti_op_lshift(CTI_ARGS);
188         static JSValue* SFX_CALL cti_op_bitand(CTI_ARGS);
189         static JSValue* SFX_CALL cti_op_rshift(CTI_ARGS);
190         static JSValue* SFX_CALL cti_op_bitnot(CTI_ARGS);
191         static JSValue* SFX_CALL cti_op_resolve_with_base(CTI_ARGS);
192         static JSValue* SFX_CALL cti_op_new_func_exp(CTI_ARGS);
193         static JSValue* SFX_CALL cti_op_mod(CTI_ARGS);
194         static JSValue* SFX_CALL cti_op_less(CTI_ARGS);
195         static JSValue* SFX_CALL cti_op_neq(CTI_ARGS);
196         static JSValue* SFX_CALL cti_op_post_dec(CTI_ARGS);
197         static JSValue* SFX_CALL cti_op_urshift(CTI_ARGS);
198         static JSValue* SFX_CALL cti_op_bitxor(CTI_ARGS);
199         static JSValue* SFX_CALL cti_op_new_regexp(CTI_ARGS);
200         static JSValue* SFX_CALL cti_op_bitor(CTI_ARGS);
201         static JSValue* SFX_CALL cti_op_call_eval(CTI_ARGS);
202         static void* SFX_CALL cti_op_throw(CTI_ARGS);
203         static JSPropertyNameIterator* SFX_CALL cti_op_get_pnames(CTI_ARGS);
204         static JSValue* SFX_CALL cti_op_next_pname(CTI_ARGS);
205         static void SFX_CALL cti_op_push_scope(CTI_ARGS);
206         static void SFX_CALL cti_op_pop_scope(CTI_ARGS);
207         static JSValue* SFX_CALL cti_op_typeof(CTI_ARGS);
208         static JSValue* SFX_CALL cti_op_is_undefined(CTI_ARGS);
209         static JSValue* SFX_CALL cti_op_is_boolean(CTI_ARGS);
210         static JSValue* SFX_CALL cti_op_is_number(CTI_ARGS);
211         static JSValue* SFX_CALL cti_op_is_string(CTI_ARGS);
212         static JSValue* SFX_CALL cti_op_is_object(CTI_ARGS);
213         static JSValue* SFX_CALL cti_op_is_function(CTI_ARGS);
214         static JSValue* SFX_CALL cti_op_stricteq(CTI_ARGS);
215         static JSValue* SFX_CALL cti_op_nstricteq(CTI_ARGS);
216         static JSValue* SFX_CALL cti_op_to_jsnumber(CTI_ARGS);
217         static JSValue* SFX_CALL cti_op_in(CTI_ARGS);
218         static JSValue* SFX_CALL cti_op_push_new_scope(CTI_ARGS);
219         static void SFX_CALL cti_op_jmp_scopes(CTI_ARGS);
220         static void SFX_CALL cti_op_put_by_index(CTI_ARGS);
221         static void* SFX_CALL cti_op_switch_imm(CTI_ARGS);
222         static void* SFX_CALL cti_op_switch_char(CTI_ARGS);
223         static void* SFX_CALL cti_op_switch_string(CTI_ARGS);
224         static JSValue* SFX_CALL cti_op_del_by_val(CTI_ARGS);
225         static void SFX_CALL cti_op_put_getter(CTI_ARGS);
226         static void SFX_CALL cti_op_put_setter(CTI_ARGS);
227         static JSValue* SFX_CALL cti_op_new_error(CTI_ARGS);
228         static void SFX_CALL cti_op_debug(CTI_ARGS);
229         static JSValue* SFX_CALL cti_op_eq_null(CTI_ARGS);
230         static JSValue* SFX_CALL cti_op_neq_null(CTI_ARGS);
231
232         static void* SFX_CALL cti_vm_throw(CTI_ARGS);
233 #endif // ENABLE(CTI)
234
235         // Default number of ticks before a timeout check should be done.
236         static const int initialTickCountThreshold = 1024;
237
238     private:
239         enum ExecutionFlag { Normal, InitializeAndReturn };
240
241         NEVER_INLINE JSValue* callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile*, Register* r, int argv, int argc, JSValue*& exceptionValue);
242         JSValue* execute(EvalNode*, ExecState*, JSObject* thisObj, int registerOffset, ScopeChainNode*, JSValue** exception);
243
244         ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock*, Instruction*, ScopeChainNode*, Register* r, int returnValueRegister, int argv, int argc, JSValue* function);
245
246         ALWAYS_INLINE void setScopeChain(ExecState* exec, ScopeChainNode*&, ScopeChainNode*);
247         NEVER_INLINE void debug(ExecState*, const CodeBlock*, ScopeChainNode*, Register*, DebugHookID, int firstLine, int lastLine);
248
249         NEVER_INLINE bool unwindCallFrame(ExecState*, JSValue*, const Instruction*&, CodeBlock*&, ScopeChainNode*&, Register*&);
250         NEVER_INLINE Instruction* throwException(ExecState*, JSValue*&, const Instruction*, CodeBlock*&, ScopeChainNode*&, Register*&, bool);
251
252         Register* callFrame(ExecState*, InternalFunction*) const;
253
254         JSValue* privateExecute(ExecutionFlag, ExecState* = 0, RegisterFile* = 0, Register* = 0, ScopeChainNode* = 0, CodeBlock* = 0, JSValue** exception = 0);
255
256         void dumpCallFrame(const CodeBlock*, ScopeChainNode*, RegisterFile*, const Register*);
257         void dumpRegisters(const CodeBlock*, RegisterFile*, const Register*);
258
259         JSValue* checkTimeout(JSGlobalObject*);
260         void resetTimeoutCheck();
261
262         bool isJSArray(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsArrayVptr; }
263         bool isJSString(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringVptr; }
264         
265         void tryCacheGetByID(ExecState*, CodeBlock*, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
266         void uncacheGetByID(CodeBlock*, Instruction* vPC);
267         void tryCachePutByID(ExecState* exec, CodeBlock*, Instruction* vPC, JSValue* baseValue, const PutPropertySlot&);
268         void uncachePutByID(CodeBlock*, Instruction* vPC);
269
270 #if ENABLE(CTI)
271         void tryCTICacheGetByID(ExecState*, CodeBlock*, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
272         void tryCTICachePutByID(ExecState*, CodeBlock*, void* returnAddress, JSValue* baseValue, const PutPropertySlot&);
273
274         void* getCTIArrayLengthTrampoline(ExecState*, CodeBlock*);
275         void* getCTIStringLengthTrampoline(ExecState*, CodeBlock*);
276
277         void* m_ctiArrayLengthTrampoline;
278         void* m_ctiStringLengthTrampoline;
279
280         OwnPtr<JITCodeBuffer> m_jitCodeBuffer;
281         JITCodeBuffer* jitCodeBuffer() const { return m_jitCodeBuffer.get(); }
282 #endif
283
284         int m_reentryDepth;
285         unsigned m_timeoutTime;
286         unsigned m_timeAtLastCheckTimeout;
287         unsigned m_timeExecuting;
288         unsigned m_timeoutCheckCount;
289         unsigned m_ticksUntilNextTimeoutCheck;
290
291         RegisterFile m_registerFile;
292         
293         void* m_jsArrayVptr;
294         void* m_jsStringVptr;
295         void* m_jsFunctionVptr;
296
297 #if HAVE(COMPUTED_GOTO)
298         Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
299         HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
300 #endif
301     };
302
303 } // namespace JSC
304
305 #endif // Machine_h