2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
36 #include "RegisterFile.h"
37 #include <wtf/HashMap.h>
48 class FunctionBodyNode;
50 class InternalFunction;
67 enum { MaxReentryDepth = 128 };
75 RegisterFile& registerFile() { return m_registerFile; }
77 static Opcode getOpcode(OpcodeID id);
79 OpcodeID getOpcodeID(Opcode opcode)
81 #if HAVE(COMPUTED_GOTO)
82 ASSERT(isOpcode(opcode));
83 return m_opcodeIDTable.get(opcode);
89 bool isOpcode(Opcode opcode);
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);
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;
99 void getArgumentsData(Register* callFrame, JSFunction*&, int& firstParameterIndex, Register*& argv, int& argc);
100 void setTimeoutTime(unsigned timeoutTime) { m_timeoutTime = timeoutTime; }
102 void startTimeoutCheck()
104 if (!m_timeoutCheckCount)
107 ++m_timeoutCheckCount;
110 void stopTimeoutCheck()
112 ASSERT(m_timeoutCheckCount);
113 --m_timeoutCheckCount;
116 inline void initTimeout()
118 ASSERT(!m_timeoutCheckCount);
121 m_timeoutCheckCount = 0;
124 SamplingTool* m_sampler;
128 #define SFX_CALL __cdecl
133 static void SFX_CALL cti_timeout_check(CTI_ARGS);
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);
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);
227 #endif // ENABLE(CTI)
229 // Default number of ticks before a timeout check should be done.
230 static const int initialTickCountThreshold = 1024;
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; }
236 enum ExecutionFlag { Normal, InitializeAndReturn };
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);
241 ALWAYS_INLINE static void initializeCallFrame(Register* callFrame, CodeBlock*, Instruction*, ScopeChainNode*, Register* r, int returnValueRegister, int argc, JSValue* function);
243 ALWAYS_INLINE void setScopeChain(ExecState* exec, ScopeChainNode*&, ScopeChainNode*);
244 NEVER_INLINE void debug(ExecState*, const CodeBlock*, ScopeChainNode*, Register*, DebugHookID, int firstLine, int lastLine);
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);
249 Register* callFrame(ExecState*, InternalFunction*) const;
251 JSValue* privateExecute(ExecutionFlag, ExecState* = 0, RegisterFile* = 0, Register* = 0, ScopeChainNode* = 0, CodeBlock* = 0, JSValue** exception = 0);
253 void dumpCallFrame(const CodeBlock*, ScopeChainNode*, RegisterFile*, const Register*);
254 void dumpRegisters(const CodeBlock*, RegisterFile*, const Register*);
256 JSValue* checkTimeout(JSGlobalObject*);
257 void resetTimeoutCheck();
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);
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&);
268 void* getCTIArrayLengthTrampoline(ExecState*, CodeBlock*);
269 void* getCTIStringLengthTrampoline(ExecState*, CodeBlock*);
271 void* m_ctiArrayLengthTrampoline;
272 void* m_ctiStringLengthTrampoline;
274 OwnPtr<JITCodeBuffer> m_jitCodeBuffer;
275 JITCodeBuffer* jitCodeBuffer() const { return m_jitCodeBuffer.get(); }
279 unsigned m_timeoutTime;
280 unsigned m_timeAtLastCheckTimeout;
281 unsigned m_timeExecuting;
282 unsigned m_timeoutCheckCount;
283 unsigned m_ticksUntilNextTimeoutCheck;
285 RegisterFile m_registerFile;
288 void* m_jsStringVptr;
289 void* m_jsFunctionVptr;
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