source: webkit/trunk/JavaScriptCore/VM/Machine.cpp@ 35830

Last change on this file since 35830 was 35830, checked in by Darin Adler, 17 years ago

JavaScriptCore:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • eliminate JSValue::type()

This will make it slightly easier to change the JSImmediate design without
having to touch so many call sites.

SunSpider says this change is a wash (looked like a slight speedup, but not
statistically significant).

  • API/JSStringRef.cpp: Removed include of JSType.h.
  • API/JSValueRef.cpp: Removed include of JSType.h. (JSValueGetType): Replaced use of JSValue::type() with JSValue::is functions.
  • VM/JSPropertyNameIterator.cpp: Removed type() implementation. (KJS::JSPropertyNameIterator::toPrimitive): Changed to take PreferredPrimitiveType argument instead of JSType.
  • VM/JSPropertyNameIterator.h: Ditto.
  • VM/Machine.cpp: (KJS::fastIsNumber): Updated for name change. (KJS::fastToInt32): Ditto. (KJS::fastToUInt32): Ditto. (KJS::jsAddSlowCase): Updated toPrimitive caller for change from JSType to PreferredPrimitiveType. (KJS::jsAdd): Replaced calls to JSValue::type() with calls to JSValue::isString(). (KJS::jsTypeStringForValue): Replaced calls to JSValue::type() with multiple calls to JSValue::is -- we could make this a virtual function instead if we want to have faster performance. (KJS::Machine::privateExecute): Renamed JSImmediate::toTruncatedUInt32 to JSImmediate::getTruncatedUInt32 for consistency with other functions. Changed two calls of JSValue::type() to JSValue::isString().
  • kjs/GetterSetter.cpp: (KJS::GetterSetter::toPrimitive): Changed to take PreferredPrimitiveType argument instead of JSType. (KJS::GetterSetter::isGetterSetter): Added.
  • kjs/GetterSetter.h:
  • kjs/JSCell.cpp: (KJS::JSCell::isString): Added. (KJS::JSCell::isGetterSetter): Added. (KJS::JSCell::isObject): Added.
  • kjs/JSCell.h: Eliminated type function. Added isGetterSetter. Made isString and isObject virtual. Changed toPrimitive to take PreferredPrimitiveType argument instead of JSType. (KJS::JSCell::isNumber): Use Heap::isNumber for faster performance. (KJS::JSValue::isGetterSetter): Added. (KJS::JSValue::toPrimitive): Changed to take PreferredPrimitiveType argument instead of JSType.
  • kjs/JSImmediate.h: Removed JSValue::type() and replaced JSValue::toTruncatedUInt32 with JSValue::getTruncatedUInt32. (KJS::JSImmediate::isEitherImmediate): Added.
  • kjs/JSNotAnObject.cpp: (KJS::JSNotAnObject::toPrimitive): Changed to take PreferredPrimitiveType argument instead of JSType.
  • kjs/JSNotAnObject.h: Ditto.
  • kjs/JSNumberCell.cpp: (KJS::JSNumberCell::toPrimitive): Ditto.
  • kjs/JSNumberCell.h: (KJS::JSNumberCell::toInt32): Renamed from fastToInt32. There's no other "slow" version of this once you have a JSNumberCell, so there's no need for "fast" in the name. It's a feature that this hides the base class toInt32, which does the same job less efficiently (and has an additional ExecState argument). (KJS::JSNumberCell::toUInt32): Ditto.
  • kjs/JSObject.cpp: (KJS::callDefaultValueFunction): Use isGetterSetter instead of type. (KJS::JSObject::getPrimitiveNumber): Use PreferredPrimitiveType. (KJS::JSObject::defaultValue): Ditto. (KJS::JSObject::defineGetter): Use isGetterSetter. (KJS::JSObject::defineSetter): Ditto. (KJS::JSObject::lookupGetter): Ditto. (KJS::JSObject::lookupSetter): Ditto. (KJS::JSObject::toNumber): Use PreferredPrimitiveType. (KJS::JSObject::toString): Ditto. (KJS::JSObject::isObject): Added.
  • kjs/JSObject.h: (KJS::JSObject::inherits): Call the isObject from JSCell; it's now hidden by our override of isObject. (KJS::JSObject::getOwnPropertySlotForWrite): Use isGetterSetter instead of type. (KJS::JSObject::getOwnPropertySlot): Ditto. (KJS::JSObject::toPrimitive): Use PreferredPrimitiveType.
  • kjs/JSString.cpp: (KJS::JSString::toPrimitive): Use PreferredPrimitiveType. (KJS::JSString::isString): Added.
  • kjs/JSString.h: Ditto.
  • kjs/JSValue.h: Removed type(), added isGetterSetter(). Added PreferredPrimitiveType enum and used it as the argument for the toPrimitive function. (KJS::JSValue::getBoolean): Simplified a bit an removed a branch.
  • kjs/collector.cpp: (KJS::typeName): Changed to use JSCell::is functions instead of calling JSCell::type.
  • kjs/collector.h: (KJS::Heap::isNumber): Renamed from fastIsNumber.
  • kjs/nodes.h: Added now-needed include of JSType, since the type is used here to record types of values in the tree.
  • kjs/operations.cpp: (KJS::equal): Rewrote to no longer depend on type(). (KJS::strictEqual): Ditto.

JavaScriptGlue:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • eliminate JSValue::type()
  • JSUtils.cpp: (KJSValueToCFTypeInternal): Replaced uses of JSValue::type() with JSValue::is functions.
  • UserObjectImp.cpp: (UserObjectImp::getOwnPropertySlot): Ditto. (UserObjectImp::toPrimitive): Take PreferredPrimitiveType argument instead of JSType argument.
  • UserObjectImp.h: Ditto.

WebCore:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • eliminate JSValue::type()
  • bridge/c/c_instance.cpp: (KJS::Bindings::CInstance::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument. Removed unneeded code to handle boolean, since that's never passed.
  • bridge/c/c_instance.h: Ditto.
  • bridge/c/c_utility.cpp: (KJS::Bindings::convertValueToNPVariant): Use JSValue::is functions instead of JSValue::type(). Removed unneeded code to handle "unspecified".
  • bridge/jni/jni_instance.cpp: (JavaInstance::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument. Removed unneeded code to handle boolean.
  • bridge/jni/jni_instance.h: Ditto.
  • bridge/jni/jni_jsobject.mm: (JavaJSObject::convertValueToJObject): Use JSValue::is functions instead of JSValue::type().
  • bridge/objc/objc_instance.h: Take PreferredPrimitiveType argument instead of JSType argument. Removed unused argument.
  • bridge/objc/objc_instance.mm: (ObjcInstance::getValueOfUndefinedField): Removed unused argument. (ObjcInstance::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument. Removed unneeded code to handle boolean and another dead code path for unknown types.
  • bridge/objc/objc_runtime.h: Take PreferredPrimitiveType argument instead of JSType argument. Removed override of type() that caused the fallback object to return "UndefinedType" when there is no invokeUndefinedMethodFromWebScript:withArguments: method defined. That didn't accomplish much, since most checks for undefined don't ever call type().
  • bridge/objc/objc_runtime.mm: (ObjcFallbackObjectImp::defaultValue): Ditto.
  • bridge/qt/qt_instance.cpp: (KJS::Bindings::QtInstance::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument. Removed unneeded code to handle boolean.
  • bridge/qt/qt_instance.h: Ditto.
  • bridge/runtime.h: (KJS::Bindings::Instance::getValueOfUndefinedField): Removed unsed argument.
  • bridge/runtime_object.cpp: (RuntimeObjectImp::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument.
  • bridge/runtime_object.h: Ditto.

WebKit/mac:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • eliminate JSValue::type()
  • WebView/WebView.mm: (aeDescFromJSValue): Rewrite to use the JSValue::is functions instead of a switch on JSValue::type().

LayoutTests:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • added a test since I had to rewrite the == and === operators
  • fast/js/equality-expected.txt: Added.
  • fast/js/equality.html: Added.
  • fast/js/resources/equality.js: Added.
File size: 106.7 KB
Line 
1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "Machine.h"
32
33#include "CodeBlock.h"
34#include "DebuggerCallFrame.h"
35#include "ExceptionHelpers.h"
36#include "ExecState.h"
37#include "GlobalEvalFunction.h"
38#include "JSActivation.h"
39#include "JSArray.h"
40#include "JSFunction.h"
41#include "JSNotAnObject.h"
42#include "JSPropertyNameIterator.h"
43#include "JSStaticScopeObject.h"
44#include "JSString.h"
45#include "ObjectPrototype.h"
46#include "Parser.h"
47#include "Profiler.h"
48#include "RegExpObject.h"
49#include "RegExpPrototype.h"
50#include "Register.h"
51#include "collector.h"
52#include "debugger.h"
53#include "operations.h"
54#include "SamplingTool.h"
55#include <stdio.h>
56
57#if HAVE(SYS_TIME_H)
58#include <sys/time.h>
59#endif
60
61#if PLATFORM(WIN_OS)
62#include <windows.h>
63#endif
64
65#if PLATFORM(QT)
66#include <QDateTime>
67#endif
68
69using namespace std;
70
71namespace KJS {
72
73// Default number of ticks before a timeout check should be done.
74static const int initialTickCountThreshold = 255;
75
76// Preferred number of milliseconds between each timeout check
77static const int preferredScriptCheckTimeInterval = 1000;
78
79#if HAVE(COMPUTED_GOTO)
80static void* op_throw_end_indirect;
81static void* op_call_indirect;
82#endif
83
84// Returns the depth of the scope chain within a given call frame.
85static int depth(CodeBlock* codeBlock, ScopeChain& sc)
86{
87 if (!codeBlock->needsFullScopeChain)
88 return 0;
89 int scopeDepth = 0;
90 ScopeChainIterator iter = sc.begin();
91 ScopeChainIterator end = sc.end();
92 while (!(*iter)->isActivationObject()) {
93 ++iter;
94 if (iter == end)
95 break;
96 ++scopeDepth;
97 }
98 return scopeDepth;
99}
100
101// FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
102// FIXME: There's no need to have a "slow" version of this. All versions should be fast.
103static bool fastIsNumber(JSValue* value, double& arg)
104{
105 if (JSImmediate::isNumber(value))
106 arg = JSImmediate::getTruncatedInt32(value);
107 else if (Heap::isNumber(static_cast<JSCell*>(value)))
108 arg = static_cast<JSNumberCell*>(value)->value();
109 else
110 return false;
111 return true;
112}
113
114// FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
115static bool fastToInt32(JSValue* value, int32_t& arg)
116{
117 if (JSImmediate::isNumber(value))
118 arg = JSImmediate::getTruncatedInt32(value);
119 else if (Heap::isNumber(static_cast<JSCell*>(value)))
120 arg = static_cast<JSNumberCell*>(value)->toInt32();
121 else
122 return false;
123 return true;
124}
125
126static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
127{
128 if (JSImmediate::isNumber(value)) {
129 if (JSImmediate::getTruncatedUInt32(value, arg))
130 return true;
131 bool scratch;
132 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
133 return true;
134 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
135 arg = static_cast<JSNumberCell*>(value)->toUInt32();
136 else
137 return false;
138 return true;
139}
140
141static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
142{
143 if (JSImmediate::areBothImmediateNumbers(v1, v2))
144 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
145
146 double n1;
147 double n2;
148 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
149 return n1 < n2;
150
151 JSValue* p1;
152 JSValue* p2;
153 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
154 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
155
156 if (wasNotString1 | wasNotString2)
157 return n1 < n2;
158
159 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
160}
161
162static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
163{
164 if (JSImmediate::areBothImmediateNumbers(v1, v2))
165 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
166
167 double n1;
168 double n2;
169 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
170 return n1 <= n2;
171
172 JSValue* p1;
173 JSValue* p2;
174 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
175 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
176
177 if (wasNotString1 | wasNotString2)
178 return n1 <= n2;
179
180 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
181}
182
183static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
184{
185 // exception for the Date exception in defaultValue()
186 JSValue* p1 = v1->toPrimitive(exec);
187 JSValue* p2 = v2->toPrimitive(exec);
188
189 if (p1->isString() || p2->isString()) {
190 UString value = p1->toString(exec) + p2->toString(exec);
191 if (value.isNull())
192 return throwOutOfMemoryError(exec);
193 return jsString(exec, value);
194 }
195
196 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
197}
198
199// Fast-path choices here are based on frequency data from SunSpider:
200// <times> Add case: <t1> <t2>
201// ---------------------------
202// 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
203// 247412 Add case: 5 5
204// 20900 Add case: 5 6
205// 13962 Add case: 5 3
206// 4000 Add case: 3 5
207
208static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
209{
210 double left;
211 double right;
212 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
213 return jsNumber(exec, left + right);
214
215 if (v1->isString() && v2->isString()) {
216 UString value = static_cast<JSString*>(v1)->value() + static_cast<JSString*>(v2)->value();
217 if (value.isNull())
218 return throwOutOfMemoryError(exec);
219 return jsString(exec, value);
220 }
221
222 // All other cases are pretty uncommon
223 return jsAddSlowCase(exec, v1, v2);
224}
225
226static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
227{
228 if (v->isUndefined())
229 return jsString(exec, "undefined");
230 if (v->isBoolean())
231 return jsString(exec, "boolean");
232 if (v->isNumber())
233 return jsString(exec, "number");
234 if (v->isString())
235 return jsString(exec, "string");
236 if (v->isObject()) {
237 // Return "undefined" for objects that should be treated
238 // as null when doing comparisons.
239 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
240 return jsString(exec, "undefined");
241 CallData callData;
242 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
243 return jsString(exec, "function");
244 }
245 return jsString(exec, "object");
246}
247
248static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
249{
250 int dst = (vPC + 1)->u.operand;
251 int property = (vPC + 2)->u.operand;
252
253 ScopeChainIterator iter = scopeChain->begin();
254 ScopeChainIterator end = scopeChain->end();
255 ASSERT(iter != end);
256
257 Identifier& ident = codeBlock->identifiers[property];
258 do {
259 JSObject* o = *iter;
260 PropertySlot slot(o);
261 if (o->getPropertySlot(exec, ident, slot)) {
262 JSValue* result = slot.getValue(exec, ident);
263 exceptionValue = exec->exception();
264 if (exceptionValue)
265 return false;
266 r[dst] = result;
267 return true;
268 }
269 } while (++iter != end);
270 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
271 return false;
272}
273
274static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
275{
276 int dst = (vPC + 1)->u.operand;
277 int property = (vPC + 2)->u.operand;
278 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
279
280 ScopeChainIterator iter = scopeChain->begin();
281 ScopeChainIterator end = scopeChain->end();
282 ASSERT(iter != end);
283 while (skip--) {
284 ++iter;
285 ASSERT(iter != end);
286 }
287 Identifier& ident = codeBlock->identifiers[property];
288 do {
289 JSObject* o = *iter;
290 PropertySlot slot(o);
291 if (o->getPropertySlot(exec, ident, slot)) {
292 JSValue* result = slot.getValue(exec, ident);
293 exceptionValue = exec->exception();
294 if (exceptionValue)
295 return false;
296 r[dst] = result;
297 return true;
298 }
299 } while (++iter != end);
300 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
301 return false;
302}
303
304static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
305{
306 int dst = (vPC + 1)->u.operand;
307 int property = (vPC + 2)->u.operand;
308
309 ScopeChainIterator iter = scopeChain->begin();
310 ScopeChainIterator next = iter;
311 ++next;
312 ScopeChainIterator end = scopeChain->end();
313 ASSERT(iter != end);
314
315 PropertySlot slot;
316 Identifier& ident = codeBlock->identifiers[property];
317 JSObject* base;
318 while (true) {
319 base = *iter;
320 if (next == end || base->getPropertySlot(exec, ident, slot)) {
321 r[dst] = base;
322 return;
323 }
324 iter = next;
325 ++next;
326 }
327}
328
329static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
330{
331 int baseDst = (vPC + 1)->u.operand;
332 int propDst = (vPC + 2)->u.operand;
333 int property = (vPC + 3)->u.operand;
334
335 ScopeChainIterator iter = scopeChain->begin();
336 ScopeChainIterator end = scopeChain->end();
337
338 // FIXME: add scopeDepthIsZero optimization
339
340 ASSERT(iter != end);
341
342 Identifier& ident = codeBlock->identifiers[property];
343 JSObject* base;
344 do {
345 base = *iter;
346 PropertySlot slot(base);
347 if (base->getPropertySlot(exec, ident, slot)) {
348 JSValue* result = slot.getValue(exec, ident);
349 exceptionValue = exec->exception();
350 if (exceptionValue)
351 return false;
352 r[propDst] = result;
353 r[baseDst] = base;
354 return true;
355 }
356 ++iter;
357 } while (iter != end);
358
359 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
360 return false;
361}
362
363static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
364{
365 int baseDst = (vPC + 1)->u.operand;
366 int funcDst = (vPC + 2)->u.operand;
367 int property = (vPC + 3)->u.operand;
368
369 ScopeChainIterator iter = scopeChain->begin();
370 ScopeChainIterator end = scopeChain->end();
371
372 // FIXME: add scopeDepthIsZero optimization
373
374 ASSERT(iter != end);
375
376 Identifier& ident = codeBlock->identifiers[property];
377 JSObject* base;
378 do {
379 base = *iter;
380 PropertySlot slot(base);
381 if (base->getPropertySlot(exec, ident, slot)) {
382 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
383 // However, section 10.2.3 says that in the case where the value provided
384 // by the caller is null, the global object should be used. It also says
385 // that the section does not apply to internal functions, but for simplicity
386 // of implementation we use the global object anyway here. This guarantees
387 // that in host objects you always get a valid object for this.
388 // We also handle wrapper substitution for the global object at the same time.
389 JSObject* thisObj = base->toThisObject(exec);
390 JSValue* result = slot.getValue(exec, ident);
391 exceptionValue = exec->exception();
392 if (exceptionValue)
393 return false;
394
395 r[baseDst] = thisObj;
396 r[funcDst] = result;
397 return true;
398 }
399 ++iter;
400 } while (iter != end);
401
402 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
403 return false;
404}
405
406ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
407{
408 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
409 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
410 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
411 callFrame[RegisterFile::CallerRegisters] = r;
412 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
413 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
414 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
415 callFrame[RegisterFile::CalledAsConstructor] = calledAsConstructor;
416 callFrame[RegisterFile::Callee] = function;
417 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
418}
419
420ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
421{
422 size_t registerOffset = argv + newCodeBlock->numLocals;
423 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
424
425 if (argc == newCodeBlock->numParameters) { // correct number of arguments
426 if (!registerFile->grow(size)) {
427 exceptionValue = createStackOverflowError(exec);
428 return r;
429 }
430 r += registerOffset;
431 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
432 if (!registerFile->grow(size)) {
433 exceptionValue = createStackOverflowError(exec);
434 return r;
435 }
436 r += registerOffset;
437
438 int omittedArgCount = newCodeBlock->numParameters - argc;
439 Register* endOfParams = r - newCodeBlock->numVars;
440 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
441 (*it) = jsUndefined();
442 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
443 int shift = argc + RegisterFile::CallFrameHeaderSize;
444 registerOffset += shift;
445 size += shift;
446
447 if (!registerFile->grow(size)) {
448 exceptionValue = createStackOverflowError(exec);
449 return r;
450 }
451 r += registerOffset;
452
453 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
454 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
455 for ( ; it != end; ++it)
456 *(it + shift) = *it;
457 }
458
459 // initialize local variable slots
460 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
461 (*it) = jsUndefined();
462
463
464 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
465 r[i] = newCodeBlock->constantRegisters[i];
466
467 return r;
468}
469
470ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
471{
472 if (newCodeBlock->needsFullScopeChain) {
473 JSActivation* activation = new (exec) JSActivation(functionBodyNode, r);
474 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
475
476 return callDataScopeChain->copy()->push(activation);
477 }
478
479 return callDataScopeChain;
480}
481
482static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
483{
484 if (value->isObject())
485 return false;
486 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
487 return true;
488}
489
490NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
491{
492 if (argc < 2)
493 return jsUndefined();
494
495 JSValue* program = r[argv + 1].jsValue(exec);
496
497 if (!program->isString())
498 return program;
499
500 Profiler** profiler = Profiler::enabledProfilerReference();
501 if (*profiler)
502 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
503
504 int sourceId;
505 int errLine;
506 UString errMsg;
507 RefPtr<EvalNode> evalNode = exec->parser()->parse<EvalNode>(exec, UString(), 1, UStringSourceProvider::create(static_cast<JSString*>(program)->value()), &sourceId, &errLine, &errMsg);
508
509 if (!evalNode) {
510 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
511 if (*profiler)
512 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
513 return 0;
514 }
515
516 JSValue* result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
517
518 if (*profiler)
519 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
520
521 return result;
522}
523
524Machine::Machine()
525 : m_sampler(0)
526 , m_reentryDepth(0)
527 , m_timeoutTime(0)
528 , m_timeAtLastCheckTimeout(0)
529 , m_timeExecuting(0)
530 , m_timeoutCheckCount(0)
531 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
532{
533 privateExecute(InitializeAndReturn);
534
535 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
536 void* storage = fastMalloc(sizeof(CollectorBlock));
537
538 JSArray* jsArray = new (storage) JSArray(jsNull(), 0);
539 m_jsArrayVptr = jsArray->vptr();
540 static_cast<JSCell*>(jsArray)->~JSCell();
541
542 JSString* jsString = new (storage) JSString("");
543 m_jsStringVptr = jsString->vptr();
544 static_cast<JSCell*>(jsString)->~JSCell();
545
546 fastFree(storage);
547}
548
549#ifndef NDEBUG
550
551void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
552{
553 ScopeChain sc(scopeChain);
554 JSGlobalObject* globalObject = sc.globalObject();
555 codeBlock->dump(globalObject->globalExec());
556 dumpRegisters(codeBlock, registerFile, r);
557}
558
559void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
560{
561 printf("Register frame: \n\n");
562 printf("----------------------------------------------------\n");
563 printf(" use | address | value \n");
564 printf("----------------------------------------------------\n");
565
566 const Register* it;
567 const Register* end;
568
569 if (codeBlock->codeType == GlobalCode) {
570 it = registerFile->lastGlobal();
571 end = it + registerFile->numGlobals();
572 while (it != end) {
573 printf("[global var] | %10p | %10p \n", it, (*it).v());
574 ++it;
575 }
576 printf("----------------------------------------------------\n");
577 }
578
579 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
580 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
581 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
582 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
583 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
584 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
585 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
586 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
587 printf("[CalledAsConstructor] | %10p | %10p \n", it, (*it).v()); ++it;
588 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
589 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
590 printf("----------------------------------------------------\n");
591
592 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
593 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
594 if (it != end) {
595 do {
596 printf("[param] | %10p | %10p \n", it, (*it).v());
597 ++it;
598 } while (it != end);
599 }
600 printf("----------------------------------------------------\n");
601
602 if (codeBlock->codeType != GlobalCode) {
603 end = it + codeBlock->numVars;
604 if (it != end) {
605 do {
606 printf("[var] | %10p | %10p \n", it, (*it).v());
607 ++it;
608 } while (it != end);
609 printf("----------------------------------------------------\n");
610 }
611 }
612
613 end = it + codeBlock->numTemporaries;
614 if (it != end) {
615 do {
616 printf("[temp] | %10p | %10p \n", it, (*it).v());
617 ++it;
618 } while (it != end);
619 }
620}
621
622#endif
623
624#if !defined(NDEBUG) || HAVE(SAMPLING_TOOL)
625
626bool Machine::isOpcode(Opcode opcode)
627{
628#if HAVE(COMPUTED_GOTO)
629 return opcode != HashTraits<Opcode>::emptyValue()
630 && !HashTraits<Opcode>::isDeletedValue(opcode)
631 && m_opcodeIDTable.contains(opcode);
632#else
633 return opcode >= 0 && opcode <= op_end;
634#endif
635}
636
637#endif
638
639NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
640{
641 CodeBlock* oldCodeBlock = codeBlock;
642 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
643
644 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
645 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
646 if (callFrame[RegisterFile::Callee].jsValue(exec))
647 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
648 else
649 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
650 }
651
652 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
653 if (callFrame[RegisterFile::Callee].jsValue(exec))
654 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
655 else
656 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
657 }
658
659 if (oldCodeBlock->needsFullScopeChain)
660 scopeChain->deref();
661
662 // If this call frame created an activation, tear it off.
663 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
664 ASSERT(activation->isActivationObject());
665 activation->copyRegisters();
666 }
667
668 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
669 if (!codeBlock)
670 return false;
671
672 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
673 r = callFrame[RegisterFile::CallerRegisters].r();
674 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
675 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
676
677 return true;
678}
679
680NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
681{
682 // Set up the exception object
683
684 if (exceptionValue->isObject()) {
685 JSObject* exception = static_cast<JSObject*>(exceptionValue);
686 if (exception->isNotAnObjectErrorStub()) {
687 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
688 exceptionValue = exception;
689 } else {
690 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
691 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
692 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
693 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
694 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
695 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
696 if (explicitThrow) {
697 int startOffset = 0;
698 int endOffset = 0;
699 int divotPoint = 0;
700 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
701 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
702
703 // We only hit this path for error messages and throw statements, which don't have a specific failure position
704 // So we just give the full range of the error/throw statement.
705 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
706 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
707 } else
708 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
709 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
710 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
711 }
712
713 if (exception->isWatchdogException()) {
714 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
715 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
716 }
717 return 0;
718 }
719 }
720 }
721
722 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
723 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
724 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
725 }
726
727 // Calculate an exception handler vPC, unwinding call frames as necessary.
728
729 int scopeDepth;
730 Instruction* handlerVPC;
731
732 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
733 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
734 return 0;
735 }
736
737 // Now unwind the scope chain within the exception handler's call frame.
738
739 ScopeChain sc(scopeChain);
740 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
741 ASSERT(scopeDelta >= 0);
742 while (scopeDelta--)
743 sc.pop();
744 setScopeChain(exec, scopeChain, sc.node());
745
746 return handlerVPC;
747}
748
749JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
750{
751 if (m_reentryDepth >= MaxReentryDepth) {
752 *exception = createStackOverflowError(exec);
753 return 0;
754 }
755
756 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
757
758 size_t oldSize = m_registerFile.size();
759 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
760 if (!m_registerFile.grow(newSize)) {
761 *exception = createStackOverflowError(exec);
762 return 0;
763 }
764
765 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
766 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
767 globalObject->copyGlobalsTo(m_registerFile);
768
769 Register* callFrame = m_registerFile.base() + oldSize;
770
771 // a 0 codeBlock indicates a built-in caller
772 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
773
774 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
775 r[codeBlock->thisRegister] = thisObj;
776
777 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
778 r[i] = codeBlock->constantRegisters[i];
779
780 if (codeBlock->needsFullScopeChain)
781 scopeChain = scopeChain->copy();
782
783 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
784
785 Profiler** profiler = Profiler::enabledProfilerReference();
786 if (*profiler)
787 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
788
789 m_reentryDepth++;
790 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
791 m_reentryDepth--;
792
793 MACHINE_SAMPLING_privateExecuteReturned();
794
795 if (*profiler) {
796 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
797 if (!m_reentryDepth)
798 (*profiler)->didFinishAllExecution(exec);
799 }
800
801 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
802 lastGlobalObject->copyGlobalsTo(m_registerFile);
803
804 m_registerFile.shrink(oldSize);
805 return result;
806}
807
808JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
809{
810 if (m_reentryDepth >= MaxReentryDepth) {
811 *exception = createStackOverflowError(exec);
812 return 0;
813 }
814
815 int argv = RegisterFile::CallFrameHeaderSize;
816 int argc = args.size() + 1; // implicit "this" parameter
817
818 size_t oldSize = m_registerFile.size();
819 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
820 *exception = createStackOverflowError(exec);
821 return 0;
822 }
823
824 Register* callFrame = m_registerFile.base() + oldSize;
825
826 // put args in place, including "this"
827 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
828 (*dst) = thisObj;
829
830 ArgList::const_iterator end = args.end();
831 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
832 (*++dst) = *it;
833
834 // a 0 codeBlock indicates a built-in caller
835 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, 0, function);
836
837 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
838 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
839 if (*exception) {
840 m_registerFile.shrink(oldSize);
841 return 0;
842 }
843
844 scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r);
845
846 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
847
848 Profiler** profiler = Profiler::enabledProfilerReference();
849 if (*profiler)
850 (*profiler)->willExecute(exec, function);
851
852 m_reentryDepth++;
853 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
854 m_reentryDepth--;
855
856 MACHINE_SAMPLING_privateExecuteReturned();
857
858 if (*profiler && !m_reentryDepth)
859 (*profiler)->didFinishAllExecution(exec);
860
861 m_registerFile.shrink(oldSize);
862 return result;
863}
864
865JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
866{
867 if (m_reentryDepth >= MaxReentryDepth) {
868 *exception = createStackOverflowError(exec);
869 return 0;
870 }
871
872 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
873
874 JSVariableObject* variableObject;
875 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
876 ASSERT(node);
877 if (node->object->isVariableObject()) {
878 variableObject = static_cast<JSVariableObject*>(node->object);
879 break;
880 }
881 }
882
883 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
884 Node::VarStack::const_iterator varStackEnd = varStack.end();
885 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
886 const Identifier& ident = (*it).first;
887 if (!variableObject->hasProperty(exec, ident))
888 variableObject->put(exec, ident, jsUndefined());
889 }
890
891 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
892 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
893 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it)
894 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain));
895
896 size_t oldSize = m_registerFile.size();
897 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
898 if (!m_registerFile.grow(newSize)) {
899 *exception = createStackOverflowError(exec);
900 return 0;
901 }
902
903 Register* callFrame = m_registerFile.base() + registerOffset;
904
905 // a 0 codeBlock indicates a built-in caller
906 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
907
908 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
909 r[codeBlock->thisRegister] = thisObj;
910
911 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
912 r[i] = codeBlock->constantRegisters[i];
913
914 if (codeBlock->needsFullScopeChain)
915 scopeChain = scopeChain->copy();
916
917 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
918
919 Profiler** profiler = Profiler::enabledProfilerReference();
920 if (*profiler)
921 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
922
923 m_reentryDepth++;
924 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
925 m_reentryDepth--;
926
927 MACHINE_SAMPLING_privateExecuteReturned();
928
929 if (*profiler) {
930 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
931 if (!m_reentryDepth)
932 (*profiler)->didFinishAllExecution(exec);
933 }
934
935 m_registerFile.shrink(oldSize);
936 return result;
937}
938
939ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
940{
941 scopeChain = newScopeChain;
942 exec->m_scopeChain = newScopeChain;
943}
944
945NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r)
946{
947 int debugHookID = (++vPC)->u.operand;
948 int firstLine = (++vPC)->u.operand;
949 int lastLine = (++vPC)->u.operand;
950
951 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
952 if (!debugger)
953 return;
954
955 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
956
957 switch((DebugHookID)debugHookID) {
958 case DidEnterCallFrame: {
959 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
960 return;
961 }
962 case WillLeaveCallFrame: {
963 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
964 return;
965 }
966 case WillExecuteStatement: {
967 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
968 return;
969 }
970 case WillExecuteProgram: {
971 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
972 return;
973 }
974 case DidExecuteProgram: {
975 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
976 return;
977 }
978 case DidReachBreakpoint: {
979 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
980 return;
981 }
982 }
983}
984
985void Machine::resetTimeoutCheck()
986{
987 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
988 m_timeAtLastCheckTimeout = 0;
989 m_timeExecuting = 0;
990}
991
992// Returns the current time in milliseconds
993// It doesn't matter what "current time" is here, just as long as
994// it's possible to measure the time difference correctly.
995// In an ideal world this would just be getCurrentUTCTimeWithMicroseconds
996// from DateMath.h, but unfortunately there's a slowdown if we use tha.
997static inline unsigned getCurrentTime()
998{
999#if HAVE(SYS_TIME_H)
1000 struct timeval tv;
1001 gettimeofday(&tv, 0);
1002 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1003#elif PLATFORM(QT)
1004 QDateTime t = QDateTime::currentDateTime();
1005 return t.toTime_t() * 1000 + t.time().msec();
1006#elif PLATFORM(WIN_OS)
1007 return timeGetTime();
1008#else
1009#error Platform does not have getCurrentTime function
1010#endif
1011}
1012
1013// We have to return a JSValue here, gcc seems to produce worse code if
1014// we attempt to return a bool
1015ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1016{
1017 unsigned currentTime = getCurrentTime();
1018
1019 if (!m_timeAtLastCheckTimeout) {
1020 // Suspicious amount of looping in a script -- start timing it
1021 m_timeAtLastCheckTimeout = currentTime;
1022 return 0;
1023 }
1024
1025 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1026
1027 if (timeDiff == 0)
1028 timeDiff = 1;
1029
1030 m_timeExecuting += timeDiff;
1031 m_timeAtLastCheckTimeout = currentTime;
1032
1033 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1034 // preferredScriptCheckTimeInterval
1035 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1036 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1037 // preferred script check time interval.
1038 if (m_ticksUntilNextTimeoutCheck == 0)
1039 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1040
1041 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1042 if (globalObject->shouldInterruptScript())
1043 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1044
1045 resetTimeoutCheck();
1046 }
1047
1048 return 0;
1049}
1050
1051static int32_t offsetForStringSwitch(StringJumpTable& jumpTable, JSValue* scrutinee, int32_t defaultOffset) {
1052 StringJumpTable::const_iterator end = jumpTable.end();
1053 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
1054 StringJumpTable::const_iterator loc = jumpTable.find(value);
1055 if (loc == end)
1056 return defaultOffset;
1057 return loc->second;
1058}
1059
1060static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1061{
1062 int dst = (++vPC)->u.operand;
1063 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1064 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1065 JSObject* scope = new (exec) JSStaticScopeObject(property, value, DontDelete);
1066 r[dst] = scope;
1067 return scopeChain->push(scope);
1068}
1069
1070JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1071{
1072 // One-time initialization of our address tables. We have to put this code
1073 // here because our labels are only in scope inside this function.
1074 if (flag == InitializeAndReturn) {
1075 #if HAVE(COMPUTED_GOTO)
1076 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1077 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1078 #undef ADD_OPCODE
1079
1080 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1081 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1082 #undef ADD_OPCODE_ID
1083 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1084 op_throw_end_indirect = &&op_throw_end;
1085 op_call_indirect = &&op_call;
1086 #endif // HAVE(COMPUTED_GOTO)
1087 return 0;
1088 }
1089
1090 JSValue* exceptionValue = 0;
1091 Instruction* handlerVPC = 0;
1092
1093 Register* registerBase = registerFile->base();
1094 Instruction* vPC = codeBlock->instructions.begin();
1095 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1096 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1097
1098#define VM_CHECK_EXCEPTION() \
1099 do { \
1100 if (UNLIKELY(exec->hadException())) { \
1101 exceptionValue = exec->exception(); \
1102 goto vm_throw; \
1103 } \
1104 } while (0)
1105
1106#if DUMP_OPCODE_STATS
1107 OpcodeStats::resetLastInstruction();
1108#endif
1109
1110#define CHECK_FOR_TIMEOUT() \
1111 if (!--tickCount) { \
1112 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1113 goto vm_throw; \
1114 tickCount = m_ticksUntilNextTimeoutCheck; \
1115 }
1116
1117#if HAVE(COMPUTED_GOTO)
1118 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1119#if DUMP_OPCODE_STATS
1120 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1121#else
1122 #define BEGIN_OPCODE(opcode) opcode:
1123#endif
1124 NEXT_OPCODE;
1125#else
1126 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1127#if DUMP_OPCODE_STATS
1128 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1129#else
1130 #define BEGIN_OPCODE(opcode) case opcode:
1131#endif
1132 while (1) // iterator loop begins
1133 switch (vPC->u.opcode)
1134#endif
1135 {
1136 BEGIN_OPCODE(op_new_object) {
1137 /* new_object dst(r)
1138
1139 Constructs a new empty Object instance using the original
1140 constructor, and puts the result in register dst.
1141 */
1142 int dst = (++vPC)->u.operand;
1143 r[dst] = constructEmptyObject(exec);
1144
1145 ++vPC;
1146 NEXT_OPCODE;
1147 }
1148 BEGIN_OPCODE(op_new_array) {
1149 /* new_array dst(r) firstArg(r) argCount(n)
1150
1151 Constructs a new Array instance using the original
1152 constructor, and puts the result in register dst.
1153 The array will contain argCount elements with values
1154 taken from registers starting at register firstArg.
1155 */
1156 int dst = (++vPC)->u.operand;
1157 int firstArg = (++vPC)->u.operand;
1158 int argCount = (++vPC)->u.operand;
1159 ArgList args(r + firstArg, argCount);
1160 r[dst] = constructArray(exec, args);
1161
1162 ++vPC;
1163 NEXT_OPCODE;
1164 }
1165 BEGIN_OPCODE(op_new_regexp) {
1166 /* new_regexp dst(r) regExp(re)
1167
1168 Constructs a new RegExp instance using the original
1169 constructor from regexp regExp, and puts the result in
1170 register dst.
1171 */
1172 int dst = (++vPC)->u.operand;
1173 int regExp = (++vPC)->u.operand;
1174 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1175
1176 ++vPC;
1177 NEXT_OPCODE;
1178 }
1179 BEGIN_OPCODE(op_mov) {
1180 /* mov dst(r) src(r)
1181
1182 Copies register src to register dst.
1183 */
1184 int dst = (++vPC)->u.operand;
1185 int src = (++vPC)->u.operand;
1186 r[dst] = r[src];
1187
1188 ++vPC;
1189 NEXT_OPCODE;
1190 }
1191 BEGIN_OPCODE(op_eq) {
1192 /* eq dst(r) src1(r) src2(r)
1193
1194 Checks whether register src1 and register src2 are equal,
1195 as with the ECMAScript '==' operator, and puts the result
1196 as a boolean in register dst.
1197 */
1198 int dst = (++vPC)->u.operand;
1199 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1200 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1201 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1202 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1203 else {
1204 JSValue* result = jsBoolean(equal(exec, src1, src2));
1205 VM_CHECK_EXCEPTION();
1206 r[dst] = result;
1207 }
1208
1209 ++vPC;
1210 NEXT_OPCODE;
1211 }
1212 BEGIN_OPCODE(op_neq) {
1213 /* neq dst(r) src1(r) src2(r)
1214
1215 Checks whether register src1 and register src2 are not
1216 equal, as with the ECMAScript '!=' operator, and puts the
1217 result as a boolean in register dst.
1218 */
1219 int dst = (++vPC)->u.operand;
1220 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1221 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1222 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1223 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1224 else {
1225 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1226 VM_CHECK_EXCEPTION();
1227 r[dst] = result;
1228 }
1229
1230 ++vPC;
1231 NEXT_OPCODE;
1232 }
1233 BEGIN_OPCODE(op_stricteq) {
1234 /* stricteq dst(r) src1(r) src2(r)
1235
1236 Checks whether register src1 and register src2 are strictly
1237 equal, as with the ECMAScript '===' operator, and puts the
1238 result as a boolean in register dst.
1239 */
1240 int dst = (++vPC)->u.operand;
1241 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1242 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1243 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1244 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1245 else
1246 r[dst] = jsBoolean(strictEqual(src1, src2));
1247
1248 ++vPC;
1249 NEXT_OPCODE;
1250 }
1251 BEGIN_OPCODE(op_nstricteq) {
1252 /* nstricteq dst(r) src1(r) src2(r)
1253
1254 Checks whether register src1 and register src2 are not
1255 strictly equal, as with the ECMAScript '!==' operator, and
1256 puts the result as a boolean in register dst.
1257 */
1258 int dst = (++vPC)->u.operand;
1259 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1260 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1261 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1262 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1263 else
1264 r[dst] = jsBoolean(!strictEqual(src1, src2));
1265
1266 ++vPC;
1267 NEXT_OPCODE;
1268 }
1269 BEGIN_OPCODE(op_less) {
1270 /* less dst(r) src1(r) src2(r)
1271
1272 Checks whether register src1 is less than register src2, as
1273 with the ECMAScript '<' operator, and puts the result as
1274 a boolean in register dst.
1275 */
1276 int dst = (++vPC)->u.operand;
1277 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1278 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1279 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1280 VM_CHECK_EXCEPTION();
1281 r[dst] = result;
1282
1283 ++vPC;
1284 NEXT_OPCODE;
1285 }
1286 BEGIN_OPCODE(op_lesseq) {
1287 /* lesseq dst(r) src1(r) src2(r)
1288
1289 Checks whether register src1 is less than or equal to
1290 register src2, as with the ECMAScript '<=' operator, and
1291 puts the result as a boolean in register dst.
1292 */
1293 int dst = (++vPC)->u.operand;
1294 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1295 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1296 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1297 VM_CHECK_EXCEPTION();
1298 r[dst] = result;
1299
1300 ++vPC;
1301 NEXT_OPCODE;
1302 }
1303 BEGIN_OPCODE(op_pre_inc) {
1304 /* pre_inc srcDst(r)
1305
1306 Converts register srcDst to number, adds one, and puts the result
1307 back in register srcDst.
1308 */
1309 int srcDst = (++vPC)->u.operand;
1310 JSValue* v = r[srcDst].jsValue(exec);
1311 if (JSImmediate::canDoFastAdditiveOperations(v))
1312 r[srcDst] = JSImmediate::incImmediateNumber(v);
1313 else {
1314 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1315 VM_CHECK_EXCEPTION();
1316 r[srcDst] = result;
1317 }
1318
1319 ++vPC;
1320 NEXT_OPCODE;
1321 }
1322 BEGIN_OPCODE(op_pre_dec) {
1323 /* pre_dec srcDst(r)
1324
1325 Converts register srcDst to number, subtracts one, and puts the result
1326 back in register srcDst.
1327 */
1328 int srcDst = (++vPC)->u.operand;
1329 JSValue* v = r[srcDst].jsValue(exec);
1330 if (JSImmediate::canDoFastAdditiveOperations(v))
1331 r[srcDst] = JSImmediate::decImmediateNumber(v);
1332 else {
1333 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1334 VM_CHECK_EXCEPTION();
1335 r[srcDst] = result;
1336 }
1337
1338 ++vPC;
1339 NEXT_OPCODE;
1340 }
1341 BEGIN_OPCODE(op_post_inc) {
1342 /* post_inc dst(r) srcDst(r)
1343
1344 Converts register srcDst to number. The number itself is
1345 written to register dst, and the number plus one is written
1346 back to register srcDst.
1347 */
1348 int dst = (++vPC)->u.operand;
1349 int srcDst = (++vPC)->u.operand;
1350 JSValue* v = r[srcDst].jsValue(exec);
1351 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1352 r[dst] = v;
1353 r[srcDst] = JSImmediate::incImmediateNumber(v);
1354 } else {
1355 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1356 VM_CHECK_EXCEPTION();
1357 r[dst] = number;
1358 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1359 }
1360
1361 ++vPC;
1362 NEXT_OPCODE;
1363 }
1364 BEGIN_OPCODE(op_post_dec) {
1365 /* post_dec dst(r) srcDst(r)
1366
1367 Converts register srcDst to number. The number itself is
1368 written to register dst, and the number minus one is written
1369 back to register srcDst.
1370 */
1371 int dst = (++vPC)->u.operand;
1372 int srcDst = (++vPC)->u.operand;
1373 JSValue* v = r[srcDst].jsValue(exec);
1374 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1375 r[dst] = v;
1376 r[srcDst] = JSImmediate::decImmediateNumber(v);
1377 } else {
1378 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1379 VM_CHECK_EXCEPTION();
1380 r[dst] = number;
1381 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1382 }
1383
1384 ++vPC;
1385 NEXT_OPCODE;
1386 }
1387 BEGIN_OPCODE(op_to_jsnumber) {
1388 /* to_jsnumber dst(r) src(r)
1389
1390 Converts register src to number, and puts the result
1391 in register dst.
1392 */
1393 int dst = (++vPC)->u.operand;
1394 int src = (++vPC)->u.operand;
1395 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1396 VM_CHECK_EXCEPTION();
1397
1398 r[dst] = result;
1399
1400 ++vPC;
1401 NEXT_OPCODE;
1402 }
1403 BEGIN_OPCODE(op_negate) {
1404 /* negate dst(r) src(r)
1405
1406 Converts register src to number, negates it, and puts the
1407 result in register dst.
1408 */
1409 int dst = (++vPC)->u.operand;
1410 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1411 double v;
1412 if (fastIsNumber(src, v))
1413 r[dst] = jsNumber(exec, -v);
1414 else {
1415 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1416 VM_CHECK_EXCEPTION();
1417 r[dst] = result;
1418 }
1419
1420 ++vPC;
1421 NEXT_OPCODE;
1422 }
1423 BEGIN_OPCODE(op_add) {
1424 /* add dst(r) src1(r) src2(r)
1425
1426 Adds register src1 and register src2, and puts the result
1427 in register dst. (JS add may be string concatenation or
1428 numeric add, depending on the types of the operands.)
1429 */
1430 int dst = (++vPC)->u.operand;
1431 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1432 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1433 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1434 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1435 else {
1436 JSValue* result = jsAdd(exec, src1, src2);
1437 VM_CHECK_EXCEPTION();
1438 r[dst] = result;
1439 }
1440 ++vPC;
1441 NEXT_OPCODE;
1442 }
1443 BEGIN_OPCODE(op_mul) {
1444 /* mul dst(r) src1(r) src2(r)
1445
1446 Multiplies register src1 and register src2 (converted to
1447 numbers), and puts the product in register dst.
1448 */
1449 int dst = (++vPC)->u.operand;
1450 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1451 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1452 double left;
1453 double right;
1454 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1455 r[dst] = jsNumber(exec, left * right);
1456 else {
1457 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1458 VM_CHECK_EXCEPTION();
1459 r[dst] = result;
1460 }
1461
1462 ++vPC;
1463 NEXT_OPCODE;
1464 }
1465 BEGIN_OPCODE(op_div) {
1466 /* div dst(r) dividend(r) divisor(r)
1467
1468 Divides register dividend (converted to number) by the
1469 register divisor (converted to number), and puts the
1470 quotient in register dst.
1471 */
1472 int dst = (++vPC)->u.operand;
1473 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1474 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1475 double left;
1476 double right;
1477 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1478 r[dst] = jsNumber(exec, left / right);
1479 else {
1480 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1481 VM_CHECK_EXCEPTION();
1482 r[dst] = result;
1483 }
1484 ++vPC;
1485 NEXT_OPCODE;
1486 }
1487 BEGIN_OPCODE(op_mod) {
1488 /* mod dst(r) dividend(r) divisor(r)
1489
1490 Divides register dividend (converted to number) by
1491 register divisor (converted to number), and puts the
1492 remainder in register dst.
1493 */
1494 int dst = (++vPC)->u.operand;
1495 int dividend = (++vPC)->u.operand;
1496 int divisor = (++vPC)->u.operand;
1497
1498 JSValue* dividendValue = r[dividend].jsValue(exec);
1499 JSValue* divisorValue = r[divisor].jsValue(exec);
1500
1501 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1502 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1503 ++vPC;
1504 NEXT_OPCODE;
1505 }
1506
1507 double d = dividendValue->toNumber(exec);
1508 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1509 VM_CHECK_EXCEPTION();
1510 r[dst] = result;
1511 ++vPC;
1512 NEXT_OPCODE;
1513 }
1514 BEGIN_OPCODE(op_sub) {
1515 /* sub dst(r) src1(r) src2(r)
1516
1517 Subtracts register src2 (converted to number) from register
1518 src1 (converted to number), and puts the difference in
1519 register dst.
1520 */
1521 int dst = (++vPC)->u.operand;
1522 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1523 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1524 double left;
1525 double right;
1526 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1527 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1528 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1529 r[dst] = jsNumber(exec, left - right);
1530 else {
1531 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1532 VM_CHECK_EXCEPTION();
1533 r[dst] = result;
1534 }
1535 ++vPC;
1536 NEXT_OPCODE;
1537 }
1538 BEGIN_OPCODE(op_lshift) {
1539 /* lshift dst(r) val(r) shift(r)
1540
1541 Performs left shift of register val (converted to int32) by
1542 register shift (converted to uint32), and puts the result
1543 in register dst.
1544 */
1545 int dst = (++vPC)->u.operand;
1546 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1547 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1548 int32_t left;
1549 uint32_t right;
1550 if (JSImmediate::areBothImmediateNumbers(val, shift))
1551 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1552 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1553 r[dst] = jsNumber(exec, left << (right & 0x1f));
1554 else {
1555 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1556 VM_CHECK_EXCEPTION();
1557 r[dst] = result;
1558 }
1559
1560 ++vPC;
1561 NEXT_OPCODE;
1562 }
1563 BEGIN_OPCODE(op_rshift) {
1564 /* rshift dst(r) val(r) shift(r)
1565
1566 Performs arithmetic right shift of register val (converted
1567 to int32) by register shift (converted to
1568 uint32), and puts the result in register dst.
1569 */
1570 int dst = (++vPC)->u.operand;
1571 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1572 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1573 int32_t left;
1574 uint32_t right;
1575 if (JSImmediate::areBothImmediateNumbers(val, shift))
1576 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1577 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1578 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1579 else {
1580 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1581 VM_CHECK_EXCEPTION();
1582 r[dst] = result;
1583 }
1584
1585 ++vPC;
1586 NEXT_OPCODE;
1587 }
1588 BEGIN_OPCODE(op_urshift) {
1589 /* rshift dst(r) val(r) shift(r)
1590
1591 Performs logical right shift of register val (converted
1592 to uint32) by register shift (converted to
1593 uint32), and puts the result in register dst.
1594 */
1595 int dst = (++vPC)->u.operand;
1596 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1597 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1598 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1599 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1600 else {
1601 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1602 VM_CHECK_EXCEPTION();
1603 r[dst] = result;
1604 }
1605
1606 ++vPC;
1607 NEXT_OPCODE;
1608 }
1609 BEGIN_OPCODE(op_bitand) {
1610 /* bitand dst(r) src1(r) src2(r)
1611
1612 Computes bitwise AND of register src1 (converted to int32)
1613 and register src2 (converted to int32), and puts the result
1614 in register dst.
1615 */
1616 int dst = (++vPC)->u.operand;
1617 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1618 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1619 int32_t left;
1620 int32_t right;
1621 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1622 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1623 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1624 r[dst] = jsNumber(exec, left & right);
1625 else {
1626 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
1627 VM_CHECK_EXCEPTION();
1628 r[dst] = result;
1629 }
1630
1631 ++vPC;
1632 NEXT_OPCODE;
1633 }
1634 BEGIN_OPCODE(op_bitxor) {
1635 /* bitxor dst(r) src1(r) src2(r)
1636
1637 Computes bitwise XOR of register src1 (converted to int32)
1638 and register src2 (converted to int32), and puts the result
1639 in register dst.
1640 */
1641 int dst = (++vPC)->u.operand;
1642 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1643 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1644 int32_t left;
1645 int32_t right;
1646 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1647 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
1648 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1649 r[dst] = jsNumber(exec, left ^ right);
1650 else {
1651 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
1652 VM_CHECK_EXCEPTION();
1653 r[dst] = result;
1654 }
1655
1656 ++vPC;
1657 NEXT_OPCODE;
1658 }
1659 BEGIN_OPCODE(op_bitor) {
1660 /* bitor dst(r) src1(r) src2(r)
1661
1662 Computes bitwise OR of register src1 (converted to int32)
1663 and register src2 (converted to int32), and puts the
1664 result in register dst.
1665 */
1666 int dst = (++vPC)->u.operand;
1667 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1668 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1669 int32_t left;
1670 int32_t right;
1671 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1672 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
1673 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1674 r[dst] = jsNumber(exec, left | right);
1675 else {
1676 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
1677 VM_CHECK_EXCEPTION();
1678 r[dst] = result;
1679 }
1680
1681 ++vPC;
1682 NEXT_OPCODE;
1683 }
1684 BEGIN_OPCODE(op_bitnot) {
1685 /* bitnot dst(r) src(r)
1686
1687 Computes bitwise NOT of register src1 (converted to int32),
1688 and puts the result in register dst.
1689 */
1690 int dst = (++vPC)->u.operand;
1691 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1692 int32_t value;
1693 if (fastToInt32(src, value))
1694 r[dst] = jsNumber(exec, ~value);
1695 else {
1696 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
1697 VM_CHECK_EXCEPTION();
1698 r[dst] = result;
1699 }
1700 ++vPC;
1701 NEXT_OPCODE;
1702 }
1703 BEGIN_OPCODE(op_not) {
1704 /* not dst(r) src(r)
1705
1706 Computes logical NOT of register src (converted to
1707 boolean), and puts the result in register dst.
1708 */
1709 int dst = (++vPC)->u.operand;
1710 int src = (++vPC)->u.operand;
1711 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
1712 VM_CHECK_EXCEPTION();
1713 r[dst] = result;
1714
1715 ++vPC;
1716 NEXT_OPCODE;
1717 }
1718 BEGIN_OPCODE(op_instanceof) {
1719 /* instanceof dst(r) value(r) constructor(r)
1720
1721 Tests whether register value is an instance of register
1722 constructor, and puts the boolean result in register dst.
1723
1724 Raises an exception if register constructor is not an
1725 object.
1726 */
1727 int dst = (++vPC)->u.operand;
1728 int value = (++vPC)->u.operand;
1729 int base = (++vPC)->u.operand;
1730
1731 JSValue* baseVal = r[base].jsValue(exec);
1732
1733 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
1734 goto vm_throw;
1735
1736 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1737 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec)) : false);
1738
1739 ++vPC;
1740 NEXT_OPCODE;
1741 }
1742 BEGIN_OPCODE(op_typeof) {
1743 /* typeof dst(r) src(r)
1744
1745 Determines the type string for src according to ECMAScript
1746 rules, and puts the result in register dst.
1747 */
1748 int dst = (++vPC)->u.operand;
1749 int src = (++vPC)->u.operand;
1750 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
1751
1752 ++vPC;
1753 NEXT_OPCODE;
1754 }
1755 BEGIN_OPCODE(op_in) {
1756 /* in dst(r) property(r) base(r)
1757
1758 Tests whether register base has a property named register
1759 property, and puts the boolean result in register dst.
1760
1761 Raises an exception if register constructor is not an
1762 object.
1763 */
1764 int dst = (++vPC)->u.operand;
1765 int property = (++vPC)->u.operand;
1766 int base = (++vPC)->u.operand;
1767
1768 JSValue* baseVal = r[base].jsValue(exec);
1769 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
1770 goto vm_throw;
1771
1772 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1773
1774 JSValue* propName = r[property].jsValue(exec);
1775
1776 uint32_t i;
1777 if (propName->getUInt32(i))
1778 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
1779 else {
1780 Identifier property(exec, propName->toString(exec));
1781 VM_CHECK_EXCEPTION();
1782 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
1783 }
1784
1785 ++vPC;
1786 NEXT_OPCODE;
1787 }
1788 BEGIN_OPCODE(op_resolve) {
1789 /* resolve dst(r) property(id)
1790
1791 Looks up the property named by identifier property in the
1792 scope chain, and writes the resulting value to register
1793 dst. If the property is not found, raises an exception.
1794 */
1795 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1796 goto vm_throw;
1797
1798 vPC += 3;
1799 NEXT_OPCODE;
1800 }
1801 BEGIN_OPCODE(op_resolve_skip) {
1802 /* resolve_skip dst(r) property(id) skip(n)
1803
1804 Looks up the property named by identifier property in the
1805 scope chain skipping the top 'skip' levels, and writes the resulting
1806 value to register dst. If the property is not found, raises an exception.
1807 */
1808 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1809 goto vm_throw;
1810
1811 vPC += 4;
1812
1813 NEXT_OPCODE;
1814 }
1815 BEGIN_OPCODE(op_get_scoped_var) {
1816 /* get_scoped_var dst(r) index(n) skip(n)
1817
1818 Loads the contents of the index-th local from the scope skip nodes from
1819 the top of the scope chain, and places it in register dst
1820 */
1821 int dst = (++vPC)->u.operand;
1822 int index = (++vPC)->u.operand;
1823 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1824
1825 ScopeChainIterator iter = scopeChain->begin();
1826 ScopeChainIterator end = scopeChain->end();
1827 ASSERT(iter != end);
1828 while (skip--) {
1829 ++iter;
1830 ASSERT(iter != end);
1831 }
1832
1833 ASSERT((*iter)->isVariableObject());
1834 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1835 r[dst] = scope->registerAt(index);
1836 ++vPC;
1837 NEXT_OPCODE;
1838 }
1839 BEGIN_OPCODE(op_put_scoped_var) {
1840 /* put_scoped_var index(n) skip(n) value(r)
1841
1842 */
1843 int index = (++vPC)->u.operand;
1844 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1845 int value = (++vPC)->u.operand;
1846
1847 ScopeChainIterator iter = scopeChain->begin();
1848 ScopeChainIterator end = scopeChain->end();
1849 ASSERT(iter != end);
1850 while (skip--) {
1851 ++iter;
1852 ASSERT(iter != end);
1853 }
1854
1855 ASSERT((*iter)->isVariableObject());
1856 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1857 scope->registerAt(index) = r[value].jsValue(exec);
1858 ++vPC;
1859 NEXT_OPCODE;
1860 }
1861 BEGIN_OPCODE(op_resolve_base) {
1862 /* resolve_base dst(r) property(id)
1863
1864 Searches the scope chain for an object containing
1865 identifier property, and if one is found, writes it to
1866 register dst. If none is found, the outermost scope (which
1867 will be the global object) is stored in register dst.
1868 */
1869 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1870
1871 vPC += 3;
1872 NEXT_OPCODE;
1873 }
1874 BEGIN_OPCODE(op_resolve_with_base) {
1875 /* resolve_with_base baseDst(r) propDst(r) property(id)
1876
1877 Searches the scope chain for an object containing
1878 identifier property, and if one is found, writes it to
1879 register srcDst, and the retrieved property value to register
1880 propDst. If the property is not found, raises an exception.
1881
1882 This is more efficient than doing resolve_base followed by
1883 resolve, or resolve_base followed by get_by_id, as it
1884 avoids duplicate hash lookups.
1885 */
1886 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1887 goto vm_throw;
1888
1889 vPC += 4;
1890 NEXT_OPCODE;
1891 }
1892 BEGIN_OPCODE(op_resolve_func) {
1893 /* resolve_func baseDst(r) funcDst(r) property(id)
1894
1895 Searches the scope chain for an object containing
1896 identifier property, and if one is found, writes the
1897 appropriate object to use as "this" when calling its
1898 properties to register baseDst; and the retrieved property
1899 value to register propDst. If the property is not found,
1900 raises an exception.
1901
1902 This differs from resolve_with_base, because the
1903 global this value will be substituted for activations or
1904 the global object, which is the right behavior for function
1905 calls but not for other property lookup.
1906 */
1907 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1908 goto vm_throw;
1909
1910 vPC += 4;
1911 NEXT_OPCODE;
1912 }
1913 BEGIN_OPCODE(op_get_by_id) {
1914 /* get_by_id dst(r) base(r) property(id)
1915
1916 Converts register base to Object, gets the property
1917 named by identifier property from the object, and puts the
1918 result in register dst.
1919 */
1920 int dst = (++vPC)->u.operand;
1921 int base = (++vPC)->u.operand;
1922 int property = (++vPC)->u.operand;
1923
1924 Identifier& ident = codeBlock->identifiers[property];
1925 JSValue *result = r[base].jsValue(exec)->get(exec, ident);
1926 VM_CHECK_EXCEPTION();
1927 r[dst] = result;
1928 ++vPC;
1929 NEXT_OPCODE;
1930 }
1931 BEGIN_OPCODE(op_put_by_id) {
1932 /* put_by_id base(r) property(id) value(r)
1933
1934 Sets register value on register base as the property named
1935 by identifier property. Base is converted to object first.
1936
1937 Unlike many opcodes, this one does not write any output to
1938 the register file.
1939 */
1940 int base = (++vPC)->u.operand;
1941 int property = (++vPC)->u.operand;
1942 int value = (++vPC)->u.operand;
1943
1944 Identifier& ident = codeBlock->identifiers[property];
1945 r[base].jsValue(exec)->put(exec, ident, r[value].jsValue(exec));
1946
1947 VM_CHECK_EXCEPTION();
1948 ++vPC;
1949 NEXT_OPCODE;
1950 }
1951 BEGIN_OPCODE(op_del_by_id) {
1952 /* del_by_id dst(r) base(r) property(id)
1953
1954 Converts register base to Object, deletes the property
1955 named by identifier property from the object, and writes a
1956 boolean indicating success (if true) or failure (if false)
1957 to register dst.
1958 */
1959 int dst = (++vPC)->u.operand;
1960 int base = (++vPC)->u.operand;
1961 int property = (++vPC)->u.operand;
1962
1963 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
1964
1965 Identifier& ident = codeBlock->identifiers[property];
1966 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1967 VM_CHECK_EXCEPTION();
1968 r[dst] = result;
1969 ++vPC;
1970 NEXT_OPCODE;
1971 }
1972 BEGIN_OPCODE(op_get_by_val) {
1973 /* get_by_val dst(r) base(r) property(r)
1974
1975 Converts register base to Object, gets the property named
1976 by register property from the object, and puts the result
1977 in register dst. property is nominally converted to string
1978 but numbers are treated more efficiently.
1979 */
1980 int dst = (++vPC)->u.operand;
1981 int base = (++vPC)->u.operand;
1982 int property = (++vPC)->u.operand;
1983
1984 JSValue* baseValue = r[base].jsValue(exec);
1985 JSValue* subscript = r[property].jsValue(exec);
1986
1987 JSValue* result;
1988 unsigned i;
1989
1990 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
1991 if (LIKELY(isUInt32)) {
1992 if (isJSArray(baseValue)) {
1993 JSArray* jsArray = static_cast<JSArray*>(baseValue);
1994 if (jsArray->canGetIndex(i))
1995 result = jsArray->getIndex(i);
1996 else
1997 result = jsArray->JSArray::get(exec, i);
1998 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
1999 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2000 else
2001 result = baseValue->get(exec, i);
2002 } else {
2003 Identifier property(exec, subscript->toString(exec));
2004 result = baseValue->get(exec, property);
2005 }
2006
2007 VM_CHECK_EXCEPTION();
2008 r[dst] = result;
2009 ++vPC;
2010 NEXT_OPCODE;
2011 }
2012 BEGIN_OPCODE(op_put_by_val) {
2013 /* put_by_val base(r) property(r) value(r)
2014
2015 Sets register value on register base as the property named
2016 by register property. Base is converted to object
2017 first. register property is nominally converted to string
2018 but numbers are treated more efficiently.
2019
2020 Unlike many opcodes, this one does not write any output to
2021 the register file.
2022 */
2023 int base = (++vPC)->u.operand;
2024 int property = (++vPC)->u.operand;
2025 int value = (++vPC)->u.operand;
2026
2027 JSValue* baseValue = r[base].jsValue(exec);
2028 JSValue* subscript = r[property].jsValue(exec);
2029
2030 unsigned i;
2031
2032 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2033 if (LIKELY(isUInt32)) {
2034 if (isJSArray(baseValue)) {
2035 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2036 if (jsArray->canSetIndex(i))
2037 jsArray->setIndex(i, r[value].jsValue(exec));
2038 else
2039 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2040 } else
2041 baseValue->put(exec, i, r[value].jsValue(exec));
2042 } else {
2043 Identifier property(exec, subscript->toString(exec));
2044 if (!exec->hadException()) // Don't put to an object if toString threw an exception.
2045 baseValue->put(exec, property, r[value].jsValue(exec));
2046 }
2047
2048 VM_CHECK_EXCEPTION();
2049 ++vPC;
2050 NEXT_OPCODE;
2051 }
2052 BEGIN_OPCODE(op_del_by_val) {
2053 /* del_by_val dst(r) base(r) property(r)
2054
2055 Converts register base to Object, deletes the property
2056 named by register property from the object, and writes a
2057 boolean indicating success (if true) or failure (if false)
2058 to register dst.
2059 */
2060 int dst = (++vPC)->u.operand;
2061 int base = (++vPC)->u.operand;
2062 int property = (++vPC)->u.operand;
2063
2064 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2065
2066 JSValue* subscript = r[property].jsValue(exec);
2067 JSValue* result;
2068 uint32_t i;
2069 if (subscript->getUInt32(i))
2070 result = jsBoolean(baseObj->deleteProperty(exec, i));
2071 else {
2072 VM_CHECK_EXCEPTION();
2073 Identifier property(exec, subscript->toString(exec));
2074 VM_CHECK_EXCEPTION();
2075 result = jsBoolean(baseObj->deleteProperty(exec, property));
2076 }
2077
2078 VM_CHECK_EXCEPTION();
2079 r[dst] = result;
2080 ++vPC;
2081 NEXT_OPCODE;
2082 }
2083 BEGIN_OPCODE(op_put_by_index) {
2084 /* put_by_index base(r) property(n) value(r)
2085
2086 Sets register value on register base as the property named
2087 by the immediate number property. Base is converted to
2088 object first.
2089
2090 Unlike many opcodes, this one does not write any output to
2091 the register file.
2092
2093 This opcode is mainly used to initialize array literals.
2094 */
2095 int base = (++vPC)->u.operand;
2096 unsigned property = (++vPC)->u.operand;
2097 int value = (++vPC)->u.operand;
2098
2099 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2100
2101 ++vPC;
2102 NEXT_OPCODE;
2103 }
2104 BEGIN_OPCODE(op_loop) {
2105 /* loop target(offset)
2106
2107 Jumps unconditionally to offset target from the current
2108 instruction.
2109
2110 Additionally this loop instruction may terminate JS execution is
2111 the JS timeout is reached.
2112 */
2113#if DUMP_OPCODE_STATS
2114 OpcodeStats::resetLastInstruction();
2115#endif
2116 int target = (++vPC)->u.operand;
2117 CHECK_FOR_TIMEOUT();
2118 vPC += target;
2119 NEXT_OPCODE;
2120 }
2121 BEGIN_OPCODE(op_jmp) {
2122 /* jmp target(offset)
2123
2124 Jumps unconditionally to offset target from the current
2125 instruction.
2126 */
2127#if DUMP_OPCODE_STATS
2128 OpcodeStats::resetLastInstruction();
2129#endif
2130 int target = (++vPC)->u.operand;
2131
2132 vPC += target;
2133 NEXT_OPCODE;
2134 }
2135 BEGIN_OPCODE(op_loop_if_true) {
2136 /* loop_if_true cond(r) target(offset)
2137
2138 Jumps to offset target from the current instruction, if and
2139 only if register cond converts to boolean as true.
2140
2141 Additionally this loop instruction may terminate JS execution is
2142 the JS timeout is reached.
2143 */
2144 int cond = (++vPC)->u.operand;
2145 int target = (++vPC)->u.operand;
2146 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2147 vPC += target;
2148 CHECK_FOR_TIMEOUT();
2149 NEXT_OPCODE;
2150 }
2151
2152 ++vPC;
2153 NEXT_OPCODE;
2154 }
2155 BEGIN_OPCODE(op_jtrue) {
2156 /* jtrue cond(r) target(offset)
2157
2158 Jumps to offset target from the current instruction, if and
2159 only if register cond converts to boolean as true.
2160 */
2161 int cond = (++vPC)->u.operand;
2162 int target = (++vPC)->u.operand;
2163 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2164 vPC += target;
2165 NEXT_OPCODE;
2166 }
2167
2168 ++vPC;
2169 NEXT_OPCODE;
2170 }
2171 BEGIN_OPCODE(op_jfalse) {
2172 /* jfalse cond(r) target(offset)
2173
2174 Jumps to offset target from the current instruction, if and
2175 only if register cond converts to boolean as false.
2176 */
2177 int cond = (++vPC)->u.operand;
2178 int target = (++vPC)->u.operand;
2179 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2180 vPC += target;
2181 NEXT_OPCODE;
2182 }
2183
2184 ++vPC;
2185 NEXT_OPCODE;
2186 }
2187 BEGIN_OPCODE(op_loop_if_less) {
2188 /* loop_if_less src1(r) src2(r) target(offset)
2189
2190 Checks whether register src1 is less than register src2, as
2191 with the ECMAScript '<' operator, and then jumps to offset
2192 target from the current instruction, if and only if the
2193 result of the comparison is true.
2194
2195 Additionally this loop instruction may terminate JS execution is
2196 the JS timeout is reached.
2197 */
2198 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2199 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2200 int target = (++vPC)->u.operand;
2201
2202 bool result = jsLess(exec, src1, src2);
2203 VM_CHECK_EXCEPTION();
2204
2205 if (result) {
2206 vPC += target;
2207 CHECK_FOR_TIMEOUT();
2208 NEXT_OPCODE;
2209 }
2210
2211 ++vPC;
2212 NEXT_OPCODE;
2213 }
2214 BEGIN_OPCODE(op_jnless) {
2215 /* jnless src1(r) src2(r) target(offset)
2216
2217 Checks whether register src1 is less than register src2, as
2218 with the ECMAScript '<' operator, and then jumps to offset
2219 target from the current instruction, if and only if the
2220 result of the comparison is false.
2221 */
2222 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2223 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2224 int target = (++vPC)->u.operand;
2225
2226 bool result = jsLess(exec, src1, src2);
2227 VM_CHECK_EXCEPTION();
2228
2229 if (!result) {
2230 vPC += target;
2231 NEXT_OPCODE;
2232 }
2233
2234 ++vPC;
2235 NEXT_OPCODE;
2236 }
2237 BEGIN_OPCODE(op_switch_imm) {
2238 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2239
2240 Performs a range checked switch on the scrutinee value, using
2241 the tableIndex-th immediate switch jump table. If the scrutinee value
2242 is an immediate number in the range covered by the referenced jump
2243 table, and the value at jumpTable[scrutinee value] is non-zero, then
2244 that value is used as the jump offset, otherwise defaultOffset is used.
2245 */
2246 int tableIndex = (++vPC)->u.operand;
2247 int defaultOffset = (++vPC)->u.operand;
2248 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2249 if (!JSImmediate::isNumber(scrutinee))
2250 vPC += defaultOffset;
2251 else {
2252 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
2253 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
2254 }
2255 NEXT_OPCODE;
2256 }
2257 BEGIN_OPCODE(op_switch_char) {
2258 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2259
2260 Performs a range checked switch on the scrutinee value, using
2261 the tableIndex-th character switch jump table. If the scrutinee value
2262 is a single character string in the range covered by the referenced jump
2263 table, and the value at jumpTable[scrutinee value] is non-zero, then
2264 that value is used as the jump offset, otherwise defaultOffset is used.
2265 */
2266 int tableIndex = (++vPC)->u.operand;
2267 int defaultOffset = (++vPC)->u.operand;
2268 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2269 if (!scrutinee->isString())
2270 vPC += defaultOffset;
2271 else {
2272 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
2273 if (value->size() != 1)
2274 vPC += defaultOffset;
2275 else
2276 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
2277 }
2278 NEXT_OPCODE;
2279 }
2280 BEGIN_OPCODE(op_switch_string) {
2281 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2282
2283 Performs a sparse hashmap based switch on the value in the scrutinee
2284 register, using the tableIndex-th string switch jump table. If the
2285 scrutinee value is a string that exists as a key in the referenced
2286 jump table, then the value associated with the string is used as the
2287 jump offset, otherwise defaultOffset is used.
2288 */
2289 int tableIndex = (++vPC)->u.operand;
2290 int defaultOffset = (++vPC)->u.operand;
2291 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2292 if (!scrutinee->isString())
2293 vPC += defaultOffset;
2294 else
2295 vPC += offsetForStringSwitch(codeBlock->stringSwitchJumpTables[tableIndex], scrutinee, defaultOffset);
2296 NEXT_OPCODE;
2297 }
2298 BEGIN_OPCODE(op_new_func) {
2299 /* new_func dst(r) func(f)
2300
2301 Constructs a new Function instance from function func and
2302 the current scope chain using the original Function
2303 constructor, using the rules for function declarations, and
2304 puts the result in register dst.
2305 */
2306 int dst = (++vPC)->u.operand;
2307 int func = (++vPC)->u.operand;
2308
2309 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
2310
2311 ++vPC;
2312 NEXT_OPCODE;
2313 }
2314 BEGIN_OPCODE(op_new_func_exp) {
2315 /* new_func_exp dst(r) func(f)
2316
2317 Constructs a new Function instance from function func and
2318 the current scope chain using the original Function
2319 constructor, using the rules for function expressions, and
2320 puts the result in register dst.
2321 */
2322 int dst = (++vPC)->u.operand;
2323 int func = (++vPC)->u.operand;
2324
2325 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
2326
2327 ++vPC;
2328 NEXT_OPCODE;
2329 }
2330 BEGIN_OPCODE(op_call_eval) {
2331 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2332
2333 Call a function named "eval" with no explicit "this" value
2334 (which may therefore be the eval operator). If register
2335 thisVal is the global object, and register func contains
2336 that global object's original global eval function, then
2337 perform the eval operator in local scope (interpreting
2338 the argument registers as for the "call"
2339 opcode). Otherwise, act exactly as the "call" opcode would.
2340 */
2341
2342 int dst = (++vPC)->u.operand;
2343 int func = (++vPC)->u.operand;
2344 int thisVal = (++vPC)->u.operand;
2345 int firstArg = (++vPC)->u.operand;
2346 int argCount = (++vPC)->u.operand;
2347
2348 JSValue* funcVal = r[func].jsValue(exec);
2349 JSValue* baseVal = r[thisVal].jsValue(exec);
2350
2351 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
2352 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
2353 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
2354 if (exceptionValue)
2355 goto vm_throw;
2356
2357 r[dst] = result;
2358
2359 ++vPC;
2360 NEXT_OPCODE;
2361 }
2362
2363 // We didn't find the blessed version of eval, so reset vPC and process
2364 // this instruction as a normal function call, supplying the proper 'this'
2365 // value.
2366 vPC -= 5;
2367 r[thisVal] = baseVal->toThisObject(exec);
2368
2369#if HAVE(COMPUTED_GOTO)
2370 // Hack around gcc performance quirk by performing an indirect goto
2371 // in order to set the vPC -- attempting to do so directly results in a
2372 // significant regression.
2373 goto *op_call_indirect; // indirect goto -> op_call
2374#endif
2375 // fall through to op_call
2376 }
2377 BEGIN_OPCODE(op_call) {
2378 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2379
2380 Perform a function call. Specifically, call register func
2381 with a "this" value of register thisVal, and put the result
2382 in register dst.
2383
2384 The arguments start at register firstArg and go up to
2385 argCount, but the "this" value is considered an implicit
2386 first argument, so the argCount should be one greater than
2387 the number of explicit arguments passed, and the register
2388 after firstArg should contain the actual first
2389 argument. This opcode will copy from the thisVal register
2390 to the firstArg register, unless the register index of
2391 thisVal is the special missing this object marker, which is
2392 2^31-1; in that case, the global object will be used as the
2393 "this" value.
2394
2395 If func is a native code function, then this opcode calls
2396 it and returns the value immediately.
2397
2398 But if it is a JS function, then the current scope chain
2399 and code block is set to the function's, and we slide the
2400 register window so that the arguments would form the first
2401 few local registers of the called function's register
2402 window. In addition, a call frame header is written
2403 immediately before the arguments; see the call frame
2404 documentation for an explanation of how many registers a
2405 call frame takes and what they contain. That many registers
2406 before the firstArg register will be overwritten by the
2407 call. In addition, any registers higher than firstArg +
2408 argCount may be overwritten. Once this setup is complete,
2409 execution continues from the called function's first
2410 argument, and does not return until a "ret" opcode is
2411 encountered.
2412 */
2413
2414 int dst = (++vPC)->u.operand;
2415 int func = (++vPC)->u.operand;
2416 int thisVal = (++vPC)->u.operand;
2417 int firstArg = (++vPC)->u.operand;
2418 int argCount = (++vPC)->u.operand;
2419
2420 JSValue* v = r[func].jsValue(exec);
2421
2422 CallData callData;
2423 CallType callType = v->getCallData(callData);
2424
2425 if (callType == CallTypeJS) {
2426 if (*enabledProfilerReference)
2427 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
2428
2429 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
2430 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
2431 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
2432
2433 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2434
2435 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
2436 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 0, v);
2437 exec->m_callFrame = callFrame;
2438
2439 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
2440 if (UNLIKELY(exceptionValue != 0))
2441 goto vm_throw;
2442
2443 codeBlock = newCodeBlock;
2444 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
2445 vPC = codeBlock->instructions.begin();
2446
2447#if DUMP_OPCODE_STATS
2448 OpcodeStats::resetLastInstruction();
2449#endif
2450
2451 NEXT_OPCODE;
2452 }
2453
2454 if (callType == CallTypeHost) {
2455 if (*enabledProfilerReference)
2456 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
2457
2458 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2459 ArgList args(r + firstArg + 1, argCount - 1);
2460
2461 MACHINE_SAMPLING_callingHostFunction();
2462
2463 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
2464 VM_CHECK_EXCEPTION();
2465
2466 r[dst] = returnValue;
2467
2468 if (*enabledProfilerReference)
2469 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
2470
2471 ++vPC;
2472 NEXT_OPCODE;
2473 }
2474
2475 ASSERT(callType == CallTypeNone);
2476
2477 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
2478 goto vm_throw;
2479 }
2480 BEGIN_OPCODE(op_ret) {
2481 /* ret result(r)
2482
2483 Return register result as the return value of the current
2484 function call, writing it into the caller's expected return
2485 value register. In addition, unwind one call frame and
2486 restore the scope chain, code block instruction pointer and
2487 register base to those of the calling function.
2488 */
2489
2490 int result = (++vPC)->u.operand;
2491
2492 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2493 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
2494 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
2495 ASSERT(activation->isActivationObject());
2496 activation->copyRegisters();
2497 }
2498
2499 if (*enabledProfilerReference)
2500 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
2501
2502 if (codeBlock->needsFullScopeChain)
2503 scopeChain->deref();
2504
2505 JSValue* returnValue = r[result].jsValue(exec);
2506 if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) {
2507 JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec);
2508 returnValue = thisObject;
2509 }
2510
2511 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2512 if (!codeBlock)
2513 return returnValue;
2514
2515 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
2516 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
2517 r = callFrame[RegisterFile::CallerRegisters].r();
2518 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2519 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
2520 r[dst] = returnValue;
2521
2522 NEXT_OPCODE;
2523 }
2524 BEGIN_OPCODE(op_construct) {
2525 /* construct dst(r) constr(r) firstArg(r) argCount(n)
2526
2527 Invoke register "constr" as a constructor. For JS
2528 functions, the calling convention is exactly as for the
2529 "call" opcode, except that the "this" value is a newly
2530 created Object. For native constructors, a null "this"
2531 value is passed. In either case, the firstArg and argCount
2532 registers are interpreted as for the "call" opcode.
2533 */
2534
2535 int dst = (++vPC)->u.operand;
2536 int constr = (++vPC)->u.operand;
2537 int firstArg = (++vPC)->u.operand;
2538 int argCount = (++vPC)->u.operand;
2539
2540 JSValue* constrVal = r[constr].jsValue(exec);
2541
2542 ConstructData constructData;
2543 ConstructType constructType = constrVal->getConstructData(constructData);
2544
2545 // Removing this line of code causes a measurable regression on squirrelfish.
2546 JSObject* constructor = static_cast<JSObject*>(constrVal);
2547
2548 if (constructType == ConstructTypeJS) {
2549 if (*enabledProfilerReference)
2550 (*enabledProfilerReference)->willExecute(exec, constructor);
2551
2552 JSObject* prototype;
2553 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
2554 if (p->isObject())
2555 prototype = static_cast<JSObject*>(p);
2556 else
2557 prototype = scopeChain->globalObject()->objectPrototype();
2558 JSObject* newObject = new (exec) JSObject(prototype);
2559
2560 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
2561 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
2562 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
2563
2564 r[firstArg] = newObject; // "this" value
2565
2566 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
2567 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 1, constructor);
2568 exec->m_callFrame = callFrame;
2569
2570 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
2571 if (exceptionValue)
2572 goto vm_throw;
2573
2574 codeBlock = newCodeBlock;
2575 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
2576 vPC = codeBlock->instructions.begin();
2577
2578 NEXT_OPCODE;
2579 }
2580
2581 if (constructType == ConstructTypeHost) {
2582 if (*enabledProfilerReference)
2583 (*enabledProfilerReference)->willExecute(exec, constructor);
2584
2585 ArgList args(r + firstArg + 1, argCount - 1);
2586
2587 MACHINE_SAMPLING_callingHostFunction();
2588
2589 JSValue* returnValue = constructData.native.function(exec, constructor, args);
2590
2591 VM_CHECK_EXCEPTION();
2592 r[dst] = returnValue;
2593
2594 if (*enabledProfilerReference)
2595 (*enabledProfilerReference)->didExecute(exec, constructor);
2596
2597 ++vPC;
2598 NEXT_OPCODE;
2599 }
2600
2601 ASSERT(constructType == ConstructTypeNone);
2602
2603 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
2604 goto vm_throw;
2605 }
2606 BEGIN_OPCODE(op_push_scope) {
2607 /* push_scope scope(r)
2608
2609 Converts register scope to object, and pushes it onto the top
2610 of the current scope chain.
2611 */
2612 int scope = (++vPC)->u.operand;
2613 JSValue* v = r[scope].jsValue(exec);
2614 JSObject* o = v->toObject(exec);
2615 VM_CHECK_EXCEPTION();
2616
2617 setScopeChain(exec, scopeChain, scopeChain->push(o));
2618
2619 ++vPC;
2620 NEXT_OPCODE;
2621 }
2622 BEGIN_OPCODE(op_pop_scope) {
2623 /* pop_scope
2624
2625 Removes the top item from the current scope chain.
2626 */
2627 setScopeChain(exec, scopeChain, scopeChain->pop());
2628
2629 ++vPC;
2630 NEXT_OPCODE;
2631 }
2632 BEGIN_OPCODE(op_get_pnames) {
2633 /* get_pnames dst(r) base(r)
2634
2635 Creates a property name list for register base and puts it
2636 in register dst. This is not a true JavaScript value, just
2637 a synthetic value used to keep the iteration state in a
2638 register.
2639 */
2640 int dst = (++vPC)->u.operand;
2641 int base = (++vPC)->u.operand;
2642
2643 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
2644 ++vPC;
2645 NEXT_OPCODE;
2646 }
2647 BEGIN_OPCODE(op_next_pname) {
2648 /* next_pname dst(r) iter(r) target(offset)
2649
2650 Tries to copies the next name from property name list in
2651 register iter. If there are names left, then copies one to
2652 register dst, and jumps to offset target. If there are none
2653 left, invalidates the iterator and continues to the next
2654 instruction.
2655 */
2656 int dst = (++vPC)->u.operand;
2657 int iter = (++vPC)->u.operand;
2658 int target = (++vPC)->u.operand;
2659
2660 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
2661 if (JSValue* temp = it->next(exec)) {
2662 CHECK_FOR_TIMEOUT();
2663 r[dst] = temp;
2664 vPC += target;
2665 NEXT_OPCODE;
2666 }
2667 it->invalidate();
2668
2669 ++vPC;
2670 NEXT_OPCODE;
2671 }
2672 BEGIN_OPCODE(op_jmp_scopes) {
2673 /* jmp_scopes count(n) target(offset)
2674
2675 Removes the a number of items from the current scope chain
2676 specified by immediate number count, then jumps to offset
2677 target.
2678 */
2679 int count = (++vPC)->u.operand;
2680 int target = (++vPC)->u.operand;
2681
2682 ScopeChainNode* tmp = scopeChain;
2683 while (count--)
2684 tmp = tmp->pop();
2685 setScopeChain(exec, scopeChain, tmp);
2686
2687 vPC += target;
2688 NEXT_OPCODE;
2689 }
2690#if HAVE(COMPUTED_GOTO)
2691 // Appease GCC
2692 goto *(&&skip_new_scope);
2693#endif
2694 BEGIN_OPCODE(op_push_new_scope) {
2695 /* new_scope dst(r) property(id) value(r)
2696
2697 Constructs a new StaticScopeObject with property set to value. That scope
2698 object is then pushed onto the ScopeChain. The scope object is then stored
2699 in dst for GC.
2700 */
2701 setScopeChain(exec, scopeChain, createExceptionScope(exec, codeBlock, vPC, r, scopeChain));
2702 vPC += 4;
2703 NEXT_OPCODE;
2704 }
2705#if HAVE(COMPUTED_GOTO)
2706 skip_new_scope:
2707#endif
2708 BEGIN_OPCODE(op_catch) {
2709 /* catch ex(r)
2710
2711 Retrieves the VMs current exception and puts it in register
2712 ex. This is only valid after an exception has been raised,
2713 and usually forms the beginning of an exception handler.
2714 */
2715 ASSERT(exceptionValue);
2716 ASSERT(!exec->hadException());
2717 int ex = (++vPC)->u.operand;
2718 r[ex] = exceptionValue;
2719 exceptionValue = 0;
2720
2721 ++vPC;
2722 NEXT_OPCODE;
2723 }
2724 BEGIN_OPCODE(op_throw) {
2725 /* throw ex(r)
2726
2727 Throws register ex as an exception. This involves three
2728 steps: first, it is set as the current exception in the
2729 VM's internal state, then the stack is unwound until an
2730 exception handler or a native code boundary is found, and
2731 then control resumes at the exception handler if any or
2732 else the script returns control to the nearest native caller.
2733 */
2734
2735 int ex = (++vPC)->u.operand;
2736 exceptionValue = r[ex].jsValue(exec);
2737
2738 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, true);
2739 if (!handlerVPC) {
2740 *exception = exceptionValue;
2741 return jsNull();
2742 }
2743
2744#if HAVE(COMPUTED_GOTO)
2745 // Hack around gcc performance quirk by performing an indirect goto
2746 // in order to set the vPC -- attempting to do so directly results in a
2747 // significant regression.
2748 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2749 }
2750 op_throw_end: {
2751#endif
2752
2753 vPC = handlerVPC;
2754 NEXT_OPCODE;
2755 }
2756 BEGIN_OPCODE(op_unexpected_load) {
2757 /* unexpected_load load dst(r) src(k)
2758
2759 Copies constant src to register dst.
2760 */
2761 int dst = (++vPC)->u.operand;
2762 int src = (++vPC)->u.operand;
2763 r[dst] = codeBlock->unexpectedConstants[src];
2764
2765 ++vPC;
2766 NEXT_OPCODE;
2767 }
2768 BEGIN_OPCODE(op_new_error) {
2769 /* new_error dst(r) type(n) message(k)
2770
2771 Constructs a new Error instance using the original
2772 constructor, using immediate number n as the type and
2773 constant message as the message string. The result is
2774 written to register dst.
2775 */
2776 int dst = (++vPC)->u.operand;
2777 int type = (++vPC)->u.operand;
2778 int message = (++vPC)->u.operand;
2779
2780 r[dst] = Error::create(exec, (ErrorType)type, codeBlock->unexpectedConstants[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2781
2782 ++vPC;
2783 NEXT_OPCODE;
2784 }
2785 BEGIN_OPCODE(op_end) {
2786 /* end result(r)
2787
2788 Return register result as the value of a global or eval
2789 program. Return control to the calling native code.
2790 */
2791
2792 if (codeBlock->needsFullScopeChain) {
2793 ASSERT(scopeChain->refCount > 1);
2794 scopeChain->deref();
2795 }
2796 int result = (++vPC)->u.operand;
2797 return r[result].jsValue(exec);
2798 }
2799 BEGIN_OPCODE(op_put_getter) {
2800 /* put_getter base(r) property(id) function(r)
2801
2802 Sets register function on register base as the getter named
2803 by identifier property. Base and function are assumed to be
2804 objects as this op should only be used for getters defined
2805 in object literal form.
2806
2807 Unlike many opcodes, this one does not write any output to
2808 the register file.
2809 */
2810 int base = (++vPC)->u.operand;
2811 int property = (++vPC)->u.operand;
2812 int function = (++vPC)->u.operand;
2813
2814 ASSERT(r[base].jsValue(exec)->isObject());
2815 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
2816 Identifier& ident = codeBlock->identifiers[property];
2817 ASSERT(r[function].jsValue(exec)->isObject());
2818 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
2819
2820 ++vPC;
2821 NEXT_OPCODE;
2822 }
2823 BEGIN_OPCODE(op_put_setter) {
2824 /* put_setter base(r) property(id) function(r)
2825
2826 Sets register function on register base as the setter named
2827 by identifier property. Base and function are assumed to be
2828 objects as this op should only be used for setters defined
2829 in object literal form.
2830
2831 Unlike many opcodes, this one does not write any output to
2832 the register file.
2833 */
2834 int base = (++vPC)->u.operand;
2835 int property = (++vPC)->u.operand;
2836 int function = (++vPC)->u.operand;
2837
2838 ASSERT(r[base].jsValue(exec)->isObject());
2839 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
2840 Identifier& ident = codeBlock->identifiers[property];
2841 ASSERT(r[function].jsValue(exec)->isObject());
2842 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
2843
2844 ++vPC;
2845 NEXT_OPCODE;
2846 }
2847 BEGIN_OPCODE(op_jsr) {
2848 /* jsr retAddrDst(r) target(offset)
2849
2850 Places the address of the next instruction into the retAddrDst
2851 register and jumps to offset target from the current instruction.
2852 */
2853 int retAddrDst = (++vPC)->u.operand;
2854 int target = (++vPC)->u.operand;
2855 r[retAddrDst] = vPC + 1;
2856
2857 vPC += target;
2858 NEXT_OPCODE;
2859 }
2860 BEGIN_OPCODE(op_sret) {
2861 /* sret retAddrSrc(r)
2862
2863 Jumps to the address stored in the retAddrSrc register. This
2864 differs from op_jmp because the target address is stored in a
2865 register, not as an immediate.
2866 */
2867 int retAddrSrc = (++vPC)->u.operand;
2868 vPC = r[retAddrSrc].vPC();
2869 NEXT_OPCODE;
2870 }
2871 BEGIN_OPCODE(op_debug) {
2872 /* debug debugHookID(n) firstLine(n) lastLine(n)
2873
2874 Notifies the debugger of the current state of execution. This opcode
2875 is only generated while the debugger is attached.
2876 */
2877
2878 debug(exec, vPC, codeBlock, scopeChain, r);
2879
2880 vPC += 4;
2881 NEXT_OPCODE;
2882 }
2883 vm_throw: {
2884 exec->clearException();
2885 if (!tickCount) {
2886 // The exceptionValue is a lie! (GCC produces bad code for reasons I
2887 // cannot fathom if we don't assign to the exceptionValue before branching)
2888 exceptionValue = createInterruptedExecutionException(exec);
2889 }
2890 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, false);
2891 if (!handlerVPC) {
2892 *exception = exceptionValue;
2893 return jsNull();
2894 }
2895 vPC = handlerVPC;
2896 NEXT_OPCODE;
2897 }
2898 }
2899 #undef NEXT_OPCODE
2900 #undef BEGIN_OPCODE
2901 #undef VM_CHECK_EXCEPTION
2902}
2903
2904JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
2905{
2906 Register* callFrame = this->callFrame(exec, function);
2907 if (!callFrame)
2908 return jsNull();
2909
2910 JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
2911 if (!activation) {
2912 CodeBlock* codeBlock = &function->m_body->generatedByteCode();
2913 activation = new (exec) JSActivation(function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
2914 callFrame[RegisterFile::OptionalCalleeActivation] = activation;
2915 }
2916
2917 return activation->get(exec, exec->propertyNames().arguments);
2918}
2919
2920JSValue* Machine::retrieveCaller(ExecState* exec, JSFunction* function) const
2921{
2922 Register* callFrame = this->callFrame(exec, function);
2923 if (!callFrame)
2924 return jsNull();
2925
2926 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2927 if (!callerCodeBlock)
2928 return jsNull();
2929
2930 Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2931 if (JSValue* caller = callerCallFrame[RegisterFile::Callee].jsValue(exec))
2932 return caller;
2933
2934 return jsNull();
2935}
2936
2937Register* Machine::callFrame(ExecState* exec, JSFunction* function) const
2938{
2939 Register* callFrame = exec->m_callFrame;
2940
2941 while (1) {
2942 while (!callFrame) {
2943 exec = exec->m_prev;
2944 if (!exec)
2945 return 0;
2946 callFrame = exec->m_callFrame;
2947 }
2948
2949 if (callFrame[RegisterFile::Callee].jsValue(exec) == function)
2950 return callFrame;
2951
2952 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2953 if (!callerCodeBlock) {
2954 callFrame = 0;
2955 continue;
2956 }
2957
2958 callFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2959 }
2960}
2961
2962void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, Register*& argv, int& argc)
2963{
2964 function = static_cast<JSFunction*>(callFrame[RegisterFile::Callee].getJSValue());
2965 ASSERT(function->inherits(&JSFunction::info));
2966
2967 argv = callFrame[RegisterFile::CallerRegisters].r() + callFrame[RegisterFile::ArgumentStartRegister].i() + 1; // + 1 to skip "this"
2968 argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"
2969}
2970
2971} // namespace KJS
Note: See TracBrowser for help on using the repository browser.