2008-08-29 Anders Carlsson <andersca@apple.com>
[webkit/qt.git] / JavaScriptCore / VM / Machine.cpp
blobe2bd64ed1b53d4f35c02212e2306609fe36f8837
1 /*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
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.
30 #include "config.h"
31 #include "Machine.h"
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>
57 #if PLATFORM(DARWIN)
58 #include <mach/mach.h>
59 #endif
61 #if HAVE(SYS_TIME_H)
62 #include <sys/time.h>
63 #endif
65 #if PLATFORM(WIN_OS)
66 #include <windows.h>
67 #endif
69 #if PLATFORM(QT)
70 #include <QDateTime>
71 #endif
73 using namespace std;
75 namespace KJS {
77 // Default number of ticks before a timeout check should be done.
78 static const int initialTickCountThreshold = 255;
80 // Preferred number of milliseconds between each timeout check
81 static const int preferredScriptCheckTimeInterval = 1000;
83 #if HAVE(COMPUTED_GOTO)
84 static void* op_throw_end_indirect;
85 static void* op_call_indirect;
86 #endif
88 // Returns the depth of the scope chain within a given call frame.
89 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
91 if (!codeBlock->needsFullScopeChain)
92 return 0;
93 int scopeDepth = 0;
94 ScopeChainIterator iter = sc.begin();
95 ScopeChainIterator end = sc.end();
96 while (!(*iter)->isActivationObject()) {
97 ++iter;
98 if (iter == end)
99 break;
100 ++scopeDepth;
102 return scopeDepth;
105 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
106 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
107 static bool fastIsNumber(JSValue* value, double& arg)
109 if (JSImmediate::isNumber(value))
110 arg = JSImmediate::getTruncatedInt32(value);
111 else if (Heap::isNumber(static_cast<JSCell*>(value)))
112 arg = static_cast<JSNumberCell*>(value)->value();
113 else
114 return false;
115 return true;
118 // FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
119 static bool fastToInt32(JSValue* value, int32_t& arg)
121 if (JSImmediate::isNumber(value))
122 arg = JSImmediate::getTruncatedInt32(value);
123 else if (Heap::isNumber(static_cast<JSCell*>(value)))
124 arg = static_cast<JSNumberCell*>(value)->toInt32();
125 else
126 return false;
127 return true;
130 static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
132 if (JSImmediate::isNumber(value)) {
133 if (JSImmediate::getTruncatedUInt32(value, arg))
134 return true;
135 bool scratch;
136 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
137 return true;
138 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
139 arg = static_cast<JSNumberCell*>(value)->toUInt32();
140 else
141 return false;
142 return true;
145 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
147 if (JSImmediate::areBothImmediateNumbers(v1, v2))
148 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
150 double n1;
151 double n2;
152 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
153 return n1 < n2;
155 JSValue* p1;
156 JSValue* p2;
157 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
158 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
160 if (wasNotString1 | wasNotString2)
161 return n1 < n2;
163 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
166 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
168 if (JSImmediate::areBothImmediateNumbers(v1, v2))
169 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
171 double n1;
172 double n2;
173 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
174 return n1 <= n2;
176 JSValue* p1;
177 JSValue* p2;
178 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
179 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
181 if (wasNotString1 | wasNotString2)
182 return n1 <= n2;
184 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
187 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
189 // exception for the Date exception in defaultValue()
190 JSValue* p1 = v1->toPrimitive(exec);
191 JSValue* p2 = v2->toPrimitive(exec);
193 if (p1->isString() || p2->isString()) {
194 UString value = p1->toString(exec) + p2->toString(exec);
195 if (value.isNull())
196 return throwOutOfMemoryError(exec);
197 return jsString(exec, value);
200 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
203 // Fast-path choices here are based on frequency data from SunSpider:
204 // <times> Add case: <t1> <t2>
205 // ---------------------------
206 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
207 // 247412 Add case: 5 5
208 // 20900 Add case: 5 6
209 // 13962 Add case: 5 3
210 // 4000 Add case: 3 5
212 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
214 double left;
215 double right;
216 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
217 return jsNumber(exec, left + right);
219 if (v1->isString() && v2->isString()) {
220 UString value = static_cast<JSString*>(v1)->value() + static_cast<JSString*>(v2)->value();
221 if (value.isNull())
222 return throwOutOfMemoryError(exec);
223 return jsString(exec, value);
226 // All other cases are pretty uncommon
227 return jsAddSlowCase(exec, v1, v2);
230 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
232 if (v->isUndefined())
233 return jsString(exec, "undefined");
234 if (v->isBoolean())
235 return jsString(exec, "boolean");
236 if (v->isNumber())
237 return jsString(exec, "number");
238 if (v->isString())
239 return jsString(exec, "string");
240 if (v->isObject()) {
241 // Return "undefined" for objects that should be treated
242 // as null when doing comparisons.
243 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
244 return jsString(exec, "undefined");
245 CallData callData;
246 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
247 return jsString(exec, "function");
249 return jsString(exec, "object");
252 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
254 int dst = (vPC + 1)->u.operand;
255 int property = (vPC + 2)->u.operand;
257 ScopeChainIterator iter = scopeChain->begin();
258 ScopeChainIterator end = scopeChain->end();
259 ASSERT(iter != end);
261 Identifier& ident = codeBlock->identifiers[property];
262 do {
263 JSObject* o = *iter;
264 PropertySlot slot(o);
265 if (o->getPropertySlot(exec, ident, slot)) {
266 JSValue* result = slot.getValue(exec, ident);
267 exceptionValue = exec->exception();
268 if (exceptionValue)
269 return false;
270 r[dst] = result;
271 return true;
273 } while (++iter != end);
274 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
275 return false;
278 static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
280 int dst = (vPC + 1)->u.operand;
281 int property = (vPC + 2)->u.operand;
282 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
284 ScopeChainIterator iter = scopeChain->begin();
285 ScopeChainIterator end = scopeChain->end();
286 ASSERT(iter != end);
287 while (skip--) {
288 ++iter;
289 ASSERT(iter != end);
291 Identifier& ident = codeBlock->identifiers[property];
292 do {
293 JSObject* o = *iter;
294 PropertySlot slot(o);
295 if (o->getPropertySlot(exec, ident, slot)) {
296 JSValue* result = slot.getValue(exec, ident);
297 exceptionValue = exec->exception();
298 if (exceptionValue)
299 return false;
300 r[dst] = result;
301 return true;
303 } while (++iter != end);
304 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
305 return false;
308 static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
310 int dst = (vPC + 1)->u.operand;
311 int property = (vPC + 2)->u.operand;
313 ScopeChainIterator iter = scopeChain->begin();
314 ScopeChainIterator next = iter;
315 ++next;
316 ScopeChainIterator end = scopeChain->end();
317 ASSERT(iter != end);
319 PropertySlot slot;
320 Identifier& ident = codeBlock->identifiers[property];
321 JSObject* base;
322 while (true) {
323 base = *iter;
324 if (next == end || base->getPropertySlot(exec, ident, slot)) {
325 r[dst] = base;
326 return;
328 iter = next;
329 ++next;
333 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
335 int baseDst = (vPC + 1)->u.operand;
336 int propDst = (vPC + 2)->u.operand;
337 int property = (vPC + 3)->u.operand;
339 ScopeChainIterator iter = scopeChain->begin();
340 ScopeChainIterator end = scopeChain->end();
342 // FIXME: add scopeDepthIsZero optimization
344 ASSERT(iter != end);
346 Identifier& ident = codeBlock->identifiers[property];
347 JSObject* base;
348 do {
349 base = *iter;
350 PropertySlot slot(base);
351 if (base->getPropertySlot(exec, ident, slot)) {
352 JSValue* result = slot.getValue(exec, ident);
353 exceptionValue = exec->exception();
354 if (exceptionValue)
355 return false;
356 r[propDst] = result;
357 r[baseDst] = base;
358 return true;
360 ++iter;
361 } while (iter != end);
363 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
364 return false;
367 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
369 int baseDst = (vPC + 1)->u.operand;
370 int funcDst = (vPC + 2)->u.operand;
371 int property = (vPC + 3)->u.operand;
373 ScopeChainIterator iter = scopeChain->begin();
374 ScopeChainIterator end = scopeChain->end();
376 // FIXME: add scopeDepthIsZero optimization
378 ASSERT(iter != end);
380 Identifier& ident = codeBlock->identifiers[property];
381 JSObject* base;
382 do {
383 base = *iter;
384 PropertySlot slot(base);
385 if (base->getPropertySlot(exec, ident, slot)) {
386 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
387 // However, section 10.2.3 says that in the case where the value provided
388 // by the caller is null, the global object should be used. It also says
389 // that the section does not apply to internal functions, but for simplicity
390 // of implementation we use the global object anyway here. This guarantees
391 // that in host objects you always get a valid object for this.
392 // We also handle wrapper substitution for the global object at the same time.
393 JSObject* thisObj = base->toThisObject(exec);
394 JSValue* result = slot.getValue(exec, ident);
395 exceptionValue = exec->exception();
396 if (exceptionValue)
397 return false;
399 r[baseDst] = thisObj;
400 r[funcDst] = result;
401 return true;
403 ++iter;
404 } while (iter != end);
406 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
407 return false;
410 ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
412 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
413 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
414 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
415 callFrame[RegisterFile::CallerRegisters] = r;
416 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
417 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
418 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
419 callFrame[RegisterFile::CalledAsConstructor] = calledAsConstructor;
420 callFrame[RegisterFile::Callee] = function;
421 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
424 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
426 size_t registerOffset = argv + newCodeBlock->numLocals;
427 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
429 if (argc == newCodeBlock->numParameters) { // correct number of arguments
430 if (!registerFile->grow(size)) {
431 exceptionValue = createStackOverflowError(exec);
432 return r;
434 r += registerOffset;
435 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
436 if (!registerFile->grow(size)) {
437 exceptionValue = createStackOverflowError(exec);
438 return r;
440 r += registerOffset;
442 int omittedArgCount = newCodeBlock->numParameters - argc;
443 Register* endOfParams = r - newCodeBlock->numVars;
444 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
445 (*it) = jsUndefined();
446 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
447 int shift = argc + RegisterFile::CallFrameHeaderSize;
448 registerOffset += shift;
449 size += shift;
451 if (!registerFile->grow(size)) {
452 exceptionValue = createStackOverflowError(exec);
453 return r;
455 r += registerOffset;
457 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
458 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
459 for ( ; it != end; ++it)
460 *(it + shift) = *it;
463 // initialize local variable slots
464 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
465 (*it) = jsUndefined();
468 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
469 r[i] = newCodeBlock->constantRegisters[i];
471 return r;
474 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
476 if (newCodeBlock->needsFullScopeChain) {
477 JSActivation* activation = new (exec) JSActivation(functionBodyNode, r);
478 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
480 return callDataScopeChain->copy()->push(activation);
483 return callDataScopeChain;
486 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
488 if (value->isObject())
489 return false;
490 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
491 return true;
494 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
496 if (argc < 2)
497 return jsUndefined();
499 JSValue* program = r[argv + 1].jsValue(exec);
501 if (!program->isString())
502 return program;
504 Profiler** profiler = Profiler::enabledProfilerReference();
505 if (*profiler)
506 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
508 int sourceId;
509 int errLine;
510 UString errMsg;
511 RefPtr<EvalNode> evalNode = exec->parser()->parse<EvalNode>(exec, UString(), 1, UStringSourceProvider::create(static_cast<JSString*>(program)->value()), &sourceId, &errLine, &errMsg);
513 if (!evalNode) {
514 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
515 if (*profiler)
516 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
517 return 0;
520 JSValue* result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
522 if (*profiler)
523 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
525 return result;
528 Machine::Machine()
529 : m_sampler(0)
530 , m_reentryDepth(0)
531 , m_timeoutTime(0)
532 , m_timeAtLastCheckTimeout(0)
533 , m_timeExecuting(0)
534 , m_timeoutCheckCount(0)
535 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
537 privateExecute(InitializeAndReturn);
539 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
540 void* storage = fastMalloc(sizeof(CollectorBlock));
542 JSArray* jsArray = new (storage) JSArray(jsNull(), 0);
543 m_jsArrayVptr = jsArray->vptr();
544 static_cast<JSCell*>(jsArray)->~JSCell();
546 JSString* jsString = new (storage) JSString("");
547 m_jsStringVptr = jsString->vptr();
548 static_cast<JSCell*>(jsString)->~JSCell();
550 fastFree(storage);
553 #ifndef NDEBUG
555 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
557 ScopeChain sc(scopeChain);
558 JSGlobalObject* globalObject = sc.globalObject();
559 codeBlock->dump(globalObject->globalExec());
560 dumpRegisters(codeBlock, registerFile, r);
563 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
565 printf("Register frame: \n\n");
566 printf("----------------------------------------------------\n");
567 printf(" use | address | value \n");
568 printf("----------------------------------------------------\n");
570 const Register* it;
571 const Register* end;
573 if (codeBlock->codeType == GlobalCode) {
574 it = registerFile->lastGlobal();
575 end = it + registerFile->numGlobals();
576 while (it != end) {
577 printf("[global var] | %10p | %10p \n", it, (*it).v());
578 ++it;
580 printf("----------------------------------------------------\n");
583 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
584 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
585 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
586 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
587 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
588 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
589 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
590 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
591 printf("[CalledAsConstructor] | %10p | %10p \n", it, (*it).v()); ++it;
592 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
593 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
594 printf("----------------------------------------------------\n");
596 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
597 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
598 if (it != end) {
599 do {
600 printf("[param] | %10p | %10p \n", it, (*it).v());
601 ++it;
602 } while (it != end);
604 printf("----------------------------------------------------\n");
606 if (codeBlock->codeType != GlobalCode) {
607 end = it + codeBlock->numVars;
608 if (it != end) {
609 do {
610 printf("[var] | %10p | %10p \n", it, (*it).v());
611 ++it;
612 } while (it != end);
613 printf("----------------------------------------------------\n");
617 end = it + codeBlock->numTemporaries;
618 if (it != end) {
619 do {
620 printf("[temp] | %10p | %10p \n", it, (*it).v());
621 ++it;
622 } while (it != end);
626 #endif
628 #if !defined(NDEBUG) || HAVE(SAMPLING_TOOL)
630 bool Machine::isOpcode(Opcode opcode)
632 #if HAVE(COMPUTED_GOTO)
633 return opcode != HashTraits<Opcode>::emptyValue()
634 && !HashTraits<Opcode>::isDeletedValue(opcode)
635 && m_opcodeIDTable.contains(opcode);
636 #else
637 return opcode >= 0 && opcode <= op_end;
638 #endif
641 #endif
643 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
645 CodeBlock* oldCodeBlock = codeBlock;
646 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
648 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
649 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
650 if (callFrame[RegisterFile::Callee].jsValue(exec))
651 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
652 else
653 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
656 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
657 if (callFrame[RegisterFile::Callee].jsValue(exec))
658 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
659 else
660 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
663 if (oldCodeBlock->needsFullScopeChain)
664 scopeChain->deref();
666 // If this call frame created an activation, tear it off.
667 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
668 ASSERT(activation->isActivationObject());
669 activation->copyRegisters();
672 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
673 if (!codeBlock)
674 return false;
676 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
677 r = callFrame[RegisterFile::CallerRegisters].r();
678 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
679 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
681 return true;
684 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
686 // Set up the exception object
688 if (exceptionValue->isObject()) {
689 JSObject* exception = static_cast<JSObject*>(exceptionValue);
690 if (exception->isNotAnObjectErrorStub()) {
691 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
692 exceptionValue = exception;
693 } else {
694 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
695 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
696 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
697 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
698 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
699 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
700 if (explicitThrow) {
701 int startOffset = 0;
702 int endOffset = 0;
703 int divotPoint = 0;
704 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
705 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
707 // We only hit this path for error messages and throw statements, which don't have a specific failure position
708 // So we just give the full range of the error/throw statement.
709 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
710 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
711 } else
712 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
713 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
714 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
717 if (exception->isWatchdogException()) {
718 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
719 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
721 return 0;
726 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
727 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
728 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
731 // Calculate an exception handler vPC, unwinding call frames as necessary.
733 int scopeDepth;
734 Instruction* handlerVPC;
736 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
737 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
738 return 0;
741 // Now unwind the scope chain within the exception handler's call frame.
743 ScopeChain sc(scopeChain);
744 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
745 ASSERT(scopeDelta >= 0);
746 while (scopeDelta--)
747 sc.pop();
748 setScopeChain(exec, scopeChain, sc.node());
750 return handlerVPC;
753 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
755 if (m_reentryDepth >= MaxReentryDepth) {
756 *exception = createStackOverflowError(exec);
757 return 0;
760 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
762 size_t oldSize = m_registerFile.size();
763 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
764 if (!m_registerFile.grow(newSize)) {
765 *exception = createStackOverflowError(exec);
766 return 0;
769 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
770 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
771 globalObject->copyGlobalsTo(m_registerFile);
773 Register* callFrame = m_registerFile.base() + oldSize;
775 // a 0 codeBlock indicates a built-in caller
776 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
778 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
779 r[codeBlock->thisRegister] = thisObj;
781 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
782 r[i] = codeBlock->constantRegisters[i];
784 if (codeBlock->needsFullScopeChain)
785 scopeChain = scopeChain->copy();
787 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
789 Profiler** profiler = Profiler::enabledProfilerReference();
790 if (*profiler)
791 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
793 m_reentryDepth++;
794 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
795 m_reentryDepth--;
797 MACHINE_SAMPLING_privateExecuteReturned();
799 if (*profiler) {
800 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
801 if (!m_reentryDepth)
802 (*profiler)->didFinishAllExecution(exec);
805 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
806 lastGlobalObject->copyGlobalsTo(m_registerFile);
808 m_registerFile.shrink(oldSize);
809 return result;
812 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
814 if (m_reentryDepth >= MaxReentryDepth) {
815 *exception = createStackOverflowError(exec);
816 return 0;
819 int argv = RegisterFile::CallFrameHeaderSize;
820 int argc = args.size() + 1; // implicit "this" parameter
822 size_t oldSize = m_registerFile.size();
823 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
824 *exception = createStackOverflowError(exec);
825 return 0;
828 Register* callFrame = m_registerFile.base() + oldSize;
830 // put args in place, including "this"
831 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
832 (*dst) = thisObj;
834 ArgList::const_iterator end = args.end();
835 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
836 (*++dst) = *it;
838 // a 0 codeBlock indicates a built-in caller
839 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, 0, function);
841 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
842 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
843 if (*exception) {
844 m_registerFile.shrink(oldSize);
845 return 0;
848 scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r);
850 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
852 Profiler** profiler = Profiler::enabledProfilerReference();
853 if (*profiler)
854 (*profiler)->willExecute(exec, function);
856 m_reentryDepth++;
857 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
858 m_reentryDepth--;
860 MACHINE_SAMPLING_privateExecuteReturned();
862 if (*profiler && !m_reentryDepth)
863 (*profiler)->didFinishAllExecution(exec);
865 m_registerFile.shrink(oldSize);
866 return result;
869 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
871 if (m_reentryDepth >= MaxReentryDepth) {
872 *exception = createStackOverflowError(exec);
873 return 0;
876 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
878 JSVariableObject* variableObject;
879 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
880 ASSERT(node);
881 if (node->object->isVariableObject()) {
882 variableObject = static_cast<JSVariableObject*>(node->object);
883 break;
887 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
888 Node::VarStack::const_iterator varStackEnd = varStack.end();
889 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
890 const Identifier& ident = (*it).first;
891 if (!variableObject->hasProperty(exec, ident))
892 variableObject->put(exec, ident, jsUndefined());
895 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
896 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
897 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it)
898 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain));
900 size_t oldSize = m_registerFile.size();
901 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
902 if (!m_registerFile.grow(newSize)) {
903 *exception = createStackOverflowError(exec);
904 return 0;
907 Register* callFrame = m_registerFile.base() + registerOffset;
909 // a 0 codeBlock indicates a built-in caller
910 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
912 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
913 r[codeBlock->thisRegister] = thisObj;
915 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
916 r[i] = codeBlock->constantRegisters[i];
918 if (codeBlock->needsFullScopeChain)
919 scopeChain = scopeChain->copy();
921 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
923 Profiler** profiler = Profiler::enabledProfilerReference();
924 if (*profiler)
925 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
927 m_reentryDepth++;
928 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
929 m_reentryDepth--;
931 MACHINE_SAMPLING_privateExecuteReturned();
933 if (*profiler) {
934 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
935 if (!m_reentryDepth)
936 (*profiler)->didFinishAllExecution(exec);
939 m_registerFile.shrink(oldSize);
940 return result;
943 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
945 scopeChain = newScopeChain;
946 exec->m_scopeChain = newScopeChain;
949 NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r)
951 int debugHookID = (++vPC)->u.operand;
952 int firstLine = (++vPC)->u.operand;
953 int lastLine = (++vPC)->u.operand;
955 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
956 if (!debugger)
957 return;
959 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
961 switch((DebugHookID)debugHookID) {
962 case DidEnterCallFrame: {
963 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
964 return;
966 case WillLeaveCallFrame: {
967 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
968 return;
970 case WillExecuteStatement: {
971 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
972 return;
974 case WillExecuteProgram: {
975 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
976 return;
978 case DidExecuteProgram: {
979 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
980 return;
982 case DidReachBreakpoint: {
983 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
984 return;
989 void Machine::resetTimeoutCheck()
991 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
992 m_timeAtLastCheckTimeout = 0;
993 m_timeExecuting = 0;
996 // Returns the time the current thread has spent executing, in milliseconds.
997 static inline unsigned getCPUTime()
999 #if PLATFORM(DARWIN)
1000 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1001 thread_basic_info_data_t info;
1003 // Get thread information
1004 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1006 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1007 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1009 return time;
1010 #elif HAVE(SYS_TIME_H)
1011 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1012 struct timeval tv;
1013 gettimeofday(&tv, 0);
1014 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1015 #elif PLATFORM(QT)
1016 QDateTime t = QDateTime::currentDateTime();
1017 return t.toTime_t() * 1000 + t.time().msec();
1018 #elif PLATFORM(WIN_OS)
1019 union {
1020 FILETIME fileTime;
1021 unsigned long long fileTimeAsLong;
1022 } userTime, kernelTime;
1024 // GetThreadTimes won't accept NULL arguments so we pass these even though
1025 // they're not used.
1026 FILETIME creationTime, exitTime;
1028 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1030 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1031 #else
1032 #error Platform does not have getCurrentTime function
1033 #endif
1036 // We have to return a JSValue here, gcc seems to produce worse code if
1037 // we attempt to return a bool
1038 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1040 unsigned currentTime = getCPUTime();
1042 if (!m_timeAtLastCheckTimeout) {
1043 // Suspicious amount of looping in a script -- start timing it
1044 m_timeAtLastCheckTimeout = currentTime;
1045 return 0;
1048 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1050 if (timeDiff == 0)
1051 timeDiff = 1;
1053 m_timeExecuting += timeDiff;
1054 m_timeAtLastCheckTimeout = currentTime;
1056 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1057 // preferredScriptCheckTimeInterval
1058 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1059 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1060 // preferred script check time interval.
1061 if (m_ticksUntilNextTimeoutCheck == 0)
1062 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1064 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1065 if (globalObject->shouldInterruptScript())
1066 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1068 resetTimeoutCheck();
1071 return 0;
1074 static int32_t offsetForStringSwitch(StringJumpTable& jumpTable, JSValue* scrutinee, int32_t defaultOffset) {
1075 StringJumpTable::const_iterator end = jumpTable.end();
1076 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
1077 StringJumpTable::const_iterator loc = jumpTable.find(value);
1078 if (loc == end)
1079 return defaultOffset;
1080 return loc->second;
1083 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1085 int dst = (++vPC)->u.operand;
1086 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1087 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1088 JSObject* scope = new (exec) JSStaticScopeObject(property, value, DontDelete);
1089 r[dst] = scope;
1090 return scopeChain->push(scope);
1093 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1095 // One-time initialization of our address tables. We have to put this code
1096 // here because our labels are only in scope inside this function.
1097 if (flag == InitializeAndReturn) {
1098 #if HAVE(COMPUTED_GOTO)
1099 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1100 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1101 #undef ADD_OPCODE
1103 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1104 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1105 #undef ADD_OPCODE_ID
1106 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1107 op_throw_end_indirect = &&op_throw_end;
1108 op_call_indirect = &&op_call;
1109 #endif // HAVE(COMPUTED_GOTO)
1110 return 0;
1113 JSValue* exceptionValue = 0;
1114 Instruction* handlerVPC = 0;
1116 Register* registerBase = registerFile->base();
1117 Instruction* vPC = codeBlock->instructions.begin();
1118 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1119 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1121 #define VM_CHECK_EXCEPTION() \
1122 do { \
1123 if (UNLIKELY(exec->hadException())) { \
1124 exceptionValue = exec->exception(); \
1125 goto vm_throw; \
1127 } while (0)
1129 #if DUMP_OPCODE_STATS
1130 OpcodeStats::resetLastInstruction();
1131 #endif
1133 #define CHECK_FOR_TIMEOUT() \
1134 if (!--tickCount) { \
1135 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1136 goto vm_throw; \
1137 tickCount = m_ticksUntilNextTimeoutCheck; \
1140 #if HAVE(COMPUTED_GOTO)
1141 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1142 #if DUMP_OPCODE_STATS
1143 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1144 #else
1145 #define BEGIN_OPCODE(opcode) opcode:
1146 #endif
1147 NEXT_OPCODE;
1148 #else
1149 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1150 #if DUMP_OPCODE_STATS
1151 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1152 #else
1153 #define BEGIN_OPCODE(opcode) case opcode:
1154 #endif
1155 while (1) // iterator loop begins
1156 switch (vPC->u.opcode)
1157 #endif
1159 BEGIN_OPCODE(op_new_object) {
1160 /* new_object dst(r)
1162 Constructs a new empty Object instance using the original
1163 constructor, and puts the result in register dst.
1165 int dst = (++vPC)->u.operand;
1166 r[dst] = constructEmptyObject(exec);
1168 ++vPC;
1169 NEXT_OPCODE;
1171 BEGIN_OPCODE(op_new_array) {
1172 /* new_array dst(r) firstArg(r) argCount(n)
1174 Constructs a new Array instance using the original
1175 constructor, and puts the result in register dst.
1176 The array will contain argCount elements with values
1177 taken from registers starting at register firstArg.
1179 int dst = (++vPC)->u.operand;
1180 int firstArg = (++vPC)->u.operand;
1181 int argCount = (++vPC)->u.operand;
1182 ArgList args(r + firstArg, argCount);
1183 r[dst] = constructArray(exec, args);
1185 ++vPC;
1186 NEXT_OPCODE;
1188 BEGIN_OPCODE(op_new_regexp) {
1189 /* new_regexp dst(r) regExp(re)
1191 Constructs a new RegExp instance using the original
1192 constructor from regexp regExp, and puts the result in
1193 register dst.
1195 int dst = (++vPC)->u.operand;
1196 int regExp = (++vPC)->u.operand;
1197 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1199 ++vPC;
1200 NEXT_OPCODE;
1202 BEGIN_OPCODE(op_mov) {
1203 /* mov dst(r) src(r)
1205 Copies register src to register dst.
1207 int dst = (++vPC)->u.operand;
1208 int src = (++vPC)->u.operand;
1209 r[dst] = r[src];
1211 ++vPC;
1212 NEXT_OPCODE;
1214 BEGIN_OPCODE(op_eq) {
1215 /* eq dst(r) src1(r) src2(r)
1217 Checks whether register src1 and register src2 are equal,
1218 as with the ECMAScript '==' operator, and puts the result
1219 as a boolean in register dst.
1221 int dst = (++vPC)->u.operand;
1222 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1223 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1224 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1225 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1226 else {
1227 JSValue* result = jsBoolean(equal(exec, src1, src2));
1228 VM_CHECK_EXCEPTION();
1229 r[dst] = result;
1232 ++vPC;
1233 NEXT_OPCODE;
1235 BEGIN_OPCODE(op_neq) {
1236 /* neq dst(r) src1(r) src2(r)
1238 Checks whether register src1 and register src2 are not
1239 equal, as with the ECMAScript '!=' operator, and puts the
1240 result as a boolean in register dst.
1242 int dst = (++vPC)->u.operand;
1243 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1244 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1245 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1246 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1247 else {
1248 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1249 VM_CHECK_EXCEPTION();
1250 r[dst] = result;
1253 ++vPC;
1254 NEXT_OPCODE;
1256 BEGIN_OPCODE(op_stricteq) {
1257 /* stricteq dst(r) src1(r) src2(r)
1259 Checks whether register src1 and register src2 are strictly
1260 equal, as with the ECMAScript '===' operator, and puts the
1261 result as a boolean in register dst.
1263 int dst = (++vPC)->u.operand;
1264 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1265 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1266 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1267 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1268 else
1269 r[dst] = jsBoolean(strictEqual(src1, src2));
1271 ++vPC;
1272 NEXT_OPCODE;
1274 BEGIN_OPCODE(op_nstricteq) {
1275 /* nstricteq dst(r) src1(r) src2(r)
1277 Checks whether register src1 and register src2 are not
1278 strictly equal, as with the ECMAScript '!==' operator, and
1279 puts the result as a boolean in register dst.
1281 int dst = (++vPC)->u.operand;
1282 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1283 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1284 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1285 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1286 else
1287 r[dst] = jsBoolean(!strictEqual(src1, src2));
1289 ++vPC;
1290 NEXT_OPCODE;
1292 BEGIN_OPCODE(op_less) {
1293 /* less dst(r) src1(r) src2(r)
1295 Checks whether register src1 is less than register src2, as
1296 with the ECMAScript '<' operator, and puts the result as
1297 a boolean in register dst.
1299 int dst = (++vPC)->u.operand;
1300 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1301 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1302 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1303 VM_CHECK_EXCEPTION();
1304 r[dst] = result;
1306 ++vPC;
1307 NEXT_OPCODE;
1309 BEGIN_OPCODE(op_lesseq) {
1310 /* lesseq dst(r) src1(r) src2(r)
1312 Checks whether register src1 is less than or equal to
1313 register src2, as with the ECMAScript '<=' operator, and
1314 puts the result as a boolean in register dst.
1316 int dst = (++vPC)->u.operand;
1317 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1318 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1319 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1320 VM_CHECK_EXCEPTION();
1321 r[dst] = result;
1323 ++vPC;
1324 NEXT_OPCODE;
1326 BEGIN_OPCODE(op_pre_inc) {
1327 /* pre_inc srcDst(r)
1329 Converts register srcDst to number, adds one, and puts the result
1330 back in register srcDst.
1332 int srcDst = (++vPC)->u.operand;
1333 JSValue* v = r[srcDst].jsValue(exec);
1334 if (JSImmediate::canDoFastAdditiveOperations(v))
1335 r[srcDst] = JSImmediate::incImmediateNumber(v);
1336 else {
1337 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1338 VM_CHECK_EXCEPTION();
1339 r[srcDst] = result;
1342 ++vPC;
1343 NEXT_OPCODE;
1345 BEGIN_OPCODE(op_pre_dec) {
1346 /* pre_dec srcDst(r)
1348 Converts register srcDst to number, subtracts one, and puts the result
1349 back in register srcDst.
1351 int srcDst = (++vPC)->u.operand;
1352 JSValue* v = r[srcDst].jsValue(exec);
1353 if (JSImmediate::canDoFastAdditiveOperations(v))
1354 r[srcDst] = JSImmediate::decImmediateNumber(v);
1355 else {
1356 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1357 VM_CHECK_EXCEPTION();
1358 r[srcDst] = result;
1361 ++vPC;
1362 NEXT_OPCODE;
1364 BEGIN_OPCODE(op_post_inc) {
1365 /* post_inc dst(r) srcDst(r)
1367 Converts register srcDst to number. The number itself is
1368 written to register dst, and the number plus one is written
1369 back to register srcDst.
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::incImmediateNumber(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);
1384 ++vPC;
1385 NEXT_OPCODE;
1387 BEGIN_OPCODE(op_post_dec) {
1388 /* post_dec dst(r) srcDst(r)
1390 Converts register srcDst to number. The number itself is
1391 written to register dst, and the number minus one is written
1392 back to register srcDst.
1394 int dst = (++vPC)->u.operand;
1395 int srcDst = (++vPC)->u.operand;
1396 JSValue* v = r[srcDst].jsValue(exec);
1397 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1398 r[dst] = v;
1399 r[srcDst] = JSImmediate::decImmediateNumber(v);
1400 } else {
1401 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1402 VM_CHECK_EXCEPTION();
1403 r[dst] = number;
1404 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1407 ++vPC;
1408 NEXT_OPCODE;
1410 BEGIN_OPCODE(op_to_jsnumber) {
1411 /* to_jsnumber dst(r) src(r)
1413 Converts register src to number, and puts the result
1414 in register dst.
1416 int dst = (++vPC)->u.operand;
1417 int src = (++vPC)->u.operand;
1418 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1419 VM_CHECK_EXCEPTION();
1421 r[dst] = result;
1423 ++vPC;
1424 NEXT_OPCODE;
1426 BEGIN_OPCODE(op_negate) {
1427 /* negate dst(r) src(r)
1429 Converts register src to number, negates it, and puts the
1430 result in register dst.
1432 int dst = (++vPC)->u.operand;
1433 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1434 double v;
1435 if (fastIsNumber(src, v))
1436 r[dst] = jsNumber(exec, -v);
1437 else {
1438 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1439 VM_CHECK_EXCEPTION();
1440 r[dst] = result;
1443 ++vPC;
1444 NEXT_OPCODE;
1446 BEGIN_OPCODE(op_add) {
1447 /* add dst(r) src1(r) src2(r)
1449 Adds register src1 and register src2, and puts the result
1450 in register dst. (JS add may be string concatenation or
1451 numeric add, depending on the types of the operands.)
1453 int dst = (++vPC)->u.operand;
1454 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1455 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1456 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1457 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1458 else {
1459 JSValue* result = jsAdd(exec, src1, src2);
1460 VM_CHECK_EXCEPTION();
1461 r[dst] = result;
1463 ++vPC;
1464 NEXT_OPCODE;
1466 BEGIN_OPCODE(op_mul) {
1467 /* mul dst(r) src1(r) src2(r)
1469 Multiplies register src1 and register src2 (converted to
1470 numbers), and puts the product in register dst.
1472 int dst = (++vPC)->u.operand;
1473 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1474 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1475 double left;
1476 double right;
1477 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1478 r[dst] = jsNumber(exec, left * right);
1479 else {
1480 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1481 VM_CHECK_EXCEPTION();
1482 r[dst] = result;
1485 ++vPC;
1486 NEXT_OPCODE;
1488 BEGIN_OPCODE(op_div) {
1489 /* div dst(r) dividend(r) divisor(r)
1491 Divides register dividend (converted to number) by the
1492 register divisor (converted to number), and puts the
1493 quotient in register dst.
1495 int dst = (++vPC)->u.operand;
1496 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1497 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1498 double left;
1499 double right;
1500 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1501 r[dst] = jsNumber(exec, left / right);
1502 else {
1503 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1504 VM_CHECK_EXCEPTION();
1505 r[dst] = result;
1507 ++vPC;
1508 NEXT_OPCODE;
1510 BEGIN_OPCODE(op_mod) {
1511 /* mod dst(r) dividend(r) divisor(r)
1513 Divides register dividend (converted to number) by
1514 register divisor (converted to number), and puts the
1515 remainder in register dst.
1517 int dst = (++vPC)->u.operand;
1518 int dividend = (++vPC)->u.operand;
1519 int divisor = (++vPC)->u.operand;
1521 JSValue* dividendValue = r[dividend].jsValue(exec);
1522 JSValue* divisorValue = r[divisor].jsValue(exec);
1524 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1525 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1526 ++vPC;
1527 NEXT_OPCODE;
1530 double d = dividendValue->toNumber(exec);
1531 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1532 VM_CHECK_EXCEPTION();
1533 r[dst] = result;
1534 ++vPC;
1535 NEXT_OPCODE;
1537 BEGIN_OPCODE(op_sub) {
1538 /* sub dst(r) src1(r) src2(r)
1540 Subtracts register src2 (converted to number) from register
1541 src1 (converted to number), and puts the difference in
1542 register dst.
1544 int dst = (++vPC)->u.operand;
1545 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1546 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1547 double left;
1548 double right;
1549 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1550 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1551 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1552 r[dst] = jsNumber(exec, left - right);
1553 else {
1554 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1555 VM_CHECK_EXCEPTION();
1556 r[dst] = result;
1558 ++vPC;
1559 NEXT_OPCODE;
1561 BEGIN_OPCODE(op_lshift) {
1562 /* lshift dst(r) val(r) shift(r)
1564 Performs left shift of register val (converted to int32) by
1565 register shift (converted to uint32), and puts the result
1566 in register dst.
1568 int dst = (++vPC)->u.operand;
1569 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1570 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1571 int32_t left;
1572 uint32_t right;
1573 if (JSImmediate::areBothImmediateNumbers(val, shift))
1574 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1575 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1576 r[dst] = jsNumber(exec, left << (right & 0x1f));
1577 else {
1578 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1579 VM_CHECK_EXCEPTION();
1580 r[dst] = result;
1583 ++vPC;
1584 NEXT_OPCODE;
1586 BEGIN_OPCODE(op_rshift) {
1587 /* rshift dst(r) val(r) shift(r)
1589 Performs arithmetic right shift of register val (converted
1590 to int32) by register shift (converted to
1591 uint32), and puts the result in register dst.
1593 int dst = (++vPC)->u.operand;
1594 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1595 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1596 int32_t left;
1597 uint32_t right;
1598 if (JSImmediate::areBothImmediateNumbers(val, shift))
1599 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1600 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1601 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1602 else {
1603 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1604 VM_CHECK_EXCEPTION();
1605 r[dst] = result;
1608 ++vPC;
1609 NEXT_OPCODE;
1611 BEGIN_OPCODE(op_urshift) {
1612 /* rshift dst(r) val(r) shift(r)
1614 Performs logical right shift of register val (converted
1615 to uint32) by register shift (converted to
1616 uint32), and puts the result in register dst.
1618 int dst = (++vPC)->u.operand;
1619 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1620 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1621 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1622 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1623 else {
1624 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1625 VM_CHECK_EXCEPTION();
1626 r[dst] = result;
1629 ++vPC;
1630 NEXT_OPCODE;
1632 BEGIN_OPCODE(op_bitand) {
1633 /* bitand dst(r) src1(r) src2(r)
1635 Computes bitwise AND of register src1 (converted to int32)
1636 and register src2 (converted to int32), and puts the result
1637 in register dst.
1639 int dst = (++vPC)->u.operand;
1640 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1641 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1642 int32_t left;
1643 int32_t right;
1644 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1645 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1646 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1647 r[dst] = jsNumber(exec, left & right);
1648 else {
1649 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
1650 VM_CHECK_EXCEPTION();
1651 r[dst] = result;
1654 ++vPC;
1655 NEXT_OPCODE;
1657 BEGIN_OPCODE(op_bitxor) {
1658 /* bitxor dst(r) src1(r) src2(r)
1660 Computes bitwise XOR of register src1 (converted to int32)
1661 and register src2 (converted to int32), and puts the result
1662 in register dst.
1664 int dst = (++vPC)->u.operand;
1665 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1666 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1667 int32_t left;
1668 int32_t right;
1669 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1670 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
1671 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1672 r[dst] = jsNumber(exec, left ^ right);
1673 else {
1674 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
1675 VM_CHECK_EXCEPTION();
1676 r[dst] = result;
1679 ++vPC;
1680 NEXT_OPCODE;
1682 BEGIN_OPCODE(op_bitor) {
1683 /* bitor dst(r) src1(r) src2(r)
1685 Computes bitwise OR of register src1 (converted to int32)
1686 and register src2 (converted to int32), and puts the
1687 result in register dst.
1689 int dst = (++vPC)->u.operand;
1690 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1691 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1692 int32_t left;
1693 int32_t right;
1694 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1695 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
1696 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1697 r[dst] = jsNumber(exec, left | right);
1698 else {
1699 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
1700 VM_CHECK_EXCEPTION();
1701 r[dst] = result;
1704 ++vPC;
1705 NEXT_OPCODE;
1707 BEGIN_OPCODE(op_bitnot) {
1708 /* bitnot dst(r) src(r)
1710 Computes bitwise NOT of register src1 (converted to int32),
1711 and puts the result in register dst.
1713 int dst = (++vPC)->u.operand;
1714 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1715 int32_t value;
1716 if (fastToInt32(src, value))
1717 r[dst] = jsNumber(exec, ~value);
1718 else {
1719 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
1720 VM_CHECK_EXCEPTION();
1721 r[dst] = result;
1723 ++vPC;
1724 NEXT_OPCODE;
1726 BEGIN_OPCODE(op_not) {
1727 /* not dst(r) src(r)
1729 Computes logical NOT of register src (converted to
1730 boolean), and puts the result in register dst.
1732 int dst = (++vPC)->u.operand;
1733 int src = (++vPC)->u.operand;
1734 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
1735 VM_CHECK_EXCEPTION();
1736 r[dst] = result;
1738 ++vPC;
1739 NEXT_OPCODE;
1741 BEGIN_OPCODE(op_instanceof) {
1742 /* instanceof dst(r) value(r) constructor(r)
1744 Tests whether register value is an instance of register
1745 constructor, and puts the boolean result in register dst.
1747 Raises an exception if register constructor is not an
1748 object.
1750 int dst = (++vPC)->u.operand;
1751 int value = (++vPC)->u.operand;
1752 int base = (++vPC)->u.operand;
1754 JSValue* baseVal = r[base].jsValue(exec);
1756 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
1757 goto vm_throw;
1759 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1760 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec)) : false);
1762 ++vPC;
1763 NEXT_OPCODE;
1765 BEGIN_OPCODE(op_typeof) {
1766 /* typeof dst(r) src(r)
1768 Determines the type string for src according to ECMAScript
1769 rules, and puts the result in register dst.
1771 int dst = (++vPC)->u.operand;
1772 int src = (++vPC)->u.operand;
1773 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
1775 ++vPC;
1776 NEXT_OPCODE;
1778 BEGIN_OPCODE(op_in) {
1779 /* in dst(r) property(r) base(r)
1781 Tests whether register base has a property named register
1782 property, and puts the boolean result in register dst.
1784 Raises an exception if register constructor is not an
1785 object.
1787 int dst = (++vPC)->u.operand;
1788 int property = (++vPC)->u.operand;
1789 int base = (++vPC)->u.operand;
1791 JSValue* baseVal = r[base].jsValue(exec);
1792 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
1793 goto vm_throw;
1795 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1797 JSValue* propName = r[property].jsValue(exec);
1799 uint32_t i;
1800 if (propName->getUInt32(i))
1801 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
1802 else {
1803 Identifier property(exec, propName->toString(exec));
1804 VM_CHECK_EXCEPTION();
1805 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
1808 ++vPC;
1809 NEXT_OPCODE;
1811 BEGIN_OPCODE(op_resolve) {
1812 /* resolve dst(r) property(id)
1814 Looks up the property named by identifier property in the
1815 scope chain, and writes the resulting value to register
1816 dst. If the property is not found, raises an exception.
1818 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1819 goto vm_throw;
1821 vPC += 3;
1822 NEXT_OPCODE;
1824 BEGIN_OPCODE(op_resolve_skip) {
1825 /* resolve_skip dst(r) property(id) skip(n)
1827 Looks up the property named by identifier property in the
1828 scope chain skipping the top 'skip' levels, and writes the resulting
1829 value to register dst. If the property is not found, raises an exception.
1831 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1832 goto vm_throw;
1834 vPC += 4;
1836 NEXT_OPCODE;
1838 BEGIN_OPCODE(op_get_scoped_var) {
1839 /* get_scoped_var dst(r) index(n) skip(n)
1841 Loads the contents of the index-th local from the scope skip nodes from
1842 the top of the scope chain, and places it in register dst
1844 int dst = (++vPC)->u.operand;
1845 int index = (++vPC)->u.operand;
1846 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1848 ScopeChainIterator iter = scopeChain->begin();
1849 ScopeChainIterator end = scopeChain->end();
1850 ASSERT(iter != end);
1851 while (skip--) {
1852 ++iter;
1853 ASSERT(iter != end);
1856 ASSERT((*iter)->isVariableObject());
1857 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1858 r[dst] = scope->registerAt(index);
1859 ++vPC;
1860 NEXT_OPCODE;
1862 BEGIN_OPCODE(op_put_scoped_var) {
1863 /* put_scoped_var index(n) skip(n) value(r)
1866 int index = (++vPC)->u.operand;
1867 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1868 int value = (++vPC)->u.operand;
1870 ScopeChainIterator iter = scopeChain->begin();
1871 ScopeChainIterator end = scopeChain->end();
1872 ASSERT(iter != end);
1873 while (skip--) {
1874 ++iter;
1875 ASSERT(iter != end);
1878 ASSERT((*iter)->isVariableObject());
1879 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1880 scope->registerAt(index) = r[value].jsValue(exec);
1881 ++vPC;
1882 NEXT_OPCODE;
1884 BEGIN_OPCODE(op_resolve_base) {
1885 /* resolve_base dst(r) property(id)
1887 Searches the scope chain for an object containing
1888 identifier property, and if one is found, writes it to
1889 register dst. If none is found, the outermost scope (which
1890 will be the global object) is stored in register dst.
1892 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1894 vPC += 3;
1895 NEXT_OPCODE;
1897 BEGIN_OPCODE(op_resolve_with_base) {
1898 /* resolve_with_base baseDst(r) propDst(r) property(id)
1900 Searches the scope chain for an object containing
1901 identifier property, and if one is found, writes it to
1902 register srcDst, and the retrieved property value to register
1903 propDst. If the property is not found, raises an exception.
1905 This is more efficient than doing resolve_base followed by
1906 resolve, or resolve_base followed by get_by_id, as it
1907 avoids duplicate hash lookups.
1909 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1910 goto vm_throw;
1912 vPC += 4;
1913 NEXT_OPCODE;
1915 BEGIN_OPCODE(op_resolve_func) {
1916 /* resolve_func baseDst(r) funcDst(r) property(id)
1918 Searches the scope chain for an object containing
1919 identifier property, and if one is found, writes the
1920 appropriate object to use as "this" when calling its
1921 properties to register baseDst; and the retrieved property
1922 value to register propDst. If the property is not found,
1923 raises an exception.
1925 This differs from resolve_with_base, because the
1926 global this value will be substituted for activations or
1927 the global object, which is the right behavior for function
1928 calls but not for other property lookup.
1930 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1931 goto vm_throw;
1933 vPC += 4;
1934 NEXT_OPCODE;
1936 BEGIN_OPCODE(op_get_by_id) {
1937 /* get_by_id dst(r) base(r) property(id)
1939 Converts register base to Object, gets the property
1940 named by identifier property from the object, and puts the
1941 result in register dst.
1943 int dst = (++vPC)->u.operand;
1944 int base = (++vPC)->u.operand;
1945 int property = (++vPC)->u.operand;
1947 Identifier& ident = codeBlock->identifiers[property];
1948 JSValue* result = r[base].jsValue(exec)->get(exec, ident);
1949 VM_CHECK_EXCEPTION();
1950 r[dst] = result;
1951 ++vPC;
1952 NEXT_OPCODE;
1954 BEGIN_OPCODE(op_put_by_id) {
1955 /* put_by_id base(r) property(id) value(r)
1957 Sets register value on register base as the property named
1958 by identifier property. Base is converted to object first.
1960 Unlike many opcodes, this one does not write any output to
1961 the register file.
1963 int base = (++vPC)->u.operand;
1964 int property = (++vPC)->u.operand;
1965 int value = (++vPC)->u.operand;
1967 Identifier& ident = codeBlock->identifiers[property];
1968 r[base].jsValue(exec)->put(exec, ident, r[value].jsValue(exec));
1970 VM_CHECK_EXCEPTION();
1971 ++vPC;
1972 NEXT_OPCODE;
1974 BEGIN_OPCODE(op_del_by_id) {
1975 /* del_by_id dst(r) base(r) property(id)
1977 Converts register base to Object, deletes the property
1978 named by identifier property from the object, and writes a
1979 boolean indicating success (if true) or failure (if false)
1980 to register dst.
1982 int dst = (++vPC)->u.operand;
1983 int base = (++vPC)->u.operand;
1984 int property = (++vPC)->u.operand;
1986 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
1988 Identifier& ident = codeBlock->identifiers[property];
1989 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1990 VM_CHECK_EXCEPTION();
1991 r[dst] = result;
1992 ++vPC;
1993 NEXT_OPCODE;
1995 BEGIN_OPCODE(op_get_by_val) {
1996 /* get_by_val dst(r) base(r) property(r)
1998 Converts register base to Object, gets the property named
1999 by register property from the object, and puts the result
2000 in register dst. property is nominally converted to string
2001 but numbers are treated more efficiently.
2003 int dst = (++vPC)->u.operand;
2004 int base = (++vPC)->u.operand;
2005 int property = (++vPC)->u.operand;
2007 JSValue* baseValue = r[base].jsValue(exec);
2008 JSValue* subscript = r[property].jsValue(exec);
2010 JSValue* result;
2011 unsigned i;
2013 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2014 if (LIKELY(isUInt32)) {
2015 if (isJSArray(baseValue)) {
2016 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2017 if (jsArray->canGetIndex(i))
2018 result = jsArray->getIndex(i);
2019 else
2020 result = jsArray->JSArray::get(exec, i);
2021 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2022 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2023 else
2024 result = baseValue->get(exec, i);
2025 } else {
2026 Identifier property(exec, subscript->toString(exec));
2027 result = baseValue->get(exec, property);
2030 VM_CHECK_EXCEPTION();
2031 r[dst] = result;
2032 ++vPC;
2033 NEXT_OPCODE;
2035 BEGIN_OPCODE(op_put_by_val) {
2036 /* put_by_val base(r) property(r) value(r)
2038 Sets register value on register base as the property named
2039 by register property. Base is converted to object
2040 first. register property is nominally converted to string
2041 but numbers are treated more efficiently.
2043 Unlike many opcodes, this one does not write any output to
2044 the register file.
2046 int base = (++vPC)->u.operand;
2047 int property = (++vPC)->u.operand;
2048 int value = (++vPC)->u.operand;
2050 JSValue* baseValue = r[base].jsValue(exec);
2051 JSValue* subscript = r[property].jsValue(exec);
2053 unsigned i;
2055 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2056 if (LIKELY(isUInt32)) {
2057 if (isJSArray(baseValue)) {
2058 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2059 if (jsArray->canSetIndex(i))
2060 jsArray->setIndex(i, r[value].jsValue(exec));
2061 else
2062 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2063 } else
2064 baseValue->put(exec, i, r[value].jsValue(exec));
2065 } else {
2066 Identifier property(exec, subscript->toString(exec));
2067 if (!exec->hadException()) // Don't put to an object if toString threw an exception.
2068 baseValue->put(exec, property, r[value].jsValue(exec));
2071 VM_CHECK_EXCEPTION();
2072 ++vPC;
2073 NEXT_OPCODE;
2075 BEGIN_OPCODE(op_del_by_val) {
2076 /* del_by_val dst(r) base(r) property(r)
2078 Converts register base to Object, deletes the property
2079 named by register property from the object, and writes a
2080 boolean indicating success (if true) or failure (if false)
2081 to register dst.
2083 int dst = (++vPC)->u.operand;
2084 int base = (++vPC)->u.operand;
2085 int property = (++vPC)->u.operand;
2087 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2089 JSValue* subscript = r[property].jsValue(exec);
2090 JSValue* result;
2091 uint32_t i;
2092 if (subscript->getUInt32(i))
2093 result = jsBoolean(baseObj->deleteProperty(exec, i));
2094 else {
2095 VM_CHECK_EXCEPTION();
2096 Identifier property(exec, subscript->toString(exec));
2097 VM_CHECK_EXCEPTION();
2098 result = jsBoolean(baseObj->deleteProperty(exec, property));
2101 VM_CHECK_EXCEPTION();
2102 r[dst] = result;
2103 ++vPC;
2104 NEXT_OPCODE;
2106 BEGIN_OPCODE(op_put_by_index) {
2107 /* put_by_index base(r) property(n) value(r)
2109 Sets register value on register base as the property named
2110 by the immediate number property. Base is converted to
2111 object first.
2113 Unlike many opcodes, this one does not write any output to
2114 the register file.
2116 This opcode is mainly used to initialize array literals.
2118 int base = (++vPC)->u.operand;
2119 unsigned property = (++vPC)->u.operand;
2120 int value = (++vPC)->u.operand;
2122 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2124 ++vPC;
2125 NEXT_OPCODE;
2127 BEGIN_OPCODE(op_loop) {
2128 /* loop target(offset)
2130 Jumps unconditionally to offset target from the current
2131 instruction.
2133 Additionally this loop instruction may terminate JS execution is
2134 the JS timeout is reached.
2136 #if DUMP_OPCODE_STATS
2137 OpcodeStats::resetLastInstruction();
2138 #endif
2139 int target = (++vPC)->u.operand;
2140 CHECK_FOR_TIMEOUT();
2141 vPC += target;
2142 NEXT_OPCODE;
2144 BEGIN_OPCODE(op_jmp) {
2145 /* jmp target(offset)
2147 Jumps unconditionally to offset target from the current
2148 instruction.
2150 #if DUMP_OPCODE_STATS
2151 OpcodeStats::resetLastInstruction();
2152 #endif
2153 int target = (++vPC)->u.operand;
2155 vPC += target;
2156 NEXT_OPCODE;
2158 BEGIN_OPCODE(op_loop_if_true) {
2159 /* loop_if_true cond(r) target(offset)
2161 Jumps to offset target from the current instruction, if and
2162 only if register cond converts to boolean as true.
2164 Additionally this loop instruction may terminate JS execution is
2165 the JS timeout is reached.
2167 int cond = (++vPC)->u.operand;
2168 int target = (++vPC)->u.operand;
2169 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2170 vPC += target;
2171 CHECK_FOR_TIMEOUT();
2172 NEXT_OPCODE;
2175 ++vPC;
2176 NEXT_OPCODE;
2178 BEGIN_OPCODE(op_jtrue) {
2179 /* jtrue cond(r) target(offset)
2181 Jumps to offset target from the current instruction, if and
2182 only if register cond converts to boolean as true.
2184 int cond = (++vPC)->u.operand;
2185 int target = (++vPC)->u.operand;
2186 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2187 vPC += target;
2188 NEXT_OPCODE;
2191 ++vPC;
2192 NEXT_OPCODE;
2194 BEGIN_OPCODE(op_jfalse) {
2195 /* jfalse cond(r) target(offset)
2197 Jumps to offset target from the current instruction, if and
2198 only if register cond converts to boolean as false.
2200 int cond = (++vPC)->u.operand;
2201 int target = (++vPC)->u.operand;
2202 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2203 vPC += target;
2204 NEXT_OPCODE;
2207 ++vPC;
2208 NEXT_OPCODE;
2210 BEGIN_OPCODE(op_loop_if_less) {
2211 /* loop_if_less src1(r) src2(r) target(offset)
2213 Checks whether register src1 is less than register src2, as
2214 with the ECMAScript '<' operator, and then jumps to offset
2215 target from the current instruction, if and only if the
2216 result of the comparison is true.
2218 Additionally this loop instruction may terminate JS execution is
2219 the JS timeout is reached.
2221 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2222 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2223 int target = (++vPC)->u.operand;
2225 bool result = jsLess(exec, src1, src2);
2226 VM_CHECK_EXCEPTION();
2228 if (result) {
2229 vPC += target;
2230 CHECK_FOR_TIMEOUT();
2231 NEXT_OPCODE;
2234 ++vPC;
2235 NEXT_OPCODE;
2237 BEGIN_OPCODE(op_jnless) {
2238 /* jnless src1(r) src2(r) target(offset)
2240 Checks whether register src1 is less than register src2, as
2241 with the ECMAScript '<' operator, and then jumps to offset
2242 target from the current instruction, if and only if the
2243 result of the comparison is false.
2245 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2246 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2247 int target = (++vPC)->u.operand;
2249 bool result = jsLess(exec, src1, src2);
2250 VM_CHECK_EXCEPTION();
2252 if (!result) {
2253 vPC += target;
2254 NEXT_OPCODE;
2257 ++vPC;
2258 NEXT_OPCODE;
2260 BEGIN_OPCODE(op_switch_imm) {
2261 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2263 Performs a range checked switch on the scrutinee value, using
2264 the tableIndex-th immediate switch jump table. If the scrutinee value
2265 is an immediate number in the range covered by the referenced jump
2266 table, and the value at jumpTable[scrutinee value] is non-zero, then
2267 that value is used as the jump offset, otherwise defaultOffset is used.
2269 int tableIndex = (++vPC)->u.operand;
2270 int defaultOffset = (++vPC)->u.operand;
2271 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2272 if (!JSImmediate::isNumber(scrutinee))
2273 vPC += defaultOffset;
2274 else {
2275 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
2276 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
2278 NEXT_OPCODE;
2280 BEGIN_OPCODE(op_switch_char) {
2281 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2283 Performs a range checked switch on the scrutinee value, using
2284 the tableIndex-th character switch jump table. If the scrutinee value
2285 is a single character string in the range covered by the referenced jump
2286 table, and the value at jumpTable[scrutinee value] is non-zero, then
2287 that value is used as the jump offset, otherwise defaultOffset is used.
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 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
2296 if (value->size() != 1)
2297 vPC += defaultOffset;
2298 else
2299 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
2301 NEXT_OPCODE;
2303 BEGIN_OPCODE(op_switch_string) {
2304 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2306 Performs a sparse hashmap based switch on the value in the scrutinee
2307 register, using the tableIndex-th string switch jump table. If the
2308 scrutinee value is a string that exists as a key in the referenced
2309 jump table, then the value associated with the string is used as the
2310 jump offset, otherwise defaultOffset is used.
2312 int tableIndex = (++vPC)->u.operand;
2313 int defaultOffset = (++vPC)->u.operand;
2314 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2315 if (!scrutinee->isString())
2316 vPC += defaultOffset;
2317 else
2318 vPC += offsetForStringSwitch(codeBlock->stringSwitchJumpTables[tableIndex], scrutinee, defaultOffset);
2319 NEXT_OPCODE;
2321 BEGIN_OPCODE(op_new_func) {
2322 /* new_func dst(r) func(f)
2324 Constructs a new Function instance from function func and
2325 the current scope chain using the original Function
2326 constructor, using the rules for function declarations, and
2327 puts the result in register dst.
2329 int dst = (++vPC)->u.operand;
2330 int func = (++vPC)->u.operand;
2332 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
2334 ++vPC;
2335 NEXT_OPCODE;
2337 BEGIN_OPCODE(op_new_func_exp) {
2338 /* new_func_exp dst(r) func(f)
2340 Constructs a new Function instance from function func and
2341 the current scope chain using the original Function
2342 constructor, using the rules for function expressions, and
2343 puts the result in register dst.
2345 int dst = (++vPC)->u.operand;
2346 int func = (++vPC)->u.operand;
2348 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
2350 ++vPC;
2351 NEXT_OPCODE;
2353 BEGIN_OPCODE(op_call_eval) {
2354 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2356 Call a function named "eval" with no explicit "this" value
2357 (which may therefore be the eval operator). If register
2358 thisVal is the global object, and register func contains
2359 that global object's original global eval function, then
2360 perform the eval operator in local scope (interpreting
2361 the argument registers as for the "call"
2362 opcode). Otherwise, act exactly as the "call" opcode would.
2365 int dst = (++vPC)->u.operand;
2366 int func = (++vPC)->u.operand;
2367 int thisVal = (++vPC)->u.operand;
2368 int firstArg = (++vPC)->u.operand;
2369 int argCount = (++vPC)->u.operand;
2371 JSValue* funcVal = r[func].jsValue(exec);
2372 JSValue* baseVal = r[thisVal].jsValue(exec);
2374 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
2375 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
2376 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
2377 if (exceptionValue)
2378 goto vm_throw;
2380 r[dst] = result;
2382 ++vPC;
2383 NEXT_OPCODE;
2386 // We didn't find the blessed version of eval, so reset vPC and process
2387 // this instruction as a normal function call, supplying the proper 'this'
2388 // value.
2389 vPC -= 5;
2390 r[thisVal] = baseVal->toThisObject(exec);
2392 #if HAVE(COMPUTED_GOTO)
2393 // Hack around gcc performance quirk by performing an indirect goto
2394 // in order to set the vPC -- attempting to do so directly results in a
2395 // significant regression.
2396 goto *op_call_indirect; // indirect goto -> op_call
2397 #endif
2398 // fall through to op_call
2400 BEGIN_OPCODE(op_call) {
2401 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2403 Perform a function call. Specifically, call register func
2404 with a "this" value of register thisVal, and put the result
2405 in register dst.
2407 The arguments start at register firstArg and go up to
2408 argCount, but the "this" value is considered an implicit
2409 first argument, so the argCount should be one greater than
2410 the number of explicit arguments passed, and the register
2411 after firstArg should contain the actual first
2412 argument. This opcode will copy from the thisVal register
2413 to the firstArg register, unless the register index of
2414 thisVal is the special missing this object marker, which is
2415 2^31-1; in that case, the global object will be used as the
2416 "this" value.
2418 If func is a native code function, then this opcode calls
2419 it and returns the value immediately.
2421 But if it is a JS function, then the current scope chain
2422 and code block is set to the function's, and we slide the
2423 register window so that the arguments would form the first
2424 few local registers of the called function's register
2425 window. In addition, a call frame header is written
2426 immediately before the arguments; see the call frame
2427 documentation for an explanation of how many registers a
2428 call frame takes and what they contain. That many registers
2429 before the firstArg register will be overwritten by the
2430 call. In addition, any registers higher than firstArg +
2431 argCount may be overwritten. Once this setup is complete,
2432 execution continues from the called function's first
2433 argument, and does not return until a "ret" opcode is
2434 encountered.
2437 int dst = (++vPC)->u.operand;
2438 int func = (++vPC)->u.operand;
2439 int thisVal = (++vPC)->u.operand;
2440 int firstArg = (++vPC)->u.operand;
2441 int argCount = (++vPC)->u.operand;
2443 JSValue* v = r[func].jsValue(exec);
2445 CallData callData;
2446 CallType callType = v->getCallData(callData);
2448 if (*enabledProfilerReference)
2449 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
2451 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
2452 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 0, v);
2453 exec->m_callFrame = callFrame;
2455 if (callType == CallTypeJS) {
2457 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
2458 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
2459 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
2461 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2463 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
2464 if (UNLIKELY(exceptionValue != 0))
2465 goto vm_throw;
2467 codeBlock = newCodeBlock;
2468 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
2469 vPC = codeBlock->instructions.begin();
2471 #if DUMP_OPCODE_STATS
2472 OpcodeStats::resetLastInstruction();
2473 #endif
2475 NEXT_OPCODE;
2478 if (callType == CallTypeHost) {
2479 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2480 ArgList args(r + firstArg + 1, argCount - 1);
2482 MACHINE_SAMPLING_callingHostFunction();
2484 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
2485 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2486 VM_CHECK_EXCEPTION();
2488 r[dst] = returnValue;
2490 if (*enabledProfilerReference)
2491 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
2493 ++vPC;
2494 NEXT_OPCODE;
2497 ASSERT(callType == CallTypeNone);
2499 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
2500 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2501 goto vm_throw;
2503 BEGIN_OPCODE(op_ret) {
2504 /* ret result(r)
2506 Return register result as the return value of the current
2507 function call, writing it into the caller's expected return
2508 value register. In addition, unwind one call frame and
2509 restore the scope chain, code block instruction pointer and
2510 register base to those of the calling function.
2513 int result = (++vPC)->u.operand;
2515 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2516 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
2517 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
2518 ASSERT(activation->isActivationObject());
2519 activation->copyRegisters();
2522 if (*enabledProfilerReference)
2523 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
2525 if (codeBlock->needsFullScopeChain)
2526 scopeChain->deref();
2528 JSValue* returnValue = r[result].jsValue(exec);
2529 if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) {
2530 JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec);
2531 returnValue = thisObject;
2534 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2535 if (!codeBlock)
2536 return returnValue;
2538 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
2539 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
2540 r = callFrame[RegisterFile::CallerRegisters].r();
2541 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2542 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
2543 r[dst] = returnValue;
2545 NEXT_OPCODE;
2547 BEGIN_OPCODE(op_construct) {
2548 /* construct dst(r) constr(r) firstArg(r) argCount(n)
2550 Invoke register "constr" as a constructor. For JS
2551 functions, the calling convention is exactly as for the
2552 "call" opcode, except that the "this" value is a newly
2553 created Object. For native constructors, a null "this"
2554 value is passed. In either case, the firstArg and argCount
2555 registers are interpreted as for the "call" opcode.
2558 int dst = (++vPC)->u.operand;
2559 int constr = (++vPC)->u.operand;
2560 int firstArg = (++vPC)->u.operand;
2561 int argCount = (++vPC)->u.operand;
2563 JSValue* constrVal = r[constr].jsValue(exec);
2565 ConstructData constructData;
2566 ConstructType constructType = constrVal->getConstructData(constructData);
2568 // Removing this line of code causes a measurable regression on squirrelfish.
2569 JSObject* constructor = static_cast<JSObject*>(constrVal);
2571 if (constructType == ConstructTypeJS) {
2572 if (*enabledProfilerReference)
2573 (*enabledProfilerReference)->willExecute(exec, constructor);
2575 JSObject* prototype;
2576 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
2577 if (p->isObject())
2578 prototype = static_cast<JSObject*>(p);
2579 else
2580 prototype = scopeChain->globalObject()->objectPrototype();
2581 JSObject* newObject = new (exec) JSObject(prototype);
2583 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
2584 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
2585 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
2587 r[firstArg] = newObject; // "this" value
2589 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
2590 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 1, constructor);
2591 exec->m_callFrame = callFrame;
2593 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
2594 if (exceptionValue)
2595 goto vm_throw;
2597 codeBlock = newCodeBlock;
2598 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
2599 vPC = codeBlock->instructions.begin();
2601 NEXT_OPCODE;
2604 if (constructType == ConstructTypeHost) {
2605 if (*enabledProfilerReference)
2606 (*enabledProfilerReference)->willExecute(exec, constructor);
2608 ArgList args(r + firstArg + 1, argCount - 1);
2610 MACHINE_SAMPLING_callingHostFunction();
2612 JSValue* returnValue = constructData.native.function(exec, constructor, args);
2614 VM_CHECK_EXCEPTION();
2615 r[dst] = returnValue;
2617 if (*enabledProfilerReference)
2618 (*enabledProfilerReference)->didExecute(exec, constructor);
2620 ++vPC;
2621 NEXT_OPCODE;
2624 ASSERT(constructType == ConstructTypeNone);
2626 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
2627 goto vm_throw;
2629 BEGIN_OPCODE(op_push_scope) {
2630 /* push_scope scope(r)
2632 Converts register scope to object, and pushes it onto the top
2633 of the current scope chain.
2635 int scope = (++vPC)->u.operand;
2636 JSValue* v = r[scope].jsValue(exec);
2637 JSObject* o = v->toObject(exec);
2638 VM_CHECK_EXCEPTION();
2640 setScopeChain(exec, scopeChain, scopeChain->push(o));
2642 ++vPC;
2643 NEXT_OPCODE;
2645 BEGIN_OPCODE(op_pop_scope) {
2646 /* pop_scope
2648 Removes the top item from the current scope chain.
2650 setScopeChain(exec, scopeChain, scopeChain->pop());
2652 ++vPC;
2653 NEXT_OPCODE;
2655 BEGIN_OPCODE(op_get_pnames) {
2656 /* get_pnames dst(r) base(r)
2658 Creates a property name list for register base and puts it
2659 in register dst. This is not a true JavaScript value, just
2660 a synthetic value used to keep the iteration state in a
2661 register.
2663 int dst = (++vPC)->u.operand;
2664 int base = (++vPC)->u.operand;
2666 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
2667 ++vPC;
2668 NEXT_OPCODE;
2670 BEGIN_OPCODE(op_next_pname) {
2671 /* next_pname dst(r) iter(r) target(offset)
2673 Tries to copies the next name from property name list in
2674 register iter. If there are names left, then copies one to
2675 register dst, and jumps to offset target. If there are none
2676 left, invalidates the iterator and continues to the next
2677 instruction.
2679 int dst = (++vPC)->u.operand;
2680 int iter = (++vPC)->u.operand;
2681 int target = (++vPC)->u.operand;
2683 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
2684 if (JSValue* temp = it->next(exec)) {
2685 CHECK_FOR_TIMEOUT();
2686 r[dst] = temp;
2687 vPC += target;
2688 NEXT_OPCODE;
2690 it->invalidate();
2692 ++vPC;
2693 NEXT_OPCODE;
2695 BEGIN_OPCODE(op_jmp_scopes) {
2696 /* jmp_scopes count(n) target(offset)
2698 Removes the a number of items from the current scope chain
2699 specified by immediate number count, then jumps to offset
2700 target.
2702 int count = (++vPC)->u.operand;
2703 int target = (++vPC)->u.operand;
2705 ScopeChainNode* tmp = scopeChain;
2706 while (count--)
2707 tmp = tmp->pop();
2708 setScopeChain(exec, scopeChain, tmp);
2710 vPC += target;
2711 NEXT_OPCODE;
2713 #if HAVE(COMPUTED_GOTO)
2714 // Appease GCC
2715 goto *(&&skip_new_scope);
2716 #endif
2717 BEGIN_OPCODE(op_push_new_scope) {
2718 /* new_scope dst(r) property(id) value(r)
2720 Constructs a new StaticScopeObject with property set to value. That scope
2721 object is then pushed onto the ScopeChain. The scope object is then stored
2722 in dst for GC.
2724 setScopeChain(exec, scopeChain, createExceptionScope(exec, codeBlock, vPC, r, scopeChain));
2725 vPC += 4;
2726 NEXT_OPCODE;
2728 #if HAVE(COMPUTED_GOTO)
2729 skip_new_scope:
2730 #endif
2731 BEGIN_OPCODE(op_catch) {
2732 /* catch ex(r)
2734 Retrieves the VMs current exception and puts it in register
2735 ex. This is only valid after an exception has been raised,
2736 and usually forms the beginning of an exception handler.
2738 ASSERT(exceptionValue);
2739 ASSERT(!exec->hadException());
2740 int ex = (++vPC)->u.operand;
2741 r[ex] = exceptionValue;
2742 exceptionValue = 0;
2744 ++vPC;
2745 NEXT_OPCODE;
2747 BEGIN_OPCODE(op_throw) {
2748 /* throw ex(r)
2750 Throws register ex as an exception. This involves three
2751 steps: first, it is set as the current exception in the
2752 VM's internal state, then the stack is unwound until an
2753 exception handler or a native code boundary is found, and
2754 then control resumes at the exception handler if any or
2755 else the script returns control to the nearest native caller.
2758 int ex = (++vPC)->u.operand;
2759 exceptionValue = r[ex].jsValue(exec);
2761 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, true);
2762 if (!handlerVPC) {
2763 *exception = exceptionValue;
2764 return jsNull();
2767 #if HAVE(COMPUTED_GOTO)
2768 // Hack around gcc performance quirk by performing an indirect goto
2769 // in order to set the vPC -- attempting to do so directly results in a
2770 // significant regression.
2771 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2773 op_throw_end: {
2774 #endif
2776 vPC = handlerVPC;
2777 NEXT_OPCODE;
2779 BEGIN_OPCODE(op_unexpected_load) {
2780 /* unexpected_load load dst(r) src(k)
2782 Copies constant src to register dst.
2784 int dst = (++vPC)->u.operand;
2785 int src = (++vPC)->u.operand;
2786 r[dst] = codeBlock->unexpectedConstants[src];
2788 ++vPC;
2789 NEXT_OPCODE;
2791 BEGIN_OPCODE(op_new_error) {
2792 /* new_error dst(r) type(n) message(k)
2794 Constructs a new Error instance using the original
2795 constructor, using immediate number n as the type and
2796 constant message as the message string. The result is
2797 written to register dst.
2799 int dst = (++vPC)->u.operand;
2800 int type = (++vPC)->u.operand;
2801 int message = (++vPC)->u.operand;
2803 r[dst] = Error::create(exec, (ErrorType)type, codeBlock->unexpectedConstants[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2805 ++vPC;
2806 NEXT_OPCODE;
2808 BEGIN_OPCODE(op_end) {
2809 /* end result(r)
2811 Return register result as the value of a global or eval
2812 program. Return control to the calling native code.
2815 if (codeBlock->needsFullScopeChain) {
2816 ASSERT(scopeChain->refCount > 1);
2817 scopeChain->deref();
2819 int result = (++vPC)->u.operand;
2820 return r[result].jsValue(exec);
2822 BEGIN_OPCODE(op_put_getter) {
2823 /* put_getter base(r) property(id) function(r)
2825 Sets register function on register base as the getter named
2826 by identifier property. Base and function are assumed to be
2827 objects as this op should only be used for getters defined
2828 in object literal form.
2830 Unlike many opcodes, this one does not write any output to
2831 the register file.
2833 int base = (++vPC)->u.operand;
2834 int property = (++vPC)->u.operand;
2835 int function = (++vPC)->u.operand;
2837 ASSERT(r[base].jsValue(exec)->isObject());
2838 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
2839 Identifier& ident = codeBlock->identifiers[property];
2840 ASSERT(r[function].jsValue(exec)->isObject());
2841 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
2843 ++vPC;
2844 NEXT_OPCODE;
2846 BEGIN_OPCODE(op_put_setter) {
2847 /* put_setter base(r) property(id) function(r)
2849 Sets register function on register base as the setter named
2850 by identifier property. Base and function are assumed to be
2851 objects as this op should only be used for setters defined
2852 in object literal form.
2854 Unlike many opcodes, this one does not write any output to
2855 the register file.
2857 int base = (++vPC)->u.operand;
2858 int property = (++vPC)->u.operand;
2859 int function = (++vPC)->u.operand;
2861 ASSERT(r[base].jsValue(exec)->isObject());
2862 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
2863 Identifier& ident = codeBlock->identifiers[property];
2864 ASSERT(r[function].jsValue(exec)->isObject());
2865 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
2867 ++vPC;
2868 NEXT_OPCODE;
2870 BEGIN_OPCODE(op_jsr) {
2871 /* jsr retAddrDst(r) target(offset)
2873 Places the address of the next instruction into the retAddrDst
2874 register and jumps to offset target from the current instruction.
2876 int retAddrDst = (++vPC)->u.operand;
2877 int target = (++vPC)->u.operand;
2878 r[retAddrDst] = vPC + 1;
2880 vPC += target;
2881 NEXT_OPCODE;
2883 BEGIN_OPCODE(op_sret) {
2884 /* sret retAddrSrc(r)
2886 Jumps to the address stored in the retAddrSrc register. This
2887 differs from op_jmp because the target address is stored in a
2888 register, not as an immediate.
2890 int retAddrSrc = (++vPC)->u.operand;
2891 vPC = r[retAddrSrc].vPC();
2892 NEXT_OPCODE;
2894 BEGIN_OPCODE(op_debug) {
2895 /* debug debugHookID(n) firstLine(n) lastLine(n)
2897 Notifies the debugger of the current state of execution. This opcode
2898 is only generated while the debugger is attached.
2901 debug(exec, vPC, codeBlock, scopeChain, r);
2903 vPC += 4;
2904 NEXT_OPCODE;
2906 vm_throw: {
2907 exec->clearException();
2908 if (!tickCount) {
2909 // The exceptionValue is a lie! (GCC produces bad code for reasons I
2910 // cannot fathom if we don't assign to the exceptionValue before branching)
2911 exceptionValue = createInterruptedExecutionException(exec);
2913 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, false);
2914 if (!handlerVPC) {
2915 *exception = exceptionValue;
2916 return jsNull();
2918 vPC = handlerVPC;
2919 NEXT_OPCODE;
2922 #undef NEXT_OPCODE
2923 #undef BEGIN_OPCODE
2924 #undef VM_CHECK_EXCEPTION
2927 JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
2929 Register* callFrame = this->callFrame(exec, function);
2930 if (!callFrame)
2931 return jsNull();
2933 JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
2934 if (!activation) {
2935 CodeBlock* codeBlock = &function->m_body->generatedByteCode();
2936 activation = new (exec) JSActivation(function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
2937 callFrame[RegisterFile::OptionalCalleeActivation] = activation;
2940 return activation->get(exec, exec->propertyNames().arguments);
2943 JSValue* Machine::retrieveCaller(ExecState* exec, JSFunction* function) const
2945 Register* callFrame = this->callFrame(exec, function);
2946 if (!callFrame)
2947 return jsNull();
2949 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2950 if (!callerCodeBlock)
2951 return jsNull();
2953 Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2954 if (JSValue* caller = callerCallFrame[RegisterFile::Callee].jsValue(exec))
2955 return caller;
2957 return jsNull();
2960 void Machine::retrieveLastCaller(ExecState* exec, int& lineNumber, int& sourceId, UString& sourceURL) const
2962 lineNumber = -1;
2963 sourceURL = UString();
2965 Register* callFrame = exec->m_callFrame;
2966 if (!callFrame)
2967 return;
2969 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2970 if (!callerCodeBlock)
2971 return;
2973 Instruction* vPC = callFrame[RegisterFile::ReturnVPC].vPC();
2974 lineNumber = callerCodeBlock->lineNumberForVPC(vPC - 1);
2975 sourceId = callerCodeBlock->ownerNode->sourceId();
2976 sourceURL = callerCodeBlock->ownerNode->sourceURL();
2979 Register* Machine::callFrame(ExecState* exec, JSFunction* function) const
2981 Register* callFrame = exec->m_callFrame;
2983 while (1) {
2984 while (!callFrame) {
2985 exec = exec->m_prev;
2986 if (!exec)
2987 return 0;
2988 callFrame = exec->m_callFrame;
2991 if (callFrame[RegisterFile::Callee].jsValue(exec) == function)
2992 return callFrame;
2994 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2995 if (!callerCodeBlock) {
2996 callFrame = 0;
2997 continue;
3000 callFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3004 void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, Register*& argv, int& argc)
3006 function = static_cast<JSFunction*>(callFrame[RegisterFile::Callee].getJSValue());
3007 ASSERT(function->inherits(&JSFunction::info));
3009 argv = callFrame[RegisterFile::CallerRegisters].r() + callFrame[RegisterFile::ArgumentStartRegister].i() + 1; // + 1 to skip "this"
3010 argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"
3013 } // namespace KJS