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