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
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.
33 #include "CodeBlock.h"
34 #include "DebuggerCallFrame.h"
35 #include "ExceptionHelpers.h"
36 #include "ExecState.h"
37 #include "GlobalEvalFunction.h"
38 #include "JSActivation.h"
40 #include "JSFunction.h"
41 #include "JSNotAnObject.h"
42 #include "JSPropertyNameIterator.h"
43 #include "JSStaticScopeObject.h"
45 #include "ObjectPrototype.h"
48 #include "RegExpObject.h"
49 #include "RegExpPrototype.h"
51 #include "collector.h"
53 #include "operations.h"
54 #include "SamplingTool.h"
73 // Default number of ticks before a timeout check should be done.
74 static const int initialTickCountThreshold = 255;
76 // Preferred number of milliseconds between each timeout check
77 static const int preferredScriptCheckTimeInterval = 1000;
79 #if HAVE(COMPUTED_GOTO)
80 static void* op_throw_end_indirect;
81 static void* op_call_indirect;
84 // Returns the depth of the scope chain within a given call frame.
85 static int depth(ScopeChain& sc)
88 ScopeChainIterator iter = sc.begin();
89 ScopeChainIterator end = sc.end();
90 while (!(*iter)->isActivationObject()) {
99 static bool fastIsNumber(JSValue* value, double& arg) {
100 if (JSImmediate::isNumber(value))
101 arg = JSImmediate::getTruncatedInt32(value);
102 else if (Heap::fastIsNumber(static_cast<JSCell*>(value)))
103 arg = static_cast<JSNumberCell*>(value)->value();
109 static bool fastToInt32(JSValue* value, int32_t& arg) {
110 if (JSImmediate::isNumber(value))
111 arg = JSImmediate::getTruncatedInt32(value);
112 else if (Heap::fastIsNumber(static_cast<JSCell*>(value)))
113 arg = static_cast<JSNumberCell*>(value)->fastToInt32();
119 static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg) {
120 if (JSImmediate::isNumber(value)) {
121 if (JSImmediate::getTruncatedUInt32(value, arg))
124 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
126 } else if (Heap::fastIsNumber(static_cast<JSCell*>(value)))
127 arg = static_cast<JSNumberCell*>(value)->fastToUInt32();
133 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
135 if (JSImmediate::areBothImmediateNumbers(v1, v2))
136 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
140 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
145 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
146 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
148 if (wasNotString1 | wasNotString2)
151 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
154 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
156 if (JSImmediate::areBothImmediateNumbers(v1, v2))
157 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
161 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
166 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
167 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
169 if (wasNotString1 | wasNotString2)
172 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
175 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
177 // exception for the Date exception in defaultValue()
178 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
179 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
181 if (p1->isString() || p2->isString()) {
182 UString value = p1->toString(exec) + p2->toString(exec);
184 return throwOutOfMemoryError(exec);
185 return jsString(exec, value);
188 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
191 // Fast-path choices here are based on frequency data from SunSpider:
192 // <times> Add case: <t1> <t2>
193 // ---------------------------
194 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
195 // 247412 Add case: 5 5
196 // 20900 Add case: 5 6
197 // 13962 Add case: 5 3
198 // 4000 Add case: 3 5
200 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
205 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
206 return jsNumber(exec, left + right);
208 JSType t1 = v1->type();
209 JSType t2 = v2->type();
210 const unsigned bothTypes = (t1 << 3) | t2;
211 ASSERT(bothTypes != ((NumberType << 3) | NumberType));
212 if (bothTypes == ((StringType << 3) | StringType)) {
213 UString value = static_cast<JSString*>(v1)->value() + static_cast<JSString*>(v2)->value();
215 return throwOutOfMemoryError(exec);
216 return jsString(exec, value);
219 // All other cases are pretty uncommon
220 return jsAddSlowCase(exec, v1, v2);
223 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
227 return jsString(exec, "undefined");
229 return jsString(exec, "object");
231 return jsString(exec, "boolean");
233 return jsString(exec, "number");
235 return jsString(exec, "string");
238 // Return "undefined" for objects that should be treated
239 // as null when doing comparisons.
240 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
241 return jsString(exec, "undefined");
243 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
244 return jsString(exec, "function");
247 return jsString(exec, "object");
251 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
253 int dst = (vPC + 1)->u.operand;
254 int property = (vPC + 2)->u.operand;
256 ScopeChainIterator iter = scopeChain->begin();
257 ScopeChainIterator end = scopeChain->end();
260 Identifier& ident = codeBlock->identifiers[property];
263 PropertySlot slot(o);
264 if (o->getPropertySlot(exec, ident, slot)) {
265 JSValue* result = slot.getValue(exec, ident);
266 exceptionValue = exec->exception();
272 } while (++iter != end);
273 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
277 static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
279 int dst = (vPC + 1)->u.operand;
280 int property = (vPC + 2)->u.operand;
281 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
283 ScopeChainIterator iter = scopeChain->begin();
284 ScopeChainIterator end = scopeChain->end();
290 Identifier& ident = codeBlock->identifiers[property];
293 PropertySlot slot(o);
294 if (o->getPropertySlot(exec, ident, slot)) {
295 JSValue* result = slot.getValue(exec, ident);
296 exceptionValue = exec->exception();
302 } while (++iter != end);
303 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
307 static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
309 int dst = (vPC + 1)->u.operand;
310 int property = (vPC + 2)->u.operand;
312 ScopeChainIterator iter = scopeChain->begin();
313 ScopeChainIterator next = iter;
315 ScopeChainIterator end = scopeChain->end();
319 Identifier& ident = codeBlock->identifiers[property];
323 if (next == end || base->getPropertySlot(exec, ident, slot)) {
332 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
334 int baseDst = (vPC + 1)->u.operand;
335 int propDst = (vPC + 2)->u.operand;
336 int property = (vPC + 3)->u.operand;
338 ScopeChainIterator iter = scopeChain->begin();
339 ScopeChainIterator end = scopeChain->end();
341 // FIXME: add scopeDepthIsZero optimization
345 Identifier& ident = codeBlock->identifiers[property];
349 PropertySlot slot(base);
350 if (base->getPropertySlot(exec, ident, slot)) {
351 JSValue* result = slot.getValue(exec, ident);
352 exceptionValue = exec->exception();
360 } while (iter != end);
362 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
366 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
368 int baseDst = (vPC + 1)->u.operand;
369 int funcDst = (vPC + 2)->u.operand;
370 int property = (vPC + 3)->u.operand;
372 ScopeChainIterator iter = scopeChain->begin();
373 ScopeChainIterator end = scopeChain->end();
375 // FIXME: add scopeDepthIsZero optimization
379 Identifier& ident = codeBlock->identifiers[property];
383 PropertySlot slot(base);
384 if (base->getPropertySlot(exec, ident, slot)) {
385 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
386 // However, section 10.2.3 says that in the case where the value provided
387 // by the caller is null, the global object should be used. It also says
388 // that the section does not apply to internal functions, but for simplicity
389 // of implementation we use the global object anyway here. This guarantees
390 // that in host objects you always get a valid object for this.
391 // We also handle wrapper substitution for the global object at the same time.
392 JSObject* thisObj = base->toThisObject(exec);
393 JSValue* result = slot.getValue(exec, ident);
394 exceptionValue = exec->exception();
398 r[baseDst] = thisObj;
403 } while (iter != end);
405 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
409 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)
411 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
412 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
413 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
414 callFrame[RegisterFile::CallerRegisters] = r;
415 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
416 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
417 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
418 callFrame[RegisterFile::CalledAsConstructor] = calledAsConstructor;
419 callFrame[RegisterFile::Callee] = function;
420 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
423 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
425 size_t registerOffset = argv + newCodeBlock->numLocals;
426 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
428 if (argc == newCodeBlock->numParameters) { // correct number of arguments
429 if (!registerFile->grow(size)) {
430 exceptionValue = createStackOverflowError(exec);
434 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
435 if (!registerFile->grow(size)) {
436 exceptionValue = createStackOverflowError(exec);
441 int omittedArgCount = newCodeBlock->numParameters - argc;
442 Register* endOfParams = r - newCodeBlock->numVars;
443 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
444 (*it) = jsUndefined();
445 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
446 int shift = argc + RegisterFile::CallFrameHeaderSize;
447 registerOffset += shift;
450 if (!registerFile->grow(size)) {
451 exceptionValue = createStackOverflowError(exec);
456 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
457 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
458 for ( ; it != end; ++it)
462 // initialize local variable slots
463 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
464 (*it) = jsUndefined();
467 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
468 r[i] = newCodeBlock->constantRegisters[i];
473 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
475 if (newCodeBlock->needsFullScopeChain) {
476 JSActivation* activation = new (exec) JSActivation(functionBodyNode, r);
477 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
479 return callDataScopeChain->copy()->push(activation);
482 return callDataScopeChain;
485 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
487 if (value->isObject())
489 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
493 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
496 return jsUndefined();
498 JSValue* program = r[argv + 1].jsValue(exec);
500 if (!program->isString())
503 Profiler** profiler = Profiler::enabledProfilerReference();
505 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
510 RefPtr<EvalNode> evalNode = exec->parser()->parse<EvalNode>(exec, UString(), 1, UStringSourceProvider::create(static_cast<JSString*>(program)->value()), &sourceId, &errLine, &errMsg);
513 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
515 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
519 JSValue* result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
522 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
531 , m_timeAtLastCheckTimeout(0)
533 , m_timeoutCheckCount(0)
534 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
536 privateExecute(InitializeAndReturn);
538 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
539 void* storage = fastMalloc(sizeof(CollectorBlock));
541 JSArray* jsArray = new (storage) JSArray(jsNull(), 0);
542 m_jsArrayVptr = jsArray->vptr();
543 static_cast<JSCell*>(jsArray)->~JSCell();
545 JSString* jsString = new (storage) JSString("");
546 m_jsStringVptr = jsString->vptr();
547 static_cast<JSCell*>(jsString)->~JSCell();
554 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
556 ScopeChain sc(scopeChain);
557 JSGlobalObject* globalObject = sc.globalObject();
558 codeBlock->dump(globalObject->globalExec());
559 dumpRegisters(codeBlock, registerFile, r);
562 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
564 printf("Register frame: \n\n");
565 printf("----------------------------------------------------\n");
566 printf(" use | address | value \n");
567 printf("----------------------------------------------------\n");
572 if (codeBlock->codeType == GlobalCode) {
573 it = registerFile->lastGlobal();
574 end = it + registerFile->numGlobals();
576 printf("[global var] | %10p | %10p \n", it, (*it).v());
579 printf("----------------------------------------------------\n");
582 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
583 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
584 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
585 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
586 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
587 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
588 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
589 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
590 printf("[CalledAsConstructor] | %10p | %10p \n", it, (*it).v()); ++it;
591 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
592 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
593 printf("----------------------------------------------------\n");
595 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
596 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
599 printf("[param] | %10p | %10p \n", it, (*it).v());
603 printf("----------------------------------------------------\n");
605 if (codeBlock->codeType != GlobalCode) {
606 end = it + codeBlock->numVars;
609 printf("[var] | %10p | %10p \n", it, (*it).v());
612 printf("----------------------------------------------------\n");
616 end = it + codeBlock->numTemporaries;
619 printf("[temp] | %10p | %10p \n", it, (*it).v());
627 #if !defined(NDEBUG) || HAVE(SAMPLING_TOOL)
629 bool Machine::isOpcode(Opcode opcode)
631 #if HAVE(COMPUTED_GOTO)
632 return opcode != HashTraits<Opcode>::emptyValue()
633 && !HashTraits<Opcode>::isDeletedValue(opcode)
634 && m_opcodeIDTable.contains(opcode);
636 return opcode >= 0 && opcode <= op_end;
642 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
644 CodeBlock* oldCodeBlock = codeBlock;
645 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
647 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
648 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
649 if (callFrame[RegisterFile::Callee].jsValue(exec))
650 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
652 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
655 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
656 if (callFrame[RegisterFile::Callee].jsValue(exec))
657 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
659 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
662 if (oldCodeBlock->needsFullScopeChain)
665 // If this call frame created an activation, tear it off.
666 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
667 ASSERT(activation->isActivationObject());
668 activation->copyRegisters();
671 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
675 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
676 r = callFrame[RegisterFile::CallerRegisters].r();
677 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
678 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
683 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
685 // Set up the exception object
687 if (exceptionValue->isObject()) {
688 JSObject* exception = static_cast<JSObject*>(exceptionValue);
689 if (exception->isNotAnObjectErrorStub()) {
690 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
691 exceptionValue = exception;
693 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
694 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
695 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
696 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
697 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
698 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
703 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
704 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
706 // We only hit this path for error messages and throw statements, which don't have a specific failure position
707 // So we just give the full range of the error/throw statement.
708 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
709 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
711 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
712 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
713 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
716 if (exception->isWatchdogException()) {
717 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
718 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
725 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
726 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
727 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
730 // Calculate an exception handler vPC, unwinding call frames as necessary.
733 Instruction* handlerVPC;
735 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
736 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
740 // Now unwind the scope chain within the exception handler's call frame.
742 ScopeChain sc(scopeChain);
743 int scopeDelta = depth(sc) - scopeDepth;
744 ASSERT(scopeDelta >= 0);
747 setScopeChain(exec, scopeChain, sc.node());
752 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
754 if (m_reentryDepth >= MaxReentryDepth) {
755 *exception = createStackOverflowError(exec);
759 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
761 size_t oldSize = m_registerFile.size();
762 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
763 if (!m_registerFile.grow(newSize)) {
764 *exception = createStackOverflowError(exec);
768 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
769 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
770 globalObject->copyGlobalsTo(m_registerFile);
772 Register* callFrame = m_registerFile.base() + oldSize;
774 // a 0 codeBlock indicates a built-in caller
775 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
777 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
778 r[codeBlock->thisRegister] = thisObj;
780 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
781 r[i] = codeBlock->constantRegisters[i];
783 if (codeBlock->needsFullScopeChain)
784 scopeChain = scopeChain->copy();
786 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
788 Profiler** profiler = Profiler::enabledProfilerReference();
790 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
793 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
796 MACHINE_SAMPLING_privateExecuteReturned();
799 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
801 (*profiler)->didFinishAllExecution(exec);
804 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
805 lastGlobalObject->copyGlobalsTo(m_registerFile);
807 m_registerFile.shrink(oldSize);
811 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
813 if (m_reentryDepth >= MaxReentryDepth) {
814 *exception = createStackOverflowError(exec);
818 int argv = RegisterFile::CallFrameHeaderSize;
819 int argc = args.size() + 1; // implicit "this" parameter
821 size_t oldSize = m_registerFile.size();
822 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
823 *exception = createStackOverflowError(exec);
827 Register* callFrame = m_registerFile.base() + oldSize;
829 // put args in place, including "this"
830 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
833 ArgList::const_iterator end = args.end();
834 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
837 // a 0 codeBlock indicates a built-in caller
838 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, 0, function);
840 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
841 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
843 m_registerFile.shrink(oldSize);
847 scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r);
849 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
851 Profiler** profiler = Profiler::enabledProfilerReference();
853 (*profiler)->willExecute(exec, function);
856 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
859 MACHINE_SAMPLING_privateExecuteReturned();
861 if (*profiler && !m_reentryDepth)
862 (*profiler)->didFinishAllExecution(exec);
864 m_registerFile.shrink(oldSize);
868 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
870 if (m_reentryDepth >= MaxReentryDepth) {
871 *exception = createStackOverflowError(exec);
875 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
877 JSVariableObject* variableObject;
878 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
880 if (node->object->isVariableObject()) {
881 variableObject = static_cast<JSVariableObject*>(node->object);
886 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
887 Node::VarStack::const_iterator varStackEnd = varStack.end();
888 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
889 const Identifier& ident = (*it).first;
890 if (!variableObject->hasProperty(exec, ident))
891 variableObject->put(exec, ident, jsUndefined());
894 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
895 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
896 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it)
897 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain));
899 size_t oldSize = m_registerFile.size();
900 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
901 if (!m_registerFile.grow(newSize)) {
902 *exception = createStackOverflowError(exec);
906 Register* callFrame = m_registerFile.base() + registerOffset;
908 // a 0 codeBlock indicates a built-in caller
909 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
911 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
912 r[codeBlock->thisRegister] = thisObj;
914 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
915 r[i] = codeBlock->constantRegisters[i];
917 if (codeBlock->needsFullScopeChain)
918 scopeChain = scopeChain->copy();
920 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
922 Profiler** profiler = Profiler::enabledProfilerReference();
924 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
927 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
930 MACHINE_SAMPLING_privateExecuteReturned();
933 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
935 (*profiler)->didFinishAllExecution(exec);
938 m_registerFile.shrink(oldSize);
942 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
944 scopeChain = newScopeChain;
945 exec->m_scopeChain = newScopeChain;
948 NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r)
950 int debugHookID = (++vPC)->u.operand;
951 int firstLine = (++vPC)->u.operand;
952 int lastLine = (++vPC)->u.operand;
954 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
958 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
960 switch((DebugHookID)debugHookID) {
961 case DidEnterCallFrame: {
962 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
965 case WillLeaveCallFrame: {
966 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
969 case WillExecuteStatement: {
970 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
973 case WillExecuteProgram: {
974 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
977 case DidExecuteProgram: {
978 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
981 case DidReachBreakpoint: {
982 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
988 void Machine::resetTimeoutCheck()
990 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
991 m_timeAtLastCheckTimeout = 0;
995 // Returns the current time in milliseconds
996 // It doesn't matter what "current time" is here, just as long as
997 // it's possible to measure the time difference correctly.
998 // In an ideal world this would just be getCurrentUTCTimeWithMicroseconds
999 // from DateMath.h, but unfortunately there's a slowdown if we use tha.
1000 static inline unsigned getCurrentTime()
1002 #if HAVE(SYS_TIME_H)
1004 gettimeofday(&tv, 0);
1005 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1007 QDateTime t = QDateTime::currentDateTime();
1008 return t.toTime_t() * 1000 + t.time().msec();
1009 #elif PLATFORM(WIN_OS)
1010 return timeGetTime();
1012 #error Platform does not have getCurrentTime function
1016 // We have to return a JSValue here, gcc seems to produce worse code if
1017 // we attempt to return a bool
1018 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1020 unsigned currentTime = getCurrentTime();
1022 if (!m_timeAtLastCheckTimeout) {
1023 // Suspicious amount of looping in a script -- start timing it
1024 m_timeAtLastCheckTimeout = currentTime;
1028 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1033 m_timeExecuting += timeDiff;
1034 m_timeAtLastCheckTimeout = currentTime;
1036 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1037 // preferredScriptCheckTimeInterval
1038 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1039 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1040 // preferred script check time interval.
1041 if (m_ticksUntilNextTimeoutCheck == 0)
1042 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1044 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1045 if (globalObject->shouldInterruptScript())
1046 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1048 resetTimeoutCheck();
1054 static int32_t offsetForStringSwitch(StringJumpTable& jumpTable, JSValue* scrutinee, int32_t defaultOffset) {
1055 StringJumpTable::const_iterator end = jumpTable.end();
1056 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
1057 StringJumpTable::const_iterator loc = jumpTable.find(value);
1059 return defaultOffset;
1063 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1065 int dst = (++vPC)->u.operand;
1066 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1067 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1068 JSObject* scope = new (exec) JSStaticScopeObject(property, value, DontDelete);
1070 return scopeChain->push(scope);
1073 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1075 // One-time initialization of our address tables. We have to put this code
1076 // here because our labels are only in scope inside this function.
1077 if (flag == InitializeAndReturn) {
1078 #if HAVE(COMPUTED_GOTO)
1079 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1080 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1083 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1084 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1085 #undef ADD_OPCODE_ID
1086 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1087 op_throw_end_indirect = &&op_throw_end;
1088 op_call_indirect = &&op_call;
1089 #endif // HAVE(COMPUTED_GOTO)
1093 JSValue* exceptionValue = 0;
1094 Instruction* handlerVPC = 0;
1096 Register* registerBase = registerFile->base();
1097 Instruction* vPC = codeBlock->instructions.begin();
1098 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1099 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1101 #define VM_CHECK_EXCEPTION() \
1103 if (UNLIKELY(exec->hadException())) { \
1104 exceptionValue = exec->exception(); \
1109 #if DUMP_OPCODE_STATS
1110 OpcodeStats::resetLastInstruction();
1113 #define CHECK_FOR_TIMEOUT() \
1114 if (!--tickCount) { \
1115 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1117 tickCount = m_ticksUntilNextTimeoutCheck; \
1120 #if HAVE(COMPUTED_GOTO)
1121 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1122 #if DUMP_OPCODE_STATS
1123 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1125 #define BEGIN_OPCODE(opcode) opcode:
1129 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1130 #if DUMP_OPCODE_STATS
1131 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1133 #define BEGIN_OPCODE(opcode) case opcode:
1135 while (1) // iterator loop begins
1136 switch (vPC->u.opcode)
1139 BEGIN_OPCODE(op_new_object) {
1140 /* new_object dst(r)
1142 Constructs a new empty Object instance using the original
1143 constructor, and puts the result in register dst.
1145 int dst = (++vPC)->u.operand;
1146 r[dst] = constructEmptyObject(exec);
1151 BEGIN_OPCODE(op_new_array) {
1152 /* new_array dst(r) firstArg(r) argCount(n)
1154 Constructs a new Array instance using the original
1155 constructor, and puts the result in register dst.
1156 The array will contain argCount elements with values
1157 taken from registers starting at register firstArg.
1159 int dst = (++vPC)->u.operand;
1160 int firstArg = (++vPC)->u.operand;
1161 int argCount = (++vPC)->u.operand;
1162 ArgList args(r + firstArg, argCount);
1163 r[dst] = constructArray(exec, args);
1168 BEGIN_OPCODE(op_new_regexp) {
1169 /* new_regexp dst(r) regExp(re)
1171 Constructs a new RegExp instance using the original
1172 constructor from regexp regExp, and puts the result in
1175 int dst = (++vPC)->u.operand;
1176 int regExp = (++vPC)->u.operand;
1177 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1182 BEGIN_OPCODE(op_mov) {
1183 /* mov dst(r) src(r)
1185 Copies register src to register dst.
1187 int dst = (++vPC)->u.operand;
1188 int src = (++vPC)->u.operand;
1194 BEGIN_OPCODE(op_eq) {
1195 /* eq dst(r) src1(r) src2(r)
1197 Checks whether register src1 and register src2 are equal,
1198 as with the ECMAScript '==' operator, and puts the result
1199 as a boolean in register dst.
1201 int dst = (++vPC)->u.operand;
1202 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1203 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1204 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1205 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1207 JSValue* result = jsBoolean(equal(exec, src1, src2));
1208 VM_CHECK_EXCEPTION();
1215 BEGIN_OPCODE(op_neq) {
1216 /* neq dst(r) src1(r) src2(r)
1218 Checks whether register src1 and register src2 are not
1219 equal, as with the ECMAScript '!=' operator, and puts the
1220 result as a boolean in register dst.
1222 int dst = (++vPC)->u.operand;
1223 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1224 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1225 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1226 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1228 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1229 VM_CHECK_EXCEPTION();
1236 BEGIN_OPCODE(op_stricteq) {
1237 /* stricteq dst(r) src1(r) src2(r)
1239 Checks whether register src1 and register src2 are strictly
1240 equal, as with the ECMAScript '===' operator, and puts the
1241 result as a boolean in register dst.
1243 int dst = (++vPC)->u.operand;
1244 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1245 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1246 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1247 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1249 r[dst] = jsBoolean(strictEqual(src1, src2));
1254 BEGIN_OPCODE(op_nstricteq) {
1255 /* nstricteq dst(r) src1(r) src2(r)
1257 Checks whether register src1 and register src2 are not
1258 strictly equal, as with the ECMAScript '!==' operator, and
1259 puts the result as a boolean in register dst.
1261 int dst = (++vPC)->u.operand;
1262 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1263 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1264 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1265 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1267 r[dst] = jsBoolean(!strictEqual(src1, src2));
1272 BEGIN_OPCODE(op_less) {
1273 /* less dst(r) src1(r) src2(r)
1275 Checks whether register src1 is less than register src2, as
1276 with the ECMAScript '<' operator, and puts the result as
1277 a boolean in register dst.
1279 int dst = (++vPC)->u.operand;
1280 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1281 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1282 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1283 VM_CHECK_EXCEPTION();
1289 BEGIN_OPCODE(op_lesseq) {
1290 /* lesseq dst(r) src1(r) src2(r)
1292 Checks whether register src1 is less than or equal to
1293 register src2, as with the ECMAScript '<=' operator, and
1294 puts the result as a boolean in register dst.
1296 int dst = (++vPC)->u.operand;
1297 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1298 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1299 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1300 VM_CHECK_EXCEPTION();
1306 BEGIN_OPCODE(op_pre_inc) {
1307 /* pre_inc srcDst(r)
1309 Converts register srcDst to number, adds one, and puts the result
1310 back in register srcDst.
1312 int srcDst = (++vPC)->u.operand;
1313 JSValue* v = r[srcDst].jsValue(exec);
1314 if (JSImmediate::canDoFastAdditiveOperations(v))
1315 r[srcDst] = JSImmediate::incImmediateNumber(v);
1317 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1318 VM_CHECK_EXCEPTION();
1325 BEGIN_OPCODE(op_pre_dec) {
1326 /* pre_dec srcDst(r)
1328 Converts register srcDst to number, subtracts one, and puts the result
1329 back in register srcDst.
1331 int srcDst = (++vPC)->u.operand;
1332 JSValue* v = r[srcDst].jsValue(exec);
1333 if (JSImmediate::canDoFastAdditiveOperations(v))
1334 r[srcDst] = JSImmediate::decImmediateNumber(v);
1336 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1337 VM_CHECK_EXCEPTION();
1344 BEGIN_OPCODE(op_post_inc) {
1345 /* post_inc dst(r) srcDst(r)
1347 Converts register srcDst to number. The number itself is
1348 written to register dst, and the number plus one is written
1349 back to register srcDst.
1351 int dst = (++vPC)->u.operand;
1352 int srcDst = (++vPC)->u.operand;
1353 JSValue* v = r[srcDst].jsValue(exec);
1354 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1356 r[srcDst] = JSImmediate::incImmediateNumber(v);
1358 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1359 VM_CHECK_EXCEPTION();
1361 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1367 BEGIN_OPCODE(op_post_dec) {
1368 /* post_dec dst(r) srcDst(r)
1370 Converts register srcDst to number. The number itself is
1371 written to register dst, and the number minus one is written
1372 back to register srcDst.
1374 int dst = (++vPC)->u.operand;
1375 int srcDst = (++vPC)->u.operand;
1376 JSValue* v = r[srcDst].jsValue(exec);
1377 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1379 r[srcDst] = JSImmediate::decImmediateNumber(v);
1381 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1382 VM_CHECK_EXCEPTION();
1384 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1390 BEGIN_OPCODE(op_to_jsnumber) {
1391 /* to_jsnumber dst(r) src(r)
1393 Converts register src to number, and puts the result
1396 int dst = (++vPC)->u.operand;
1397 int src = (++vPC)->u.operand;
1398 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1399 VM_CHECK_EXCEPTION();
1406 BEGIN_OPCODE(op_negate) {
1407 /* negate dst(r) src(r)
1409 Converts register src to number, negates it, and puts the
1410 result in register dst.
1412 int dst = (++vPC)->u.operand;
1413 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1415 if (fastIsNumber(src, v))
1416 r[dst] = jsNumber(exec, -v);
1418 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1419 VM_CHECK_EXCEPTION();
1426 BEGIN_OPCODE(op_add) {
1427 /* add dst(r) src1(r) src2(r)
1429 Adds register src1 and register src2, and puts the result
1430 in register dst. (JS add may be string concatenation or
1431 numeric add, depending on the types of the operands.)
1433 int dst = (++vPC)->u.operand;
1434 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1435 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1436 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1437 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1439 JSValue* result = jsAdd(exec, src1, src2);
1440 VM_CHECK_EXCEPTION();
1446 BEGIN_OPCODE(op_mul) {
1447 /* mul dst(r) src1(r) src2(r)
1449 Multiplies register src1 and register src2 (converted to
1450 numbers), and puts the product in register dst.
1452 int dst = (++vPC)->u.operand;
1453 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1454 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1457 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1458 r[dst] = jsNumber(exec, left * right);
1460 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1461 VM_CHECK_EXCEPTION();
1468 BEGIN_OPCODE(op_div) {
1469 /* div dst(r) dividend(r) divisor(r)
1471 Divides register dividend (converted to number) by the
1472 register divisor (converted to number), and puts the
1473 quotient in register dst.
1475 int dst = (++vPC)->u.operand;
1476 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1477 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1480 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1481 r[dst] = jsNumber(exec, left / right);
1483 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1484 VM_CHECK_EXCEPTION();
1490 BEGIN_OPCODE(op_mod) {
1491 /* mod dst(r) dividend(r) divisor(r)
1493 Divides register dividend (converted to number) by
1494 register divisor (converted to number), and puts the
1495 remainder in register dst.
1497 int dst = (++vPC)->u.operand;
1498 int dividend = (++vPC)->u.operand;
1499 int divisor = (++vPC)->u.operand;
1501 JSValue* dividendValue = r[dividend].jsValue(exec);
1502 JSValue* divisorValue = r[divisor].jsValue(exec);
1504 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1505 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1510 double d = dividendValue->toNumber(exec);
1511 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1512 VM_CHECK_EXCEPTION();
1517 BEGIN_OPCODE(op_sub) {
1518 /* sub dst(r) src1(r) src2(r)
1520 Subtracts register src2 (converted to number) from register
1521 src1 (converted to number), and puts the difference in
1524 int dst = (++vPC)->u.operand;
1525 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1526 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1529 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1530 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1531 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1532 r[dst] = jsNumber(exec, left - right);
1534 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1535 VM_CHECK_EXCEPTION();
1541 BEGIN_OPCODE(op_lshift) {
1542 /* lshift dst(r) val(r) shift(r)
1544 Performs left shift of register val (converted to int32) by
1545 register shift (converted to uint32), and puts the result
1548 int dst = (++vPC)->u.operand;
1549 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1550 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1553 if (JSImmediate::areBothImmediateNumbers(val, shift))
1554 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::toTruncatedUInt32(shift) & 0x1f));
1555 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1556 r[dst] = jsNumber(exec, left << (right & 0x1f));
1558 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1559 VM_CHECK_EXCEPTION();
1566 BEGIN_OPCODE(op_rshift) {
1567 /* rshift dst(r) val(r) shift(r)
1569 Performs arithmetic right shift of register val (converted
1570 to int32) by register shift (converted to
1571 uint32), and puts the result in register dst.
1573 int dst = (++vPC)->u.operand;
1574 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1575 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1578 if (JSImmediate::areBothImmediateNumbers(val, shift))
1579 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1580 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1581 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1583 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1584 VM_CHECK_EXCEPTION();
1591 BEGIN_OPCODE(op_urshift) {
1592 /* rshift dst(r) val(r) shift(r)
1594 Performs logical right shift of register val (converted
1595 to uint32) by register shift (converted to
1596 uint32), and puts the result in register dst.
1598 int dst = (++vPC)->u.operand;
1599 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1600 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1601 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1602 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1604 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1605 VM_CHECK_EXCEPTION();
1612 BEGIN_OPCODE(op_bitand) {
1613 /* bitand dst(r) src1(r) src2(r)
1615 Computes bitwise AND of register src1 (converted to int32)
1616 and register src2 (converted to int32), and puts the result
1619 int dst = (++vPC)->u.operand;
1620 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1621 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1624 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1625 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1626 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1627 r[dst] = jsNumber(exec, left & right);
1629 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
1630 VM_CHECK_EXCEPTION();
1637 BEGIN_OPCODE(op_bitxor) {
1638 /* bitxor dst(r) src1(r) src2(r)
1640 Computes bitwise XOR of register src1 (converted to int32)
1641 and register src2 (converted to int32), and puts the result
1644 int dst = (++vPC)->u.operand;
1645 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1646 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1649 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1650 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
1651 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1652 r[dst] = jsNumber(exec, left ^ right);
1654 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
1655 VM_CHECK_EXCEPTION();
1662 BEGIN_OPCODE(op_bitor) {
1663 /* bitor dst(r) src1(r) src2(r)
1665 Computes bitwise OR of register src1 (converted to int32)
1666 and register src2 (converted to int32), and puts the
1667 result in register dst.
1669 int dst = (++vPC)->u.operand;
1670 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1671 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1674 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1675 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
1676 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1677 r[dst] = jsNumber(exec, left | right);
1679 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
1680 VM_CHECK_EXCEPTION();
1687 BEGIN_OPCODE(op_bitnot) {
1688 /* bitnot dst(r) src(r)
1690 Computes bitwise NOT of register src1 (converted to int32),
1691 and puts the result in register dst.
1693 int dst = (++vPC)->u.operand;
1694 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1696 if (fastToInt32(src, value))
1697 r[dst] = jsNumber(exec, ~value);
1699 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
1700 VM_CHECK_EXCEPTION();
1706 BEGIN_OPCODE(op_not) {
1707 /* not dst(r) src(r)
1709 Computes logical NOT of register src (converted to
1710 boolean), and puts the result in register dst.
1712 int dst = (++vPC)->u.operand;
1713 int src = (++vPC)->u.operand;
1714 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
1715 VM_CHECK_EXCEPTION();
1721 BEGIN_OPCODE(op_instanceof) {
1722 /* instanceof dst(r) value(r) constructor(r)
1724 Tests whether register value is an instance of register
1725 constructor, and puts the boolean result in register dst.
1727 Raises an exception if register constructor is not an
1730 int dst = (++vPC)->u.operand;
1731 int value = (++vPC)->u.operand;
1732 int base = (++vPC)->u.operand;
1734 JSValue* baseVal = r[base].jsValue(exec);
1736 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
1739 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1740 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec)) : false);
1745 BEGIN_OPCODE(op_typeof) {
1746 /* typeof dst(r) src(r)
1748 Determines the type string for src according to ECMAScript
1749 rules, and puts the result in register dst.
1751 int dst = (++vPC)->u.operand;
1752 int src = (++vPC)->u.operand;
1753 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
1758 BEGIN_OPCODE(op_in) {
1759 /* in dst(r) property(r) base(r)
1761 Tests whether register base has a property named register
1762 property, and puts the boolean result in register dst.
1764 Raises an exception if register constructor is not an
1767 int dst = (++vPC)->u.operand;
1768 int property = (++vPC)->u.operand;
1769 int base = (++vPC)->u.operand;
1771 JSValue* baseVal = r[base].jsValue(exec);
1772 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
1775 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1777 JSValue* propName = r[property].jsValue(exec);
1780 if (propName->getUInt32(i))
1781 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
1783 Identifier property(exec, propName->toString(exec));
1784 VM_CHECK_EXCEPTION();
1785 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
1791 BEGIN_OPCODE(op_resolve) {
1792 /* resolve dst(r) property(id)
1794 Looks up the property named by identifier property in the
1795 scope chain, and writes the resulting value to register
1796 dst. If the property is not found, raises an exception.
1798 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1804 BEGIN_OPCODE(op_resolve_skip) {
1805 /* resolve_skip dst(r) property(id) skip(n)
1807 Looks up the property named by identifier property in the
1808 scope chain skipping the top 'skip' levels, and writes the resulting
1809 value to register dst. If the property is not found, raises an exception.
1811 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1818 BEGIN_OPCODE(op_get_scoped_var) {
1819 /* get_scoped_var dst(r) index(n) skip(n)
1821 Loads the contents of the index-th local from the scope skip nodes from
1822 the top of the scope chain, and places it in register dst
1824 int dst = (++vPC)->u.operand;
1825 int index = (++vPC)->u.operand;
1826 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1828 ScopeChainIterator iter = scopeChain->begin();
1829 ScopeChainIterator end = scopeChain->end();
1830 ASSERT(iter != end);
1833 ASSERT(iter != end);
1836 ASSERT((*iter)->isVariableObject());
1837 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1838 r[dst] = scope->registerAt(index);
1842 BEGIN_OPCODE(op_put_scoped_var) {
1843 /* put_scoped_var index(n) skip(n) value(r)
1846 int index = (++vPC)->u.operand;
1847 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1848 int value = (++vPC)->u.operand;
1850 ScopeChainIterator iter = scopeChain->begin();
1851 ScopeChainIterator end = scopeChain->end();
1852 ASSERT(iter != end);
1855 ASSERT(iter != end);
1858 ASSERT((*iter)->isVariableObject());
1859 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1860 scope->registerAt(index) = r[value].jsValue(exec);
1864 BEGIN_OPCODE(op_resolve_base) {
1865 /* resolve_base dst(r) property(id)
1867 Searches the scope chain for an object containing
1868 identifier property, and if one is found, writes it to
1869 register dst. If none is found, the outermost scope (which
1870 will be the global object) is stored in register dst.
1872 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1877 BEGIN_OPCODE(op_resolve_with_base) {
1878 /* resolve_with_base baseDst(r) propDst(r) property(id)
1880 Searches the scope chain for an object containing
1881 identifier property, and if one is found, writes it to
1882 register srcDst, and the retrieved property value to register
1883 propDst. If the property is not found, raises an exception.
1885 This is more efficient than doing resolve_base followed by
1886 resolve, or resolve_base followed by get_by_id, as it
1887 avoids duplicate hash lookups.
1889 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1895 BEGIN_OPCODE(op_resolve_func) {
1896 /* resolve_func baseDst(r) funcDst(r) property(id)
1898 Searches the scope chain for an object containing
1899 identifier property, and if one is found, writes the
1900 appropriate object to use as "this" when calling its
1901 properties to register baseDst; and the retrieved property
1902 value to register propDst. If the property is not found,
1903 raises an exception.
1905 This differs from resolve_with_base, because the
1906 global this value will be substituted for activations or
1907 the global object, which is the right behavior for function
1908 calls but not for other property lookup.
1910 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1916 BEGIN_OPCODE(op_get_by_id) {
1917 /* get_by_id dst(r) base(r) property(id)
1919 Converts register base to Object, gets the property
1920 named by identifier property from the object, and puts the
1921 result in register dst.
1923 int dst = (++vPC)->u.operand;
1924 int base = (++vPC)->u.operand;
1925 int property = (++vPC)->u.operand;
1927 Identifier& ident = codeBlock->identifiers[property];
1928 JSValue *result = r[base].jsValue(exec)->get(exec, ident);
1929 VM_CHECK_EXCEPTION();
1934 BEGIN_OPCODE(op_put_by_id) {
1935 /* put_by_id base(r) property(id) value(r)
1937 Sets register value on register base as the property named
1938 by identifier property. Base is converted to object first.
1940 Unlike many opcodes, this one does not write any output to
1943 int base = (++vPC)->u.operand;
1944 int property = (++vPC)->u.operand;
1945 int value = (++vPC)->u.operand;
1947 Identifier& ident = codeBlock->identifiers[property];
1948 r[base].jsValue(exec)->put(exec, ident, r[value].jsValue(exec));
1950 VM_CHECK_EXCEPTION();
1954 BEGIN_OPCODE(op_del_by_id) {
1955 /* del_by_id dst(r) base(r) property(id)
1957 Converts register base to Object, deletes the property
1958 named by identifier property from the object, and writes a
1959 boolean indicating success (if true) or failure (if false)
1962 int dst = (++vPC)->u.operand;
1963 int base = (++vPC)->u.operand;
1964 int property = (++vPC)->u.operand;
1966 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
1968 Identifier& ident = codeBlock->identifiers[property];
1969 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1970 VM_CHECK_EXCEPTION();
1975 BEGIN_OPCODE(op_get_by_val) {
1976 /* get_by_val dst(r) base(r) property(r)
1978 Converts register base to Object, gets the property named
1979 by register property from the object, and puts the result
1980 in register dst. property is nominally converted to string
1981 but numbers are treated more efficiently.
1983 int dst = (++vPC)->u.operand;
1984 int base = (++vPC)->u.operand;
1985 int property = (++vPC)->u.operand;
1987 JSValue* baseValue = r[base].jsValue(exec);
1988 JSValue* subscript = r[property].jsValue(exec);
1993 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
1994 if (LIKELY(isUInt32)) {
1995 if (isJSArray(baseValue)) {
1996 JSArray* jsArray = static_cast<JSArray*>(baseValue);
1997 if (jsArray->canGetIndex(i))
1998 result = jsArray->getIndex(i);
2000 result = jsArray->JSArray::get(exec, i);
2001 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2002 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2004 result = baseValue->get(exec, i);
2006 Identifier property(exec, subscript->toString(exec));
2007 result = baseValue->get(exec, property);
2010 VM_CHECK_EXCEPTION();
2015 BEGIN_OPCODE(op_put_by_val) {
2016 /* put_by_val base(r) property(r) value(r)
2018 Sets register value on register base as the property named
2019 by register property. Base is converted to object
2020 first. register property is nominally converted to string
2021 but numbers are treated more efficiently.
2023 Unlike many opcodes, this one does not write any output to
2026 int base = (++vPC)->u.operand;
2027 int property = (++vPC)->u.operand;
2028 int value = (++vPC)->u.operand;
2030 JSValue* baseValue = r[base].jsValue(exec);
2031 JSValue* subscript = r[property].jsValue(exec);
2035 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2036 if (LIKELY(isUInt32)) {
2037 if (isJSArray(baseValue)) {
2038 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2039 if (jsArray->canSetIndex(i))
2040 jsArray->setIndex(i, r[value].jsValue(exec));
2042 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2044 baseValue->put(exec, i, r[value].jsValue(exec));
2046 Identifier property(exec, subscript->toString(exec));
2047 if (!exec->hadException()) // Don't put to an object if toString threw an exception.
2048 baseValue->put(exec, property, r[value].jsValue(exec));
2051 VM_CHECK_EXCEPTION();
2055 BEGIN_OPCODE(op_del_by_val) {
2056 /* del_by_val dst(r) base(r) property(r)
2058 Converts register base to Object, deletes the property
2059 named by register property from the object, and writes a
2060 boolean indicating success (if true) or failure (if false)
2063 int dst = (++vPC)->u.operand;
2064 int base = (++vPC)->u.operand;
2065 int property = (++vPC)->u.operand;
2067 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2069 JSValue* subscript = r[property].jsValue(exec);
2072 if (subscript->getUInt32(i))
2073 result = jsBoolean(baseObj->deleteProperty(exec, i));
2075 VM_CHECK_EXCEPTION();
2076 Identifier property(exec, subscript->toString(exec));
2077 VM_CHECK_EXCEPTION();
2078 result = jsBoolean(baseObj->deleteProperty(exec, property));
2081 VM_CHECK_EXCEPTION();
2086 BEGIN_OPCODE(op_put_by_index) {
2087 /* put_by_index base(r) property(n) value(r)
2089 Sets register value on register base as the property named
2090 by the immediate number property. Base is converted to
2093 Unlike many opcodes, this one does not write any output to
2096 This opcode is mainly used to initialize array literals.
2098 int base = (++vPC)->u.operand;
2099 unsigned property = (++vPC)->u.operand;
2100 int value = (++vPC)->u.operand;
2102 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2107 BEGIN_OPCODE(op_loop) {
2108 /* loop target(offset)
2110 Jumps unconditionally to offset target from the current
2113 Additionally this loop instruction may terminate JS execution is
2114 the JS timeout is reached.
2116 #if DUMP_OPCODE_STATS
2117 OpcodeStats::resetLastInstruction();
2119 int target = (++vPC)->u.operand;
2120 CHECK_FOR_TIMEOUT();
2124 BEGIN_OPCODE(op_jmp) {
2125 /* jmp target(offset)
2127 Jumps unconditionally to offset target from the current
2130 #if DUMP_OPCODE_STATS
2131 OpcodeStats::resetLastInstruction();
2133 int target = (++vPC)->u.operand;
2138 BEGIN_OPCODE(op_loop_if_true) {
2139 /* loop_if_true cond(r) target(offset)
2141 Jumps to offset target from the current instruction, if and
2142 only if register cond converts to boolean as true.
2144 Additionally this loop instruction may terminate JS execution is
2145 the JS timeout is reached.
2147 int cond = (++vPC)->u.operand;
2148 int target = (++vPC)->u.operand;
2149 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2151 CHECK_FOR_TIMEOUT();
2158 BEGIN_OPCODE(op_jtrue) {
2159 /* jtrue 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 int cond = (++vPC)->u.operand;
2165 int target = (++vPC)->u.operand;
2166 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2174 BEGIN_OPCODE(op_jfalse) {
2175 /* jfalse cond(r) target(offset)
2177 Jumps to offset target from the current instruction, if and
2178 only if register cond converts to boolean as false.
2180 int cond = (++vPC)->u.operand;
2181 int target = (++vPC)->u.operand;
2182 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2190 BEGIN_OPCODE(op_loop_if_less) {
2191 /* loop_if_less src1(r) src2(r) target(offset)
2193 Checks whether register src1 is less than register src2, as
2194 with the ECMAScript '<' operator, and then jumps to offset
2195 target from the current instruction, if and only if the
2196 result of the comparison is true.
2198 Additionally this loop instruction may terminate JS execution is
2199 the JS timeout is reached.
2201 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2202 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2203 int target = (++vPC)->u.operand;
2205 bool result = jsLess(exec, src1, src2);
2206 VM_CHECK_EXCEPTION();
2210 CHECK_FOR_TIMEOUT();
2217 BEGIN_OPCODE(op_jnless) {
2218 /* jnless src1(r) src2(r) target(offset)
2220 Checks whether register src1 is less than register src2, as
2221 with the ECMAScript '<' operator, and then jumps to offset
2222 target from the current instruction, if and only if the
2223 result of the comparison is false.
2225 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2226 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2227 int target = (++vPC)->u.operand;
2229 bool result = jsLess(exec, src1, src2);
2230 VM_CHECK_EXCEPTION();
2240 BEGIN_OPCODE(op_switch_imm) {
2241 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2243 Performs a range checked switch on the scrutinee value, using
2244 the tableIndex-th immediate switch jump table. If the scrutinee value
2245 is an immediate number in the range covered by the referenced jump
2246 table, and the value at jumpTable[scrutinee value] is non-zero, then
2247 that value is used as the jump offset, otherwise defaultOffset is used.
2249 int tableIndex = (++vPC)->u.operand;
2250 int defaultOffset = (++vPC)->u.operand;
2251 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2252 if (!JSImmediate::isNumber(scrutinee))
2253 vPC += defaultOffset;
2255 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
2256 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
2260 BEGIN_OPCODE(op_switch_char) {
2261 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2263 Performs a range checked switch on the scrutinee value, using
2264 the tableIndex-th character switch jump table. If the scrutinee value
2265 is a single character string 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 (scrutinee->type() != StringType)
2273 vPC += defaultOffset;
2275 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
2276 if (value->size() != 1)
2277 vPC += defaultOffset;
2279 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
2283 BEGIN_OPCODE(op_switch_string) {
2284 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2286 Performs a sparse hashmap based switch on the value in the scrutinee
2287 register, using the tableIndex-th string switch jump table. If the
2288 scrutinee value is a string that exists as a key in the referenced
2289 jump table, then the value associated with the string is used as the
2290 jump offset, otherwise defaultOffset is used.
2292 int tableIndex = (++vPC)->u.operand;
2293 int defaultOffset = (++vPC)->u.operand;
2294 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2295 if (scrutinee->type() != StringType)
2296 vPC += defaultOffset;
2298 vPC += offsetForStringSwitch(codeBlock->stringSwitchJumpTables[tableIndex], scrutinee, defaultOffset);
2301 BEGIN_OPCODE(op_new_func) {
2302 /* new_func dst(r) func(f)
2304 Constructs a new Function instance from function func and
2305 the current scope chain using the original Function
2306 constructor, using the rules for function declarations, and
2307 puts the result in register dst.
2309 int dst = (++vPC)->u.operand;
2310 int func = (++vPC)->u.operand;
2312 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
2317 BEGIN_OPCODE(op_new_func_exp) {
2318 /* new_func_exp dst(r) func(f)
2320 Constructs a new Function instance from function func and
2321 the current scope chain using the original Function
2322 constructor, using the rules for function expressions, and
2323 puts the result in register dst.
2325 int dst = (++vPC)->u.operand;
2326 int func = (++vPC)->u.operand;
2328 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
2333 BEGIN_OPCODE(op_call_eval) {
2334 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2336 Call a function named "eval" with no explicit "this" value
2337 (which may therefore be the eval operator). If register
2338 thisVal is the global object, and register func contains
2339 that global object's original global eval function, then
2340 perform the eval operator in local scope (interpreting
2341 the argument registers as for the "call"
2342 opcode). Otherwise, act exactly as the "call" opcode would.
2345 int dst = (++vPC)->u.operand;
2346 int func = (++vPC)->u.operand;
2347 int thisVal = (++vPC)->u.operand;
2348 int firstArg = (++vPC)->u.operand;
2349 int argCount = (++vPC)->u.operand;
2351 JSValue* funcVal = r[func].jsValue(exec);
2352 JSValue* baseVal = r[thisVal].jsValue(exec);
2354 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
2355 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
2356 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
2366 // We didn't find the blessed version of eval, so reset vPC and process
2367 // this instruction as a normal function call, supplying the proper 'this'
2370 r[thisVal] = baseVal->toThisObject(exec);
2372 #if HAVE(COMPUTED_GOTO)
2373 // Hack around gcc performance quirk by performing an indirect goto
2374 // in order to set the vPC -- attempting to do so directly results in a
2375 // significant regression.
2376 goto *op_call_indirect; // indirect goto -> op_call
2378 // fall through to op_call
2380 BEGIN_OPCODE(op_call) {
2381 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2383 Perform a function call. Specifically, call register func
2384 with a "this" value of register thisVal, and put the result
2387 The arguments start at register firstArg and go up to
2388 argCount, but the "this" value is considered an implicit
2389 first argument, so the argCount should be one greater than
2390 the number of explicit arguments passed, and the register
2391 after firstArg should contain the actual first
2392 argument. This opcode will copy from the thisVal register
2393 to the firstArg register, unless the register index of
2394 thisVal is the special missing this object marker, which is
2395 2^31-1; in that case, the global object will be used as the
2398 If func is a native code function, then this opcode calls
2399 it and returns the value immediately.
2401 But if it is a JS function, then the current scope chain
2402 and code block is set to the function's, and we slide the
2403 register window so that the arguments would form the first
2404 few local registers of the called function's register
2405 window. In addition, a call frame header is written
2406 immediately before the arguments; see the call frame
2407 documentation for an explanation of how many registers a
2408 call frame takes and what they contain. That many registers
2409 before the firstArg register will be overwritten by the
2410 call. In addition, any registers higher than firstArg +
2411 argCount may be overwritten. Once this setup is complete,
2412 execution continues from the called function's first
2413 argument, and does not return until a "ret" opcode is
2417 int dst = (++vPC)->u.operand;
2418 int func = (++vPC)->u.operand;
2419 int thisVal = (++vPC)->u.operand;
2420 int firstArg = (++vPC)->u.operand;
2421 int argCount = (++vPC)->u.operand;
2423 JSValue* v = r[func].jsValue(exec);
2426 CallType callType = v->getCallData(callData);
2428 if (callType == CallTypeJS) {
2429 if (*enabledProfilerReference)
2430 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
2432 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
2433 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
2434 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
2436 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2438 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
2439 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 0, v);
2440 exec->m_callFrame = callFrame;
2442 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
2443 if (UNLIKELY(exceptionValue != 0))
2446 codeBlock = newCodeBlock;
2447 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
2448 vPC = codeBlock->instructions.begin();
2450 #if DUMP_OPCODE_STATS
2451 OpcodeStats::resetLastInstruction();
2457 if (callType == CallTypeHost) {
2458 if (*enabledProfilerReference)
2459 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
2461 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2462 ArgList args(r + firstArg + 1, argCount - 1);
2464 MACHINE_SAMPLING_callingHostFunction();
2466 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
2467 VM_CHECK_EXCEPTION();
2469 r[dst] = returnValue;
2471 if (*enabledProfilerReference)
2472 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
2478 ASSERT(callType == CallTypeNone);
2480 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
2483 BEGIN_OPCODE(op_ret) {
2486 Return register result as the return value of the current
2487 function call, writing it into the caller's expected return
2488 value register. In addition, unwind one call frame and
2489 restore the scope chain, code block instruction pointer and
2490 register base to those of the calling function.
2493 int result = (++vPC)->u.operand;
2495 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2496 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
2497 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
2498 ASSERT(activation->isActivationObject());
2499 activation->copyRegisters();
2502 if (*enabledProfilerReference)
2503 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
2505 if (codeBlock->needsFullScopeChain)
2506 scopeChain->deref();
2508 JSValue* returnValue = r[result].jsValue(exec);
2509 if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) {
2510 JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec);
2511 returnValue = thisObject;
2514 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2518 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
2519 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
2520 r = callFrame[RegisterFile::CallerRegisters].r();
2521 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2522 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
2523 r[dst] = returnValue;
2527 BEGIN_OPCODE(op_construct) {
2528 /* construct dst(r) constr(r) firstArg(r) argCount(n)
2530 Invoke register "constr" as a constructor. For JS
2531 functions, the calling convention is exactly as for the
2532 "call" opcode, except that the "this" value is a newly
2533 created Object. For native constructors, a null "this"
2534 value is passed. In either case, the firstArg and argCount
2535 registers are interpreted as for the "call" opcode.
2538 int dst = (++vPC)->u.operand;
2539 int constr = (++vPC)->u.operand;
2540 int firstArg = (++vPC)->u.operand;
2541 int argCount = (++vPC)->u.operand;
2543 JSValue* constrVal = r[constr].jsValue(exec);
2545 ConstructData constructData;
2546 ConstructType constructType = constrVal->getConstructData(constructData);
2548 // Removing this line of code causes a measurable regression on squirrelfish.
2549 JSObject* constructor = static_cast<JSObject*>(constrVal);
2551 if (constructType == ConstructTypeJS) {
2552 if (*enabledProfilerReference)
2553 (*enabledProfilerReference)->willExecute(exec, constructor);
2555 JSObject* prototype;
2556 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
2558 prototype = static_cast<JSObject*>(p);
2560 prototype = scopeChain->globalObject()->objectPrototype();
2561 JSObject* newObject = new (exec) JSObject(prototype);
2563 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
2564 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
2565 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
2567 r[firstArg] = newObject; // "this" value
2569 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
2570 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 1, constructor);
2571 exec->m_callFrame = callFrame;
2573 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
2577 codeBlock = newCodeBlock;
2578 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
2579 vPC = codeBlock->instructions.begin();
2584 if (constructType == ConstructTypeHost) {
2585 if (*enabledProfilerReference)
2586 (*enabledProfilerReference)->willExecute(exec, constructor);
2588 ArgList args(r + firstArg + 1, argCount - 1);
2590 MACHINE_SAMPLING_callingHostFunction();
2592 JSValue* returnValue = constructData.native.function(exec, constructor, args);
2594 VM_CHECK_EXCEPTION();
2595 r[dst] = returnValue;
2597 if (*enabledProfilerReference)
2598 (*enabledProfilerReference)->didExecute(exec, constructor);
2604 ASSERT(constructType == ConstructTypeNone);
2606 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
2609 BEGIN_OPCODE(op_push_scope) {
2610 /* push_scope scope(r)
2612 Converts register scope to object, and pushes it onto the top
2613 of the current scope chain.
2615 int scope = (++vPC)->u.operand;
2616 JSValue* v = r[scope].jsValue(exec);
2617 JSObject* o = v->toObject(exec);
2618 VM_CHECK_EXCEPTION();
2620 setScopeChain(exec, scopeChain, scopeChain->push(o));
2625 BEGIN_OPCODE(op_pop_scope) {
2628 Removes the top item from the current scope chain.
2630 setScopeChain(exec, scopeChain, scopeChain->pop());
2635 BEGIN_OPCODE(op_get_pnames) {
2636 /* get_pnames dst(r) base(r)
2638 Creates a property name list for register base and puts it
2639 in register dst. This is not a true JavaScript value, just
2640 a synthetic value used to keep the iteration state in a
2643 int dst = (++vPC)->u.operand;
2644 int base = (++vPC)->u.operand;
2646 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
2650 BEGIN_OPCODE(op_next_pname) {
2651 /* next_pname dst(r) iter(r) target(offset)
2653 Tries to copies the next name from property name list in
2654 register iter. If there are names left, then copies one to
2655 register dst, and jumps to offset target. If there are none
2656 left, invalidates the iterator and continues to the next
2659 int dst = (++vPC)->u.operand;
2660 int iter = (++vPC)->u.operand;
2661 int target = (++vPC)->u.operand;
2663 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
2664 if (JSValue* temp = it->next(exec)) {
2665 CHECK_FOR_TIMEOUT();
2675 BEGIN_OPCODE(op_jmp_scopes) {
2676 /* jmp_scopes count(n) target(offset)
2678 Removes the a number of items from the current scope chain
2679 specified by immediate number count, then jumps to offset
2682 int count = (++vPC)->u.operand;
2683 int target = (++vPC)->u.operand;
2685 ScopeChainNode* tmp = scopeChain;
2688 setScopeChain(exec, scopeChain, tmp);
2693 #if HAVE(COMPUTED_GOTO)
2695 goto *(&&skip_new_scope);
2697 BEGIN_OPCODE(op_push_new_scope) {
2698 /* new_scope dst(r) property(id) value(r)
2700 Constructs a new StaticScopeObject with property set to value. That scope
2701 object is then pushed onto the ScopeChain. The scope object is then stored
2704 setScopeChain(exec, scopeChain, createExceptionScope(exec, codeBlock, vPC, r, scopeChain));
2708 #if HAVE(COMPUTED_GOTO)
2711 BEGIN_OPCODE(op_catch) {
2714 Retrieves the VMs current exception and puts it in register
2715 ex. This is only valid after an exception has been raised,
2716 and usually forms the beginning of an exception handler.
2718 ASSERT(exceptionValue);
2719 ASSERT(!exec->hadException());
2720 int ex = (++vPC)->u.operand;
2721 r[ex] = exceptionValue;
2727 BEGIN_OPCODE(op_throw) {
2730 Throws register ex as an exception. This involves three
2731 steps: first, it is set as the current exception in the
2732 VM's internal state, then the stack is unwound until an
2733 exception handler or a native code boundary is found, and
2734 then control resumes at the exception handler if any or
2735 else the script returns control to the nearest native caller.
2738 int ex = (++vPC)->u.operand;
2739 exceptionValue = r[ex].jsValue(exec);
2741 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, true);
2743 *exception = exceptionValue;
2747 #if HAVE(COMPUTED_GOTO)
2748 // Hack around gcc performance quirk by performing an indirect goto
2749 // in order to set the vPC -- attempting to do so directly results in a
2750 // significant regression.
2751 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2759 BEGIN_OPCODE(op_unexpected_load) {
2760 /* unexpected_load load dst(r) src(k)
2762 Copies constant src to register dst.
2764 int dst = (++vPC)->u.operand;
2765 int src = (++vPC)->u.operand;
2766 r[dst] = codeBlock->unexpectedConstants[src];
2771 BEGIN_OPCODE(op_new_error) {
2772 /* new_error dst(r) type(n) message(k)
2774 Constructs a new Error instance using the original
2775 constructor, using immediate number n as the type and
2776 constant message as the message string. The result is
2777 written to register dst.
2779 int dst = (++vPC)->u.operand;
2780 int type = (++vPC)->u.operand;
2781 int message = (++vPC)->u.operand;
2783 r[dst] = Error::create(exec, (ErrorType)type, codeBlock->unexpectedConstants[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2788 BEGIN_OPCODE(op_end) {
2791 Return register result as the value of a global or eval
2792 program. Return control to the calling native code.
2795 if (codeBlock->needsFullScopeChain) {
2796 ASSERT(scopeChain->refCount > 1);
2797 scopeChain->deref();
2799 int result = (++vPC)->u.operand;
2800 return r[result].jsValue(exec);
2802 BEGIN_OPCODE(op_put_getter) {
2803 /* put_getter base(r) property(id) function(r)
2805 Sets register function on register base as the getter named
2806 by identifier property. Base and function are assumed to be
2807 objects as this op should only be used for getters defined
2808 in object literal form.
2810 Unlike many opcodes, this one does not write any output to
2813 int base = (++vPC)->u.operand;
2814 int property = (++vPC)->u.operand;
2815 int function = (++vPC)->u.operand;
2817 ASSERT(r[base].jsValue(exec)->isObject());
2818 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
2819 Identifier& ident = codeBlock->identifiers[property];
2820 ASSERT(r[function].jsValue(exec)->isObject());
2821 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
2826 BEGIN_OPCODE(op_put_setter) {
2827 /* put_setter base(r) property(id) function(r)
2829 Sets register function on register base as the setter named
2830 by identifier property. Base and function are assumed to be
2831 objects as this op should only be used for setters defined
2832 in object literal form.
2834 Unlike many opcodes, this one does not write any output to
2837 int base = (++vPC)->u.operand;
2838 int property = (++vPC)->u.operand;
2839 int function = (++vPC)->u.operand;
2841 ASSERT(r[base].jsValue(exec)->isObject());
2842 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
2843 Identifier& ident = codeBlock->identifiers[property];
2844 ASSERT(r[function].jsValue(exec)->isObject());
2845 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
2850 BEGIN_OPCODE(op_jsr) {
2851 /* jsr retAddrDst(r) target(offset)
2853 Places the address of the next instruction into the retAddrDst
2854 register and jumps to offset target from the current instruction.
2856 int retAddrDst = (++vPC)->u.operand;
2857 int target = (++vPC)->u.operand;
2858 r[retAddrDst] = vPC + 1;
2863 BEGIN_OPCODE(op_sret) {
2864 /* sret retAddrSrc(r)
2866 Jumps to the address stored in the retAddrSrc register. This
2867 differs from op_jmp because the target address is stored in a
2868 register, not as an immediate.
2870 int retAddrSrc = (++vPC)->u.operand;
2871 vPC = r[retAddrSrc].vPC();
2874 BEGIN_OPCODE(op_debug) {
2875 /* debug debugHookID(n) firstLine(n) lastLine(n)
2877 Notifies the debugger of the current state of execution. This opcode
2878 is only generated while the debugger is attached.
2881 debug(exec, vPC, codeBlock, scopeChain, r);
2887 exec->clearException();
2889 // The exceptionValue is a lie! (GCC produces bad code for reasons I
2890 // cannot fathom if we don't assign to the exceptionValue before branching)
2891 exceptionValue = createInterruptedExecutionException(exec);
2893 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, false);
2895 *exception = exceptionValue;
2904 #undef VM_CHECK_EXCEPTION
2907 JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
2909 Register* callFrame = this->callFrame(exec, function);
2913 JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
2915 CodeBlock* codeBlock = &function->m_body->generatedByteCode();
2916 activation = new (exec) JSActivation(function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
2917 callFrame[RegisterFile::OptionalCalleeActivation] = activation;
2920 return activation->get(exec, exec->propertyNames().arguments);
2923 JSValue* Machine::retrieveCaller(ExecState* exec, JSFunction* function) const
2925 Register* callFrame = this->callFrame(exec, function);
2929 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2930 if (!callerCodeBlock)
2933 Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2934 if (JSValue* caller = callerCallFrame[RegisterFile::Callee].jsValue(exec))
2940 Register* Machine::callFrame(ExecState* exec, JSFunction* function) const
2942 Register* callFrame = exec->m_callFrame;
2945 while (!callFrame) {
2946 exec = exec->m_prev;
2949 callFrame = exec->m_callFrame;
2952 if (callFrame[RegisterFile::Callee].jsValue(exec) == function)
2955 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2956 if (!callerCodeBlock) {
2961 callFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2965 void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, Register*& argv, int& argc)
2967 function = static_cast<JSFunction*>(callFrame[RegisterFile::Callee].getJSValue());
2968 ASSERT(function->inherits(&JSFunction::info));
2970 argv = callFrame[RegisterFile::CallerRegisters].r() + callFrame[RegisterFile::ArgumentStartRegister].i() + 1; // + 1 to skip "this"
2971 argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"