source: webkit/trunk/JavaScriptCore/VM/Machine.h@ 37268

Last change on this file since 37268 was 37268, checked in by [email protected], 17 years ago

2008-10-03 Cameron Zwarich <[email protected]>

Reviewed by Maciej Stachowiak.

Bug 21343: REGRESSSION (r37160): ecma_3/ExecutionContexts/10.1.3-1.js and js1_4/Functions/function-001.js fail on 64-bit
<https://bugs.webkit.org/show_bug.cgi?id=21343>

A fix was landed for this issue in r37253, and the ChangeLog assumes
that it is a compiler bug, but it turns out that it is a subtle issue
with mixing signed and unsigned 32-bit values in a 64-bit environment.
In order to properly fix this bug, we should convert our signed offsets
into the register file to use ptrdiff_t.

This may not be the only instance of this issue, but I will land this
fix first and look for more later.

  • VM/Machine.cpp: (JSC::Machine::getArgumentsData):
  • VM/Machine.h:
  • kjs/Arguments.cpp: (JSC::Arguments::getOwnPropertySlot):
  • kjs/Arguments.h: (JSC::Arguments::init):
File size: 15.6 KB
Line 
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
43namespace 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 const Register* firstCallFrame(const Register* callFrame);
107 static ScopeChainNode* scopeChain(const Register* r) { return r[RegisterFile::ScopeChain].scopeChain(); }
108 static CodeBlock* codeBlock(const Register* r) { return r[RegisterFile::CodeBlock].codeBlock(); }
109
110 void getArgumentsData(Register* callFrame, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
111 void setTimeoutTime(unsigned timeoutTime) { m_timeoutTime = timeoutTime; }
112
113 void startTimeoutCheck()
114 {
115 if (!m_timeoutCheckCount)
116 resetTimeoutCheck();
117
118 ++m_timeoutCheckCount;
119 }
120
121 void stopTimeoutCheck()
122 {
123 ASSERT(m_timeoutCheckCount);
124 --m_timeoutCheckCount;
125 }
126
127 inline void initTimeout()
128 {
129 ASSERT(!m_timeoutCheckCount);
130 resetTimeoutCheck();
131 m_timeoutTime = 0;
132 m_timeoutCheckCount = 0;
133 }
134
135 SamplingTool* m_sampler;
136
137#if ENABLE(CTI)
138#if COMPILER(MSVC)
139#define SFX_CALL __cdecl
140#else
141#define SFX_CALL
142#endif
143
144 static void SFX_CALL cti_timeout_check(CTI_ARGS);
145
146 static void SFX_CALL cti_op_end(CTI_ARGS);
147 static JSValue* SFX_CALL cti_op_add(CTI_ARGS);
148 static JSValue* SFX_CALL cti_op_pre_inc(CTI_ARGS);
149 static int SFX_CALL cti_op_loop_if_less(CTI_ARGS);
150 static int SFX_CALL cti_op_loop_if_lesseq(CTI_ARGS);
151 static JSValue* SFX_CALL cti_op_new_object(CTI_ARGS);
152 static void SFX_CALL cti_op_put_by_id(CTI_ARGS);
153 static void SFX_CALL cti_op_put_by_id_second(CTI_ARGS);
154 static void SFX_CALL cti_op_put_by_id_generic(CTI_ARGS);
155 static void SFX_CALL cti_op_put_by_id_fail(CTI_ARGS);
156 static JSValue* SFX_CALL cti_op_get_by_id(CTI_ARGS);
157 static JSValue* SFX_CALL cti_op_get_by_id_second(CTI_ARGS);
158 static JSValue* SFX_CALL cti_op_get_by_id_generic(CTI_ARGS);
159 static JSValue* SFX_CALL cti_op_get_by_id_fail(CTI_ARGS);
160 static JSValue* SFX_CALL cti_op_del_by_id(CTI_ARGS);
161 static JSValue* SFX_CALL cti_op_instanceof(CTI_ARGS);
162 static JSValue* SFX_CALL cti_op_mul(CTI_ARGS);
163 static JSValue* SFX_CALL cti_op_new_func(CTI_ARGS);
164 static void* SFX_CALL cti_op_call_JSFunction(CTI_ARGS);
165 static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
166 static void SFX_CALL cti_op_init_arguments(CTI_ARGS);
167 static void SFX_CALL cti_op_ret_activation_arguments(CTI_ARGS);
168 static void SFX_CALL cti_op_ret_profiler(CTI_ARGS);
169 static void SFX_CALL cti_op_ret_scopeChain(CTI_ARGS);
170 static JSValue* SFX_CALL cti_op_new_array(CTI_ARGS);
171 static JSValue* SFX_CALL cti_op_resolve(CTI_ARGS);
172 static JSValue* SFX_CALL cti_op_resolve_global(CTI_ARGS);
173 static void* SFX_CALL cti_op_construct_JSConstruct(CTI_ARGS);
174 static JSValue* SFX_CALL cti_op_construct_NotJSConstruct(CTI_ARGS);
175 static JSValue* SFX_CALL cti_op_get_by_val(CTI_ARGS);
176 static JSValue* SFX_CALL cti_op_resolve_func(CTI_ARGS);
177 static JSValue* SFX_CALL cti_op_sub(CTI_ARGS);
178 static void SFX_CALL cti_op_put_by_val(CTI_ARGS);
179 static void SFX_CALL cti_op_put_by_val_array(CTI_ARGS);
180 static JSValue* SFX_CALL cti_op_lesseq(CTI_ARGS);
181 static int SFX_CALL cti_op_loop_if_true(CTI_ARGS);
182 static JSValue* SFX_CALL cti_op_resolve_base(CTI_ARGS);
183 static JSValue* SFX_CALL cti_op_negate(CTI_ARGS);
184 static JSValue* SFX_CALL cti_op_resolve_skip(CTI_ARGS);
185 static JSValue* SFX_CALL cti_op_div(CTI_ARGS);
186 static JSValue* SFX_CALL cti_op_pre_dec(CTI_ARGS);
187 static int SFX_CALL cti_op_jless(CTI_ARGS);
188 static JSValue* SFX_CALL cti_op_not(CTI_ARGS);
189 static int SFX_CALL cti_op_jtrue(CTI_ARGS);
190 static JSValue* SFX_CALL cti_op_post_inc(CTI_ARGS);
191 static JSValue* SFX_CALL cti_op_eq(CTI_ARGS);
192 static JSValue* SFX_CALL cti_op_lshift(CTI_ARGS);
193 static JSValue* SFX_CALL cti_op_bitand(CTI_ARGS);
194 static JSValue* SFX_CALL cti_op_rshift(CTI_ARGS);
195 static JSValue* SFX_CALL cti_op_bitnot(CTI_ARGS);
196 static JSValue* SFX_CALL cti_op_resolve_with_base(CTI_ARGS);
197 static JSValue* SFX_CALL cti_op_new_func_exp(CTI_ARGS);
198 static JSValue* SFX_CALL cti_op_mod(CTI_ARGS);
199 static JSValue* SFX_CALL cti_op_less(CTI_ARGS);
200 static JSValue* SFX_CALL cti_op_neq(CTI_ARGS);
201 static JSValue* SFX_CALL cti_op_post_dec(CTI_ARGS);
202 static JSValue* SFX_CALL cti_op_urshift(CTI_ARGS);
203 static JSValue* SFX_CALL cti_op_bitxor(CTI_ARGS);
204 static JSValue* SFX_CALL cti_op_new_regexp(CTI_ARGS);
205 static JSValue* SFX_CALL cti_op_bitor(CTI_ARGS);
206 static JSValue* SFX_CALL cti_op_call_eval(CTI_ARGS);
207 static void* SFX_CALL cti_op_throw(CTI_ARGS);
208 static JSPropertyNameIterator* SFX_CALL cti_op_get_pnames(CTI_ARGS);
209 static JSValue* SFX_CALL cti_op_next_pname(CTI_ARGS);
210 static void SFX_CALL cti_op_push_scope(CTI_ARGS);
211 static void SFX_CALL cti_op_pop_scope(CTI_ARGS);
212 static JSValue* SFX_CALL cti_op_typeof(CTI_ARGS);
213 static JSValue* SFX_CALL cti_op_is_undefined(CTI_ARGS);
214 static JSValue* SFX_CALL cti_op_is_boolean(CTI_ARGS);
215 static JSValue* SFX_CALL cti_op_is_number(CTI_ARGS);
216 static JSValue* SFX_CALL cti_op_is_string(CTI_ARGS);
217 static JSValue* SFX_CALL cti_op_is_object(CTI_ARGS);
218 static JSValue* SFX_CALL cti_op_is_function(CTI_ARGS);
219 static JSValue* SFX_CALL cti_op_stricteq(CTI_ARGS);
220 static JSValue* SFX_CALL cti_op_nstricteq(CTI_ARGS);
221 static JSValue* SFX_CALL cti_op_to_jsnumber(CTI_ARGS);
222 static JSValue* SFX_CALL cti_op_in(CTI_ARGS);
223 static JSValue* SFX_CALL cti_op_push_new_scope(CTI_ARGS);
224 static void SFX_CALL cti_op_jmp_scopes(CTI_ARGS);
225 static void SFX_CALL cti_op_put_by_index(CTI_ARGS);
226 static void* SFX_CALL cti_op_switch_imm(CTI_ARGS);
227 static void* SFX_CALL cti_op_switch_char(CTI_ARGS);
228 static void* SFX_CALL cti_op_switch_string(CTI_ARGS);
229 static JSValue* SFX_CALL cti_op_del_by_val(CTI_ARGS);
230 static void SFX_CALL cti_op_put_getter(CTI_ARGS);
231 static void SFX_CALL cti_op_put_setter(CTI_ARGS);
232 static JSValue* SFX_CALL cti_op_new_error(CTI_ARGS);
233 static void SFX_CALL cti_op_debug(CTI_ARGS);
234
235 static void* SFX_CALL cti_vm_throw(CTI_ARGS);
236 static void* SFX_CALL cti_vm_compile(CTI_ARGS);
237 static void SFX_CALL cti_op_push_activation(CTI_ARGS);
238
239#endif // ENABLE(CTI)
240
241 // Default number of ticks before a timeout check should be done.
242 static const int initialTickCountThreshold = 1024;
243
244 bool isJSArray(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsArrayVptr; }
245 bool isJSString(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringVptr; }
246
247 ALWAYS_INLINE static void initializeCallFrame(Register* callFrame, CodeBlock*, Instruction*, ScopeChainNode*, Register* r, int returnValueRegister, int argc, JSValue* function);
248
249 private:
250 enum ExecutionFlag { Normal, InitializeAndReturn };
251
252 NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile*, Register* r, int argv, int argc, JSValue*& exceptionValue);
253 JSValue* execute(EvalNode*, ExecState*, JSObject* thisObj, int registerOffset, ScopeChainNode*, JSValue** exception);
254
255 NEVER_INLINE void debug(ExecState*, Register*, DebugHookID, int firstLine, int lastLine);
256
257 NEVER_INLINE bool resolve(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
258 NEVER_INLINE bool resolveSkip(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
259 NEVER_INLINE bool resolveGlobal(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
260 NEVER_INLINE void resolveBase(ExecState* exec, Instruction* vPC, Register* r);
261 NEVER_INLINE bool resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
262 NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, const Instruction* vPC, Register* r);
263
264 NEVER_INLINE bool unwindCallFrame(ExecState*, JSValue*, const Instruction*&, CodeBlock*&, Register*&);
265 NEVER_INLINE Instruction* throwException(ExecState*, JSValue*&, const Instruction*, Register*&, bool);
266 NEVER_INLINE bool resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue);
267
268 Register* callFrame(ExecState*, InternalFunction*) const;
269
270 JSValue* privateExecute(ExecutionFlag, ExecState* = 0, RegisterFile* = 0, Register* = 0, JSValue** exception = 0);
271
272 void dumpCallFrame(const RegisterFile*, const Register*);
273 void dumpRegisters(const RegisterFile*, const Register*);
274
275 JSValue* checkTimeout(JSGlobalObject*);
276 void resetTimeoutCheck();
277
278 void tryCacheGetByID(ExecState*, CodeBlock*, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
279 void uncacheGetByID(CodeBlock*, Instruction* vPC);
280 void tryCachePutByID(ExecState* exec, CodeBlock*, Instruction* vPC, JSValue* baseValue, const PutPropertySlot&);
281 void uncachePutByID(CodeBlock*, Instruction* vPC);
282
283#if ENABLE(CTI)
284 void tryCTICacheGetByID(ExecState*, CodeBlock*, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
285 void tryCTICachePutByID(ExecState*, CodeBlock*, void* returnAddress, JSValue* baseValue, const PutPropertySlot&);
286
287 void* getCTIArrayLengthTrampoline(ExecState*, CodeBlock*);
288 void* getCTIStringLengthTrampoline(ExecState*, CodeBlock*);
289
290 void* m_ctiArrayLengthTrampoline;
291 void* m_ctiStringLengthTrampoline;
292
293 OwnPtr<JITCodeBuffer> m_jitCodeBuffer;
294 JITCodeBuffer* jitCodeBuffer() const { return m_jitCodeBuffer.get(); }
295#endif
296
297 int m_reentryDepth;
298 unsigned m_timeoutTime;
299 unsigned m_timeAtLastCheckTimeout;
300 unsigned m_timeExecuting;
301 unsigned m_timeoutCheckCount;
302 unsigned m_ticksUntilNextTimeoutCheck;
303
304 RegisterFile m_registerFile;
305
306 void* m_jsArrayVptr;
307 void* m_jsStringVptr;
308 void* m_jsFunctionVptr;
309
310#if HAVE(COMPUTED_GOTO)
311 Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
312 HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
313#endif
314 };
315
316 ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argc, JSValue* function)
317 {
318 ASSERT(r); // use makeHostCallFramePointer(0) to create a host call frame sentinel.
319 callFrame[RegisterFile::CodeBlock] = codeBlock;
320 callFrame[RegisterFile::ScopeChain] = scopeChain;
321 callFrame[RegisterFile::CallerRegisters] = r;
322 callFrame[RegisterFile::ReturnPC] = vPC;
323 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
324 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
325 callFrame[RegisterFile::Callee] = function;
326 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
327 callFrame[RegisterFile::OptionalCalleeArguments] = nullJSValue;
328 }
329
330 const intptr_t HostCallFrameMask = 1;
331
332 inline Register* makeHostCallFramePointer(Register* callFrame)
333 {
334 return reinterpret_cast<Register*>(reinterpret_cast<intptr_t>(callFrame) | HostCallFrameMask);
335 }
336
337 inline bool isHostCallFrame(Register* callFrame)
338 {
339 return reinterpret_cast<intptr_t>(callFrame) & HostCallFrameMask;
340 }
341
342 inline Register* stripHostCallFrameBit(Register* callFrame)
343 {
344 return reinterpret_cast<Register*>(reinterpret_cast<intptr_t>(callFrame) & ~HostCallFrameMask);
345 }
346
347} // namespace JSC
348
349#endif // Machine_h
Note: See TracBrowser for help on using the repository browser.