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 "JSActivation.h"
39 #include "JSPropertyNameIterator.h"
42 #include "array_object.h"
46 #include "object_object.h"
47 #include "operations.h"
48 #include "operations.h"
49 #include "regexp_object.h"
53 __builtin_expect ((x), 0)
60 #if HAVE(COMPUTED_GOTO)
61 static void* op_throw_end_indirect;
62 static void* op_call_indirect;
65 // Retrieves the offset of a calling function within the current register file.
66 bool getCallerFunctionOffset(Register** registerBase, int callOffset, int& callerOffset)
68 Register* callFrame = (*registerBase) + callOffset;
70 CodeBlock* callerCodeBlock = callFrame[Machine::CallerCodeBlock].u.codeBlock;
71 if (!callerCodeBlock) // test for top frame of re-entrant function call
74 callerOffset = callFrame[Machine::CallerRegisterOffset].u.i - callerCodeBlock->numLocals - Machine::CallFrameHeaderSize;
75 if (callerOffset < 0) // test for global frame
78 Register* callerCallFrame = (*registerBase) + callerOffset;
79 if (!callerCallFrame[Machine::CallerCodeBlock].u.codeBlock) // test for eval frame
85 // Returns the depth of the scope chain within a given call frame.
86 static int depth(ScopeChain& sc)
89 ScopeChainIterator iter = sc.begin();
90 ScopeChainIterator end = sc.end();
91 while (!(*iter)->isVariableObject()) {
98 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
104 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
105 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
107 if (wasNotString1 | wasNotString2)
110 return static_cast<const StringImp*>(p1)->value() < static_cast<const StringImp*>(p2)->value();
113 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
119 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
120 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
122 if (wasNotString1 | wasNotString2)
125 return !(static_cast<const StringImp*>(p2)->value() < static_cast<const StringImp*>(p1)->value());
128 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
130 // exception for the Date exception in defaultValue()
131 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
132 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
134 if (p1->isString() || p2->isString()) {
135 UString value = p1->toString(exec) + p2->toString(exec);
137 return throwOutOfMemoryError(exec);
138 return jsString(value);
141 return jsNumber(p1->toNumber(exec) + p2->toNumber(exec));
144 // Fast-path choices here are based on frequency data from SunSpider:
145 // <times> Add case: <t1> <t2>
146 // ---------------------------
147 // 5627160 Add case: 1 1
148 // 247427 Add case: 5 5
149 // 20901 Add case: 5 6
150 // 13978 Add case: 5 1
151 // 4000 Add case: 1 5
154 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
156 JSType t1 = v1->type();
157 JSType t2 = v2->type();
158 const unsigned bothTypes = (t1 << 3) | t2;
160 if (bothTypes == ((NumberType << 3) | NumberType))
161 return jsNumber(v1->uncheckedGetNumber() + v2->uncheckedGetNumber());
162 if (bothTypes == ((StringType << 3) | StringType)) {
163 UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
165 return throwOutOfMemoryError(exec);
166 return jsString(value);
169 // All other cases are pretty uncommon
170 return jsAddSlowCase(exec, v1, v2);
173 static JSValue* jsTypeStringForValue(JSValue* v)
177 return jsString("undefined");
179 return jsString("object");
181 return jsString("boolean");
183 return jsString("number");
185 return jsString("string");
188 // Return "undefined" for objects that should be treated
189 // as null when doing comparisons.
190 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
191 return jsString("undefined");
192 else if (static_cast<JSObject*>(v)->implementsCall())
193 return jsString("function");
196 return jsString("object");
200 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
202 int dst = (vPC + 1)->u.operand;
203 int property = (vPC + 2)->u.operand;
205 ScopeChainIterator iter = scopeChain->begin();
206 ScopeChainIterator end = scopeChain->end();
210 Identifier& ident = codeBlock->identifiers[property];
213 if (o->getPropertySlot(exec, ident, slot)) {
214 JSValue* result = slot.getValue(exec, o, ident);
215 exceptionValue = exec->exception();
218 r[dst].u.jsValue = result;
221 } while (++iter != end);
222 exceptionValue = createUndefinedVariableError(exec, ident);
226 static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
228 int dst = (vPC + 1)->u.operand;
229 int property = (vPC + 2)->u.operand;
230 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
232 ScopeChainIterator iter = scopeChain->begin();
233 ScopeChainIterator end = scopeChain->end();
240 Identifier& ident = codeBlock->identifiers[property];
243 if (o->getPropertySlot(exec, ident, slot)) {
244 JSValue* result = slot.getValue(exec, o, ident);
245 exceptionValue = exec->exception();
248 r[dst].u.jsValue = result;
251 } while (++iter != end);
252 exceptionValue = createUndefinedVariableError(exec, ident);
256 static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
258 int dst = (vPC + 1)->u.operand;
259 int property = (vPC + 2)->u.operand;
261 ScopeChainIterator iter = scopeChain->begin();
262 ScopeChainIterator next = iter;
264 ScopeChainIterator end = scopeChain->end();
268 Identifier& ident = codeBlock->identifiers[property];
272 if (next == end || base->getPropertySlot(exec, ident, slot)) {
273 r[dst].u.jsValue = base;
281 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
283 int baseDst = (vPC + 1)->u.operand;
284 int propDst = (vPC + 2)->u.operand;
285 int property = (vPC + 3)->u.operand;
287 ScopeChainIterator iter = scopeChain->begin();
288 ScopeChainIterator end = scopeChain->end();
290 // FIXME: add scopeDepthIsZero optimization
295 Identifier& ident = codeBlock->identifiers[property];
299 if (base->getPropertySlot(exec, ident, slot)) {
300 JSValue* result = slot.getValue(exec, base, ident);
301 exceptionValue = exec->exception();
304 r[propDst].u.jsValue = result;
305 r[baseDst].u.jsValue = base;
309 } while (iter != end);
311 exceptionValue = createUndefinedVariableError(exec, ident);
315 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
317 int baseDst = (vPC + 1)->u.operand;
318 int funcDst = (vPC + 2)->u.operand;
319 int property = (vPC + 3)->u.operand;
321 ScopeChainIterator iter = scopeChain->begin();
322 ScopeChainIterator end = scopeChain->end();
324 // FIXME: add scopeDepthIsZero optimization
329 Identifier& ident = codeBlock->identifiers[property];
333 if (base->getPropertySlot(exec, ident, slot)) {
334 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
335 // However, section 10.2.3 says that in the case where the value provided
336 // by the caller is null, the global object should be used. It also says
337 // that the section does not apply to internal functions, but for simplicity
338 // of implementation we use the global object anyway here. This guarantees
339 // that in host objects you always get a valid object for this.
340 // We also handle wrapper substitution for the global object at the same time.
341 JSObject* thisObj = base->toThisObject(exec);
342 JSValue* result = slot.getValue(exec, base, ident);
343 exceptionValue = exec->exception();
347 r[baseDst].u.jsValue = thisObj;
348 r[funcDst].u.jsValue = result;
352 } while (iter != end);
354 exceptionValue = createUndefinedVariableError(exec, ident);
358 ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, int registerOffset, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
360 callFrame[Machine::CallerCodeBlock].u.codeBlock = codeBlock;
361 callFrame[Machine::ReturnVPC].u.vPC = vPC + 1;
362 callFrame[Machine::CallerScopeChain].u.scopeChain = scopeChain;
363 callFrame[Machine::CallerRegisterOffset].u.i = registerOffset;
364 callFrame[Machine::ReturnValueRegister].u.i = returnValueRegister;
365 callFrame[Machine::ArgumentStartRegister].u.i = argv; // original argument vector (for the sake of the "arguments" object)
366 callFrame[Machine::ArgumentCount].u.i = argc; // original argument count (for the sake of the "arguments" object)
367 callFrame[Machine::CalledAsConstructor].u.i = calledAsConstructor;
368 callFrame[Machine::Callee].u.jsValue = function;
369 callFrame[Machine::OptionalCalleeActivation].u.jsValue = 0;
372 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register** registerBase, int registerOffset, int argv, int argc, JSValue*& exceptionValue)
375 int oldOffset = registerOffset;
376 registerOffset += argv + newCodeBlock->numLocals;
377 size_t size = registerOffset + newCodeBlock->numTemporaries;
379 if (argc == newCodeBlock->numParameters) { // correct number of arguments
380 if (!registerFile->grow(size)) {
381 exceptionValue = createStackOverflowError(exec);
382 return *registerBase + oldOffset;
384 r = (*registerBase) + registerOffset;
385 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
386 if (!registerFile->grow(size)) {
387 exceptionValue = createStackOverflowError(exec);
388 return *registerBase + oldOffset;
390 r = (*registerBase) + registerOffset;
392 int omittedArgCount = newCodeBlock->numParameters - argc;
393 Register* endOfParams = r - newCodeBlock->numVars;
394 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
395 (*it).u.jsValue = jsUndefined();
396 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
397 int shift = argc + Machine::CallFrameHeaderSize;
398 registerOffset += shift;
401 if (!registerFile->grow(size)) {
402 exceptionValue = createStackOverflowError(exec);
403 return *registerBase + oldOffset;
405 r = (*registerBase) + registerOffset;
407 Register* it = r - newCodeBlock->numLocals - Machine::CallFrameHeaderSize - shift;
408 Register* end = it + Machine::CallFrameHeaderSize + newCodeBlock->numParameters;
409 for ( ; it != end; ++it)
416 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register** registerBase, Register* r)
418 if (newCodeBlock->needsFullScopeChain) {
419 JSActivation* activation = new JSActivation(functionBodyNode, registerBase, r - (*registerBase));
420 r[Machine::OptionalCalleeActivation - Machine::CallFrameHeaderSize - newCodeBlock->numLocals].u.jsValue = activation;
422 return callDataScopeChain->copy()->push(activation);
425 return callDataScopeChain;
428 static NEVER_INLINE bool isNotObject(ExecState* exec, const Instruction*, CodeBlock*, JSValue* value, JSValue*& exceptionData)
430 if (value->isObject())
432 exceptionData = createNotAnObjectError(exec, value, 0);
436 static NEVER_INLINE JSValue* eval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
438 JSValue* x = argc >= 2 ? r[argv + 1].u.jsValue : jsUndefined();
443 UString s = x->toString(exec);
444 if (exec->hadException()) {
445 exceptionValue = exec->exception();
446 exec->clearException();
453 RefPtr<EvalNode> evalNode = parser().parse<EvalNode>(exec, UString(), 0, UStringSourceProvider::create(s), &sourceId, &errLine, &errMsg);
456 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
460 return machine().execute(evalNode.get(), exec, thisObj, registerFile, r - (*registerFile->basePointer()) + argv + argc, scopeChain, &exceptionValue);
465 ASSERT(JSLock::currentThreadIsHoldingLock());
466 static Machine machine;
473 privateExecute(InitializeAndReturn);
476 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
478 ScopeChain sc(scopeChain);
479 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(sc.bottom());
480 codeBlock->dump(globalObject->globalExec());
481 dumpRegisters(codeBlock, registerFile, r);
484 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
486 printf("Register frame: \n\n");
487 printf("----------------------------------------\n");
488 printf(" use | address | value \n");
489 printf("----------------------------------------\n");
494 if (isGlobalCallFrame(registerFile->basePointer(), r)) {
495 it = r - registerFile->numGlobalSlots();
499 printf("[global var] | %10p | %10p \n", it, (*it).u.jsValue);
502 printf("----------------------------------------\n");
505 it = r - codeBlock->numLocals - CallFrameHeaderSize;
506 end = it + CallFrameHeaderSize;
509 printf("[call frame] | %10p | %10p \n", it, (*it).u.jsValue);
512 printf("----------------------------------------\n");
515 end = it + codeBlock->numParameters;
518 printf("[param] | %10p | %10p \n", it, (*it).u.jsValue);
521 printf("----------------------------------------\n");
524 end = it + codeBlock->numVars;
527 printf("[var] | %10p | %10p \n", it, (*it).u.jsValue);
530 printf("----------------------------------------\n");
534 end = it + codeBlock->numTemporaries;
537 printf("[temp] | %10p | %10p \n", it, (*it).u.jsValue);
543 bool Machine::isOpcode(Opcode opcode)
545 #if HAVE(COMPUTED_GOTO)
546 return opcode != HashTraits<Opcode>::emptyValue()
547 && !HashTraits<Opcode>::isDeletedValue(opcode)
548 && m_opcodeIDTable.contains(opcode);
550 return opcode >= 0 && opcode <= op_end;
554 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction*& vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
556 CodeBlock* oldCodeBlock = codeBlock;
558 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
559 if (!isGlobalCallFrame(registerBase, r)) {
560 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
561 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
565 if (oldCodeBlock->needsFullScopeChain)
568 if (isGlobalCallFrame(registerBase, r))
571 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
573 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
577 // If this call frame created an activation, tear it off.
578 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
579 ASSERT(activation->isActivationObject());
580 activation->copyRegisters();
583 k = codeBlock->jsValues.data();
584 scopeChain = callFrame[CallerScopeChain].u.scopeChain;
585 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
586 r = (*registerBase) + callerRegisterOffset;
587 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
588 vPC = callFrame[ReturnVPC].u.vPC;
592 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction* vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
594 // Set up the exception object
596 if (exceptionValue->isObject()) {
597 JSObject* exception = static_cast<JSObject*>(exceptionValue);
598 if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
599 exception->put(exec, "line", jsNumber(codeBlock->lineNumberForVPC(vPC)));
600 exception->put(exec, "sourceURL", jsOwnedString(codeBlock->ownerNode->sourceURL()));
604 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
605 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
606 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
609 // Calculate an exception handler vPC, unwinding call frames as necessary.
612 Instruction* handlerVPC;
614 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth))
615 if (!unwindCallFrame(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r))
618 // Now unwind the scope chain within the exception handler's call frame.
620 ScopeChain sc(scopeChain);
621 int scopeDelta = depth(sc) - scopeDepth;
622 ASSERT(scopeDelta >= 0);
625 setScopeChain(exec, scopeChain, sc.node());
630 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, RegisterFileStack* registerFileStack, JSValue** exception)
632 if (m_reentryDepth >= MaxReentryDepth) {
633 *exception = createStackOverflowError(exec);
637 RegisterFile* registerFile = registerFileStack->pushGlobalRegisterFile();
638 ASSERT(registerFile->numGlobalSlots());
639 CodeBlock* codeBlock = &programNode->code(scopeChain, !registerFileStack->inImplicitCall());
640 registerFile->addGlobalSlots(codeBlock->numVars);
642 registerFile->uncheckedGrow(codeBlock->numTemporaries);
643 Register* r = (*registerFile->basePointer());
645 r[ProgramCodeThisRegister].u.jsValue = thisObj;
647 if (codeBlock->needsFullScopeChain)
648 scopeChain = scopeChain->copy();
650 ExecState newExec(exec, this, registerFile, scopeChain, -1);
653 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
656 registerFileStack->popGlobalRegisterFile();
660 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, FunctionImp* function, JSObject* thisObj, const List& args, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
662 if (m_reentryDepth >= MaxReentryDepth) {
663 *exception = createStackOverflowError(exec);
667 RegisterFile* registerFile = registerFileStack->current();
669 int argv = CallFrameHeaderSize;
670 int argc = args.size() + 1; // implicit "this" parameter
672 size_t oldSize = registerFile->size();
673 if (!registerFile->grow(oldSize + CallFrameHeaderSize + argc)) {
674 *exception = createStackOverflowError(exec);
678 Register** registerBase = registerFile->basePointer();
679 int registerOffset = oldSize;
680 int callFrameOffset = registerOffset;
681 Register* callFrame = (*registerBase) + callFrameOffset;
683 // put args in place, including "this"
684 Register* dst = callFrame + CallFrameHeaderSize;
685 (*dst).u.jsValue = thisObj;
687 List::const_iterator end = args.end();
688 for (List::const_iterator it = args.begin(); it != end; ++it)
689 (*++dst).u.jsValue = *it;
691 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
692 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, argv, argc, 0, function);
694 CodeBlock* newCodeBlock = &functionBodyNode->code(scopeChain);
695 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, *exception);
697 registerFile->shrink(oldSize);
701 scopeChain = scopeChainForCall(functionBodyNode, newCodeBlock, scopeChain, registerBase, r);
703 ExecState newExec(exec, this, registerFile, scopeChain, callFrameOffset);
706 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, newCodeBlock, exception);
709 registerFile->shrink(oldSize);
714 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFile* registerFile, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
716 if (m_reentryDepth >= MaxReentryDepth) {
717 *exception = createStackOverflowError(exec);
720 EvalCodeBlock* codeBlock = &evalNode->code(scopeChain);
722 JSVariableObject* variableObject;
723 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
725 if (node->object->isVariableObject()) {
726 variableObject = static_cast<JSVariableObject*>(node->object);
731 for (Vector<Identifier>::const_iterator iter = codeBlock->declaredVariableNames.begin(); iter != codeBlock->declaredVariableNames.end(); ++iter) {
732 Identifier ident = *iter;
734 if (!variableObject->hasProperty(exec, ident))
735 variableObject->put(exec, ident, jsUndefined());
738 ASSERT(codeBlock->functions.size() == codeBlock->declaredFunctionNames.size());
739 for (size_t i = 0; i < codeBlock->functions.size(); ++i)
740 variableObject->put(exec, codeBlock->declaredFunctionNames[i], codeBlock->functions[i]->makeFunction(exec, scopeChain));
742 size_t oldSize = registerFile->size();
743 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numTemporaries + CallFrameHeaderSize;
744 if (!registerFile->grow(newSize)) {
745 *exception = createStackOverflowError(exec);
749 Register* callFrame = *registerFile->basePointer() + registerOffset;
751 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
752 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, 0, 0, 0, 0);
754 Register* r = callFrame + CallFrameHeaderSize + codeBlock->numVars;
755 r[ProgramCodeThisRegister].u.jsValue = thisObj;
757 if (codeBlock->needsFullScopeChain)
758 scopeChain = scopeChain->copy();
760 ExecState newExec(exec, this, registerFile, scopeChain, -1);
763 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
766 registerFile->shrink(oldSize);
770 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
772 RegisterFile* registerFile = registerFileStack->current();
773 if (registerFile->safeForReentry())
774 return Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
775 registerFile = registerFileStack->pushFunctionRegisterFile();
776 JSValue* result = Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
777 registerFileStack->popFunctionRegisterFile();
781 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
783 scopeChain = newScopeChain;
784 exec->m_scopeChain = newScopeChain;
787 NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register** registerBase, Register* r)
789 int debugHookID = (++vPC)->u.operand;
790 int firstLine = (++vPC)->u.operand;
791 int lastLine = (++vPC)->u.operand;
793 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
797 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, 0, registerBase, r - *registerBase);
799 switch((DebugHookID)debugHookID) {
800 case DidEnterCallFrame: {
801 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
804 case WillLeaveCallFrame: {
805 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
808 case WillExecuteStatement: {
809 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
815 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
817 // One-time initialization of our address tables. We have to put this code
818 // here because our labels are only in scope inside this function.
819 if (flag == InitializeAndReturn) {
820 #if HAVE(COMPUTED_GOTO)
821 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
822 FOR_EACH_OPCODE_ID(ADD_OPCODE);
825 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
826 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
828 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
829 op_throw_end_indirect = &&op_throw_end;
830 op_call_indirect = &&op_call;
831 #endif // HAVE(COMPUTED_GOTO)
835 JSValue* exceptionValue = 0;
836 Instruction* handlerVPC = 0;
838 Register** registerBase = registerFile->basePointer();
839 Instruction* vPC = codeBlock->instructions.begin();
840 JSValue** k = codeBlock->jsValues.data();
842 registerFile->setSafeForReentry(false);
843 #define VM_CHECK_EXCEPTION() \
845 if (UNLIKELY(exec->hadException())) { \
846 exceptionValue = exec->exception(); \
851 #if HAVE(COMPUTED_GOTO)
852 #define NEXT_OPCODE goto *vPC->u.opcode
853 #define BEGIN_OPCODE(opcode) opcode:
856 #define NEXT_OPCODE continue
857 #define BEGIN_OPCODE(opcode) case opcode:
858 while(1) // iterator loop begins
859 switch (vPC->u.opcode)
862 BEGIN_OPCODE(op_load) {
863 /* load dst(r) src(k)
865 Copies constant src to register dst.
867 int dst = (++vPC)->u.operand;
868 int src = (++vPC)->u.operand;
869 r[dst].u.jsValue = k[src];
874 BEGIN_OPCODE(op_new_object) {
877 Constructs a new empty Object instance using the original
878 constructor, and puts the result in register dst.
880 int dst = (++vPC)->u.operand;
881 r[dst].u.jsValue = scopeChain->globalObject()->objectConstructor()->construct(exec, exec->emptyList());
886 BEGIN_OPCODE(op_new_array) {
889 Constructs a new empty Array instance using the original
890 constructor, and puts the result in register dst.
892 int dst = (++vPC)->u.operand;
893 r[dst].u.jsValue = scopeChain->globalObject()->arrayConstructor()->construct(exec, exec->emptyList());
898 BEGIN_OPCODE(op_new_regexp) {
899 /* new_regexp dst(r) regExp(re)
901 Constructs a new RegExp instance using the original
902 constructor from regexp regExp, and puts the result in
905 int dst = (++vPC)->u.operand;
906 int regExp = (++vPC)->u.operand;
907 r[dst].u.jsValue = new RegExpImp(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
912 BEGIN_OPCODE(op_mov) {
915 Copies register src to register dst.
917 int dst = (++vPC)->u.operand;
918 int src = (++vPC)->u.operand;
924 BEGIN_OPCODE(op_eq) {
925 /* eq dst(r) src1(r) src2(r)
927 Checks whether register src1 and register src2 are equal,
928 as with the ECMAScript '==' operator, and puts the result
929 as a boolean in register dst.
931 int dst = (++vPC)->u.operand;
932 int src1 = (++vPC)->u.operand;
933 int src2 = (++vPC)->u.operand;
934 JSValue* result = jsBoolean(equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
935 VM_CHECK_EXCEPTION();
936 r[dst].u.jsValue = result;
941 BEGIN_OPCODE(op_neq) {
942 /* neq dst(r) src1(r) src2(r)
944 Checks whether register src1 and register src2 are not
945 equal, as with the ECMAScript '!=' operator, and puts the
946 result as a boolean in register dst.
948 int dst = (++vPC)->u.operand;
949 int src1 = (++vPC)->u.operand;
950 int src2 = (++vPC)->u.operand;
951 JSValue* result = jsBoolean(!equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
952 VM_CHECK_EXCEPTION();
953 r[dst].u.jsValue = result;
958 BEGIN_OPCODE(op_stricteq) {
959 /* stricteq dst(r) src1(r) src2(r)
961 Checks whether register src1 and register src2 are strictly
962 equal, as with the ECMAScript '===' operator, and puts the
963 result as a boolean in register dst.
965 int dst = (++vPC)->u.operand;
966 int src1 = (++vPC)->u.operand;
967 int src2 = (++vPC)->u.operand;
968 r[dst].u.jsValue = jsBoolean(strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
973 BEGIN_OPCODE(op_nstricteq) {
974 /* nstricteq dst(r) src1(r) src2(r)
976 Checks whether register src1 and register src2 are not
977 strictly equal, as with the ECMAScript '!==' operator, and
978 puts the result as a boolean in register dst.
980 int dst = (++vPC)->u.operand;
981 int src1 = (++vPC)->u.operand;
982 int src2 = (++vPC)->u.operand;
983 r[dst].u.jsValue = jsBoolean(!strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
988 BEGIN_OPCODE(op_less) {
989 /* less dst(r) src1(r) src2(r)
991 Checks whether register src1 is less than register src2, as
992 with the ECMAScript '<' operator, and puts the result as
993 a boolean in register dst.
995 int dst = (++vPC)->u.operand;
996 int src1 = (++vPC)->u.operand;
997 int src2 = (++vPC)->u.operand;
998 JSValue* result = jsBoolean(jsLess(exec, r[src1].u.jsValue, r[src2].u.jsValue));
999 VM_CHECK_EXCEPTION();
1000 r[dst].u.jsValue = result;
1005 BEGIN_OPCODE(op_lesseq) {
1006 /* lesseq dst(r) src1(r) src2(r)
1008 Checks whether register src1 is less than or equal to
1009 register src2, as with the ECMAScript '<=' operator, and
1010 puts the result as a boolean in register dst.
1012 int dst = (++vPC)->u.operand;
1013 int src1 = (++vPC)->u.operand;
1014 int src2 = (++vPC)->u.operand;
1015 JSValue* result = jsBoolean(jsLessEq(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1016 VM_CHECK_EXCEPTION();
1017 r[dst].u.jsValue = result;
1022 BEGIN_OPCODE(op_pre_inc) {
1023 /* pre_inc srcDst(r)
1025 Converts register srcDst to number, adds one, and puts the result
1026 back in register srcDst.
1028 int srcDst = (++vPC)->u.operand;
1029 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) + 1);
1030 VM_CHECK_EXCEPTION();
1031 r[srcDst].u.jsValue = result;
1036 BEGIN_OPCODE(op_pre_dec) {
1037 /* pre_dec srcDst(r)
1039 Converts register srcDst to number, subtracts one, and puts the result
1040 back in register srcDst.
1042 int srcDst = (++vPC)->u.operand;
1043 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) - 1);
1044 VM_CHECK_EXCEPTION();
1045 r[srcDst].u.jsValue = result;
1050 BEGIN_OPCODE(op_post_inc) {
1051 /* post_inc dst(r) srcDst(r)
1053 Converts register srcDst to number. The number itself is
1054 written to register dst, and the number plus one is written
1055 back to register srcDst.
1057 int dst = (++vPC)->u.operand;
1058 int srcDst = (++vPC)->u.operand;
1059 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1060 VM_CHECK_EXCEPTION();
1062 r[dst].u.jsValue = number;
1063 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() + 1);
1068 BEGIN_OPCODE(op_post_dec) {
1069 /* post_dec dst(r) srcDst(r)
1071 Converts register srcDst to number. The number itself is
1072 written to register dst, and the number minus one is written
1073 back to register srcDst.
1075 int dst = (++vPC)->u.operand;
1076 int srcDst = (++vPC)->u.operand;
1077 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1078 VM_CHECK_EXCEPTION();
1080 r[dst].u.jsValue = number;
1081 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() - 1);
1086 BEGIN_OPCODE(op_to_jsnumber) {
1087 /* to_jsnumber dst(r) src(r)
1089 Converts register src to number, and puts the result
1092 int dst = (++vPC)->u.operand;
1093 int src = (++vPC)->u.operand;
1094 JSValue* result = r[src].u.jsValue->toJSNumber(exec);
1095 VM_CHECK_EXCEPTION();
1097 r[dst].u.jsValue = result;
1102 BEGIN_OPCODE(op_negate) {
1103 /* negate dst(r) src(r)
1105 Converts register src to number, negates it, and puts the
1106 result in register dst.
1108 int dst = (++vPC)->u.operand;
1109 int src = (++vPC)->u.operand;
1110 JSValue* result = jsNumber(-r[src].u.jsValue->toNumber(exec));
1111 VM_CHECK_EXCEPTION();
1112 r[dst].u.jsValue = result;
1117 BEGIN_OPCODE(op_add) {
1118 /* add dst(r) src1(r) src2(r)
1120 Adds register src1 and register src2, and puts the result
1121 in register dst. (JS add may be string concatenation or
1122 numeric add, depending on the types of the operands.)
1124 int dst = (++vPC)->u.operand;
1125 int src1 = (++vPC)->u.operand;
1126 int src2 = (++vPC)->u.operand;
1127 JSValue* result = jsAdd(exec, r[src1].u.jsValue, r[src2].u.jsValue);
1128 VM_CHECK_EXCEPTION();
1129 r[dst].u.jsValue = result;
1133 BEGIN_OPCODE(op_mul) {
1134 /* mul dst(r) src1(r) src2(r)
1136 Multiplies register src1 and register src2 (converted to
1137 numbers), and puts the product in register dst.
1139 int dst = (++vPC)->u.operand;
1140 int src1 = (++vPC)->u.operand;
1141 int src2 = (++vPC)->u.operand;
1142 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) * r[src2].u.jsValue->toNumber(exec));
1143 VM_CHECK_EXCEPTION();
1144 r[dst].u.jsValue = result;
1149 BEGIN_OPCODE(op_div) {
1150 /* div dst(r) dividend(r) divisor(r)
1152 Divides register dividend (converted to number) by the
1153 register divisor (converted to number), and puts the
1154 quotient in register dst.
1156 int dst = (++vPC)->u.operand;
1157 int dividend = (++vPC)->u.operand;
1158 int divisor = (++vPC)->u.operand;
1159 JSValue* result = jsNumber(r[dividend].u.jsValue->toNumber(exec) / r[divisor].u.jsValue->toNumber(exec));
1160 VM_CHECK_EXCEPTION();
1161 r[dst].u.jsValue = result;
1165 BEGIN_OPCODE(op_mod) {
1166 /* mod dst(r) dividend(r) divisor(r)
1168 Divides register dividend (converted to number) by
1169 register divisor (converted to number), and puts the
1170 remainder in register dst.
1172 int dst = (++vPC)->u.operand;
1173 int dividend = (++vPC)->u.operand;
1174 int divisor = (++vPC)->u.operand;
1175 double d = r[dividend].u.jsValue->toNumber(exec);
1176 JSValue* result = jsNumber(fmod(d, r[divisor].u.jsValue->toNumber(exec)));
1177 VM_CHECK_EXCEPTION();
1178 r[dst].u.jsValue = result;
1182 BEGIN_OPCODE(op_sub) {
1183 /* sub dst(r) src1(r) src2(r)
1185 Subtracts register src2 (converted to number) from register
1186 src1 (converted to number), and puts the difference in
1189 int dst = (++vPC)->u.operand;
1190 int src1 = (++vPC)->u.operand;
1191 int src2 = (++vPC)->u.operand;
1192 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) - r[src2].u.jsValue->toNumber(exec));
1193 VM_CHECK_EXCEPTION();
1194 r[dst].u.jsValue = result;
1198 BEGIN_OPCODE(op_lshift) {
1199 /* lshift dst(r) val(r) shift(r)
1201 Performs left shift of register val (converted to int32) by
1202 register shift (converted to uint32), and puts the result
1205 int dst = (++vPC)->u.operand;
1206 int val = (++vPC)->u.operand;
1207 int shift = (++vPC)->u.operand;
1208 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) << (r[shift].u.jsValue->toUInt32(exec)));
1209 VM_CHECK_EXCEPTION();
1210 r[dst].u.jsValue = result;
1215 BEGIN_OPCODE(op_rshift) {
1216 /* rshift dst(r) val(r) shift(r)
1218 Performs arithmetic right shift of register val (converted
1219 to int32) by register shift (converted to
1220 uint32), and puts the result in register dst.
1222 int dst = (++vPC)->u.operand;
1223 int val = (++vPC)->u.operand;
1224 int shift = (++vPC)->u.operand;
1225 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1226 VM_CHECK_EXCEPTION();
1227 r[dst].u.jsValue = result;
1232 BEGIN_OPCODE(op_urshift) {
1233 /* rshift dst(r) val(r) shift(r)
1235 Performs logical right shift of register val (converted
1236 to uint32) by register shift (converted to
1237 uint32), and puts the result in register dst.
1239 int dst = (++vPC)->u.operand;
1240 int val = (++vPC)->u.operand;
1241 int shift = (++vPC)->u.operand;
1242 JSValue* result = jsNumber((r[val].u.jsValue->toUInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1243 VM_CHECK_EXCEPTION();
1244 r[dst].u.jsValue = result;
1249 BEGIN_OPCODE(op_bitand) {
1250 /* bitand dst(r) src1(r) src2(r)
1252 Computes bitwise AND of register src1 (converted to int32)
1253 and register src2 (converted to int32), and puts the result
1256 int dst = (++vPC)->u.operand;
1257 int src1 = (++vPC)->u.operand;
1258 int src2 = (++vPC)->u.operand;
1259 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) & (r[src2].u.jsValue->toInt32(exec)));
1260 VM_CHECK_EXCEPTION();
1261 r[dst].u.jsValue = result;
1266 BEGIN_OPCODE(op_bitxor) {
1267 /* bitxor dst(r) src1(r) src2(r)
1269 Computes bitwise XOR of register src1 (converted to int32)
1270 and register src2 (converted to int32), and puts the result
1273 int dst = (++vPC)->u.operand;
1274 int src1 = (++vPC)->u.operand;
1275 int src2 = (++vPC)->u.operand;
1276 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) ^ (r[src2].u.jsValue->toInt32(exec)));
1277 VM_CHECK_EXCEPTION();
1278 r[dst].u.jsValue = result;
1283 BEGIN_OPCODE(op_bitor) {
1284 /* bitor dst(r) src1(r) src2(r)
1286 Computes bitwise OR of register src1 (converted to int32)
1287 and register src2 (converted to int32), and puts the
1288 result in register dst.
1290 int dst = (++vPC)->u.operand;
1291 int src1 = (++vPC)->u.operand;
1292 int src2 = (++vPC)->u.operand;
1293 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) | (r[src2].u.jsValue->toInt32(exec)));
1294 VM_CHECK_EXCEPTION();
1295 r[dst].u.jsValue = result;
1300 BEGIN_OPCODE(op_bitnot) {
1301 /* bitnot dst(r) src(r)
1303 Computes bitwise NOT of register src1 (converted to int32),
1304 and puts the result in register dst.
1306 int dst = (++vPC)->u.operand;
1307 int src = (++vPC)->u.operand;
1308 JSValue* result = jsNumber(~r[src].u.jsValue->toInt32(exec));
1309 VM_CHECK_EXCEPTION();
1310 r[dst].u.jsValue = result;
1315 BEGIN_OPCODE(op_not) {
1316 /* not dst(r) src1(r) src2(r)
1318 Computes logical NOT of register src1 (converted to
1319 boolean), and puts the result in register dst.
1321 int dst = (++vPC)->u.operand;
1322 int src = (++vPC)->u.operand;
1323 JSValue* result = jsBoolean(!r[src].u.jsValue->toBoolean(exec));
1324 VM_CHECK_EXCEPTION();
1325 r[dst].u.jsValue = result;
1330 BEGIN_OPCODE(op_instanceof) {
1331 /* instanceof dst(r) value(r) constructor(r)
1333 Tests whether register value is an instance of register
1334 constructor, and puts the boolean result in register dst.
1336 Raises an exception if register constructor is not an
1339 int dst = (++vPC)->u.operand;
1340 int value = (++vPC)->u.operand;
1341 int base = (++vPC)->u.operand;
1343 JSValue* baseVal = r[base].u.jsValue;
1345 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1348 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1349 r[dst].u.jsValue = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].u.jsValue) : false);
1354 BEGIN_OPCODE(op_typeof) {
1355 /* typeof dst(r) src(r)
1357 Determines the type string for src according to ECMAScript
1358 rules, and puts the result in register dst.
1360 int dst = (++vPC)->u.operand;
1361 int src = (++vPC)->u.operand;
1362 r[dst].u.jsValue = jsTypeStringForValue(r[src].u.jsValue);
1367 BEGIN_OPCODE(op_in) {
1368 /* in dst(r) property(r) base(r)
1370 Tests whether register base has a property named register
1371 property, and puts the boolean result in register dst.
1373 Raises an exception if register constructor is not an
1376 int dst = (++vPC)->u.operand;
1377 int property = (++vPC)->u.operand;
1378 int base = (++vPC)->u.operand;
1380 JSValue* baseVal = r[base].u.jsValue;
1381 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1384 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1386 JSValue* propName = r[property].u.jsValue;
1389 if (propName->getUInt32(i))
1390 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, i));
1392 Identifier property(propName->toString(exec));
1393 VM_CHECK_EXCEPTION();
1394 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, property));
1400 BEGIN_OPCODE(op_resolve) {
1401 /* resolve dst(r) property(id)
1403 Looks up the property named by identifier property in the
1404 scope chain, and writes the resulting value to register
1405 dst. If the property is not found, raises an exception.
1407 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1413 BEGIN_OPCODE(op_resolve_skip) {
1414 /* resolve_skip dst(r) property(id) skip(n)
1416 Looks up the property named by identifier property in the
1417 scope chain skipping the top 'skip' levels, and writes the resulting
1418 value to register dst. If the property is not found, raises an exception.
1420 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1427 BEGIN_OPCODE(op_get_scoped_var) {
1428 /* get_scoped_var dst(r) index(n) skip(n)
1430 Loads the contents of the index-th local from the scope skip nodes from
1431 the top of the scope chain, and places it in register dst
1433 int dst = (++vPC)->u.operand;
1434 int index = (++vPC)->u.operand;
1435 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1437 ScopeChainIterator iter = scopeChain->begin();
1438 ScopeChainIterator end = scopeChain->end();
1439 ASSERT(iter != end);
1442 ASSERT(iter != end);
1445 ASSERT((*iter)->isVariableObject());
1446 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1447 r[dst].u.jsValue = scope->valueAt(index);
1451 BEGIN_OPCODE(op_put_scoped_var) {
1452 /* put_scoped_var index(n) skip(n) value(r)
1455 int index = (++vPC)->u.operand;
1456 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1457 int value = (++vPC)->u.operand;
1459 ScopeChainIterator iter = scopeChain->begin();
1460 ScopeChainIterator end = scopeChain->end();
1461 ASSERT(iter != end);
1464 ASSERT(iter != end);
1467 ASSERT((*iter)->isVariableObject());
1468 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1469 scope->valueAt(index) = r[value].u.jsValue;
1473 BEGIN_OPCODE(op_resolve_base) {
1474 /* resolve_base dst(r) property(id)
1476 Searches the scope chain for an object containing
1477 identifier property, and if one is found, writes it to
1478 register dst. If none is found, the outermost scope (which
1479 will be the global object) is stored in register dst.
1481 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1486 BEGIN_OPCODE(op_resolve_with_base) {
1487 /* resolve_with_base baseDst(r) propDst(r) property(id)
1489 Searches the scope chain for an object containing
1490 identifier property, and if one is found, writes it to
1491 register srcDst, and the retrieved property value to register
1492 propDst. If the property is not found, raises an exception.
1494 This is more efficient than doing resolve_base followed by
1495 resolve, or resolve_base followed by get_by_id, as it
1496 avoids duplicate hash lookups.
1498 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1504 BEGIN_OPCODE(op_resolve_func) {
1505 /* resolve_func baseDst(r) funcDst(r) property(id)
1507 Searches the scope chain for an object containing
1508 identifier property, and if one is found, writes the
1509 appropriate object to use as "this" when calling its
1510 properties to register baseDst; and the retrieved property
1511 value to register propDst. If the property is not found,
1512 raises an exception.
1514 This differs from resolve_with_base, because the
1515 global this value will be substituted for activations or
1516 the global object, which is the right behavior for function
1517 calls but not for other property lookup.
1519 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1525 BEGIN_OPCODE(op_get_by_id) {
1526 /* get_by_id dst(r) base(r) property(id)
1528 Converts register base to Object, gets the property
1529 named by identifier property from the object, and puts the
1530 result in register dst.
1532 int dst = (++vPC)->u.operand;
1533 int base = (++vPC)->u.operand;
1534 int property = (++vPC)->u.operand;
1536 int registerOffset = r - (*registerBase);
1538 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1540 Identifier& ident = codeBlock->identifiers[property];
1541 JSValue *result = baseObj->get(exec, ident);
1542 ASSERT(registerOffset == (r - (*registerBase)));
1543 VM_CHECK_EXCEPTION();
1544 r[dst].u.jsValue = result;
1548 BEGIN_OPCODE(op_put_by_id) {
1549 /* put_by_id base(r) property(id) value(r)
1551 Sets register value on register base as the property named
1552 by identifier property. Base is converted to object first.
1554 Unlike many opcodes, this one does not write any output to
1557 int base = (++vPC)->u.operand;
1558 int property = (++vPC)->u.operand;
1559 int value = (++vPC)->u.operand;
1561 int registerOffset = r - (*registerBase);
1564 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1566 Identifier& ident = codeBlock->identifiers[property];
1567 baseObj->put(exec, ident, r[value].u.jsValue);
1568 ASSERT(registerOffset == (r - (*registerBase)));
1570 VM_CHECK_EXCEPTION();
1574 BEGIN_OPCODE(op_del_by_id) {
1575 /* del_by_id dst(r) base(r) property(id)
1577 Converts register base to Object, deletes the property
1578 named by identifier property from the object, and writes a
1579 boolean indicating success (if true) or failure (if false)
1582 int dst = (++vPC)->u.operand;
1583 int base = (++vPC)->u.operand;
1584 int property = (++vPC)->u.operand;
1586 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1588 Identifier& ident = codeBlock->identifiers[property];
1589 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1590 VM_CHECK_EXCEPTION();
1591 r[dst].u.jsValue = result;
1595 BEGIN_OPCODE(op_get_by_val) {
1596 /* get_by_val dst(r) base(r) property(r)
1598 Converts register base to Object, gets the property named
1599 by register property from the object, and puts the result
1600 in register dst. property is nominally converted to string
1601 but numbers are treated more efficiently.
1603 int dst = (++vPC)->u.operand;
1604 int base = (++vPC)->u.operand;
1605 int property = (++vPC)->u.operand;
1607 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1609 JSValue* subscript = r[property].u.jsValue;
1612 if (subscript->getUInt32(i))
1613 result = baseObj->get(exec, i);
1615 Identifier property;
1616 if (subscript->isObject()) {
1617 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1618 property = Identifier(subscript->toString(exec));
1620 property = Identifier(subscript->toString(exec));
1622 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a getter after an exception is thrown
1623 result = baseObj->get(exec, property);
1626 VM_CHECK_EXCEPTION();
1627 r[dst].u.jsValue = result;
1631 BEGIN_OPCODE(op_put_by_val) {
1632 /* put_by_val base(r) property(r) value(r)
1634 Sets register value on register base as the property named
1635 by register property. Base is converted to object
1636 first. register property is nominally converted to string
1637 but numbers are treated more efficiently.
1639 Unlike many opcodes, this one does not write any output to
1642 int base = (++vPC)->u.operand;
1643 int property = (++vPC)->u.operand;
1644 int value = (++vPC)->u.operand;
1646 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1648 JSValue* subscript = r[property].u.jsValue;
1651 if (subscript->getUInt32(i))
1652 baseObj->put(exec, i, r[value].u.jsValue);
1654 Identifier property;
1655 if (subscript->isObject()) {
1656 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1657 property = Identifier(subscript->toString(exec));
1659 property = Identifier(subscript->toString(exec));
1661 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a setter after an exception is thrown
1662 baseObj->put(exec, property, r[value].u.jsValue);
1665 VM_CHECK_EXCEPTION();
1669 BEGIN_OPCODE(op_del_by_val) {
1670 /* del_by_val dst(r) base(r) property(r)
1672 Converts register base to Object, deletes the property
1673 named by register property from the object, and writes a
1674 boolean indicating success (if true) or failure (if false)
1677 int dst = (++vPC)->u.operand;
1678 int base = (++vPC)->u.operand;
1679 int property = (++vPC)->u.operand;
1681 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1683 JSValue* subscript = r[property].u.jsValue;
1686 if (subscript->getUInt32(i))
1687 result = jsBoolean(baseObj->deleteProperty(exec, i));
1689 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1690 Identifier property(subscript->toString(exec));
1691 VM_CHECK_EXCEPTION();
1692 result = jsBoolean(baseObj->deleteProperty(exec, property));
1695 VM_CHECK_EXCEPTION();
1696 r[dst].u.jsValue = result;
1700 BEGIN_OPCODE(op_put_by_index) {
1701 /* put_by_index base(r) property(n) value(r)
1703 Sets register value on register base as the property named
1704 by the immediate number property. Base is converted to
1705 object first. register property is nominally converted to
1706 string but numbers are treated more efficiently.
1708 Unlike many opcodes, this one does not write any output to
1711 This opcode is mainly used to initialize array literals.
1713 int base = (++vPC)->u.operand;
1714 unsigned property = (++vPC)->u.operand;
1715 int value = (++vPC)->u.operand;
1717 r[base].u.jsObject->put(exec, property, r[value].u.jsValue);
1722 BEGIN_OPCODE(op_jmp) {
1723 /* jmp target(offset)
1725 Jumps unconditionally to offset target from the current
1728 int target = (++vPC)->u.operand;
1733 BEGIN_OPCODE(op_jtrue) {
1734 /* jtrue cond(r) target(offset)
1736 Jumps to offset target from the current instruction, if and
1737 only if register cond converts to boolean as true.
1739 int cond = (++vPC)->u.operand;
1740 int target = (++vPC)->u.operand;
1741 if (r[cond].u.jsValue->toBoolean(exec)) {
1749 BEGIN_OPCODE(op_jfalse) {
1750 /* jfalse cond(r) target(offset)
1752 Jumps to offset target from the current instruction, if and
1753 only if register cond converts to boolean as false.
1755 int cond = (++vPC)->u.operand;
1756 int target = (++vPC)->u.operand;
1757 if (!r[cond].u.jsValue->toBoolean(exec)) {
1765 BEGIN_OPCODE(op_new_func) {
1766 /* new_func dst(r) func(f)
1768 Constructs a new Function instance from function func and
1769 the current scope chain using the original Function
1770 constructor, using the rules for function declarations, and
1771 puts the result in register dst.
1773 int dst = (++vPC)->u.operand;
1774 int func = (++vPC)->u.operand;
1776 r[dst].u.jsValue = codeBlock->functions[func]->makeFunction(exec, scopeChain);
1781 BEGIN_OPCODE(op_new_func_exp) {
1782 /* new_func_exp dst(r) func(f)
1784 Constructs a new Function instance from function func and
1785 the current scope chain using the original Function
1786 constructor, using the rules for function expressions, and
1787 puts the result in register dst.
1789 int dst = (++vPC)->u.operand;
1790 int func = (++vPC)->u.operand;
1792 r[dst].u.jsValue = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
1797 BEGIN_OPCODE(op_call_eval) {
1798 int r0 = (++vPC)->u.operand;
1799 int r1 = (++vPC)->u.operand;
1800 int r2 = (++vPC)->u.operand;
1801 int argv = (++vPC)->u.operand;
1802 int argc = (++vPC)->u.operand;
1804 JSValue* v = r[r1].u.jsValue;
1805 JSValue* base = r[r2].u.jsValue;
1807 if (base == scopeChain->globalObject() && v == scopeChain->globalObject()->evalFunction()) {
1808 int registerOffset = r - (*registerBase);
1810 JSObject* thisObject = r[codeBlock->thisRegister].u.jsObject;
1812 registerFile->setSafeForReentry(true);
1813 JSValue* result = eval(exec, thisObject, scopeChain, registerFile, r, argv, argc, exceptionValue);
1814 registerFile->setSafeForReentry(false);
1815 r = (*registerBase) + registerOffset;
1820 r[r0].u.jsValue = result;
1826 // We didn't find the blessed version of eval, so reset vPC and process
1827 // this instruction as a normal function call, supplying the proper 'this'
1830 r[r2].u.jsValue = base->toObject(exec)->toThisObject(exec);
1832 #if HAVE(COMPUTED_GOTO)
1833 // Hack around gcc performance quirk by performing an indirect goto
1834 // in order to set the vPC -- attempting to do so directly results in a
1835 // significant regression.
1836 goto *op_call_indirect; // indirect goto -> op_call
1838 // fall through to op_call
1840 BEGIN_OPCODE(op_call) {
1841 int r0 = (++vPC)->u.operand;
1842 int r1 = (++vPC)->u.operand;
1843 int r2 = (++vPC)->u.operand;
1844 int argv = (++vPC)->u.operand;
1845 int argc = (++vPC)->u.operand;
1847 JSValue* v = r[r1].u.jsValue;
1850 CallType callType = v->getCallData(callData);
1852 if (callType == CallTypeJS) {
1853 int registerOffset = r - (*registerBase);
1854 Register* callFrame = r + argv - CallFrameHeaderSize;
1855 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
1857 r[argv].u.jsValue = r2 == missingThisObjectMarker() ? exec->globalThisValue() : r[r2].u.jsValue; // "this" value
1858 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, r0, argv, argc, 0, v);
1860 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
1861 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
1863 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
1864 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
1865 if (UNLIKELY(exceptionValue != 0))
1868 codeBlock = newCodeBlock;
1869 exec->m_callFrameOffset = callFrameOffset;
1870 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
1871 k = codeBlock->jsValues.data();
1872 vPC = codeBlock->instructions.begin();
1877 if (callType == CallTypeNative) {
1878 int registerOffset = r - (*registerBase);
1880 r[argv].u.jsValue = r2 == missingThisObjectMarker() ? exec->globalThisValue() : (r[r2].u.jsValue)->toObject(exec); // "this" value
1881 JSObject* thisObj = static_cast<JSObject*>(r[argv].u.jsValue);
1883 List args(&r[argv + 1].u.jsValue, argc - 1);
1885 registerFile->setSafeForReentry(true);
1886 JSValue* returnValue = static_cast<JSObject*>(v)->callAsFunction(exec, thisObj, args);
1887 registerFile->setSafeForReentry(false);
1889 r = (*registerBase) + registerOffset;
1890 r[r0].u.jsValue = returnValue;
1892 VM_CHECK_EXCEPTION();
1898 ASSERT(callType == CallTypeNone);
1900 exceptionValue = createNotAFunctionError(exec, v, 0);
1903 BEGIN_OPCODE(op_ret) {
1904 int r1 = (++vPC)->u.operand;
1906 CodeBlock* oldCodeBlock = codeBlock;
1908 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
1909 JSValue* returnValue = r[r1].u.jsValue;
1911 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
1912 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
1913 ASSERT(activation->isActivationObject());
1914 activation->copyRegisters();
1917 if (codeBlock->needsFullScopeChain)
1918 scopeChain->deref();
1920 if (callFrame[CalledAsConstructor].u.i && !returnValue->isObject()) {
1921 JSValue* thisObject = callFrame[CallFrameHeaderSize].u.jsValue;
1922 returnValue = thisObject;
1925 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
1929 k = codeBlock->jsValues.data();
1930 vPC = callFrame[ReturnVPC].u.vPC;
1931 setScopeChain(exec, scopeChain, callFrame[CallerScopeChain].u.scopeChain);
1932 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
1933 r = (*registerBase) + callerRegisterOffset;
1934 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
1935 int r0 = callFrame[ReturnValueRegister].u.i;
1936 r[r0].u.jsValue = returnValue;
1940 BEGIN_OPCODE(op_construct) {
1941 int r0 = (++vPC)->u.operand;
1942 int r1 = (++vPC)->u.operand;
1943 int argv = (++vPC)->u.operand;
1944 int argc = (++vPC)->u.operand;
1946 JSValue* v = r[r1].u.jsValue;
1948 ConstructData constructData;
1949 ConstructType constructType = v->getConstructData(constructData);
1951 // Removing this line of code causes a measurable regression on squirrelfish.
1952 JSObject* constructor = static_cast<JSObject*>(v);
1954 if (constructType == ConstructTypeJS) {
1955 int registerOffset = r - (*registerBase);
1956 Register* callFrame = r + argv - CallFrameHeaderSize;
1957 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
1959 JSObject* prototype;
1960 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
1962 prototype = static_cast<JSObject*>(p);
1964 prototype = scopeChain->globalObject()->objectPrototype();
1965 JSObject* newObject = new JSObject(prototype);
1966 r[argv].u.jsValue = newObject; // "this" value
1968 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, r0, argv, argc, 1, constructor);
1970 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
1971 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
1973 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
1974 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
1978 codeBlock = newCodeBlock;
1979 exec->m_callFrameOffset = callFrameOffset;
1980 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
1981 k = codeBlock->jsValues.data();
1982 vPC = codeBlock->instructions.begin();
1987 if (constructType == ConstructTypeNative) {
1988 int registerOffset = r - (*registerBase);
1990 List args(&r[argv + 1].u.jsValue, argc - 1);
1991 registerFile->setSafeForReentry(true);
1992 JSValue* returnValue = constructor->construct(exec, args);
1993 registerFile->setSafeForReentry(false);
1995 r = (*registerBase) + registerOffset;
1996 VM_CHECK_EXCEPTION();
1997 r[r0].u.jsValue = returnValue;
2003 ASSERT(constructType == ConstructTypeNone);
2005 exceptionValue = createNotAConstructorError(exec, v, 0);
2008 BEGIN_OPCODE(op_push_scope) {
2009 /* push_scope scope(r)
2011 Converts register scope to object, and pushes it onto the top
2012 of the current scope chain.
2014 int scope = (++vPC)->u.operand;
2015 JSValue* v = r[scope].u.jsValue;
2016 JSObject* o = v->toObject(exec);
2017 VM_CHECK_EXCEPTION();
2019 setScopeChain(exec, scopeChain, scopeChain->push(o));
2024 BEGIN_OPCODE(op_pop_scope) {
2027 Removes the top item from the current scope chain.
2029 setScopeChain(exec, scopeChain, scopeChain->pop());
2034 BEGIN_OPCODE(op_get_pnames) {
2035 /* get_pnames dst(r) base(r)
2037 Creates a property name list for register base and puts it
2038 in register dst. This is not a true JavaScript value, just
2039 a synthetic value used to keep the iteration state in a
2042 int dst = (++vPC)->u.operand;
2043 int base = (++vPC)->u.operand;
2045 r[dst].u.jsPropertyNameIterator = JSPropertyNameIterator::create(exec, r[base].u.jsValue);
2049 BEGIN_OPCODE(op_next_pname) {
2050 /* next_pname dst(r) iter(r) target(offset)
2052 Tries to copies the next name from property name list in
2053 register iter. If there are names left, then copies one to
2054 register dst, and jumps to offset target. If there are none
2055 left, invalidates the iterator and continues to the next
2058 int dst = (++vPC)->u.operand;
2059 int iter = (++vPC)->u.operand;
2060 int target = (++vPC)->u.operand;
2062 JSPropertyNameIterator* it = r[iter].u.jsPropertyNameIterator;
2063 if (JSValue* temp = it->next(exec)) {
2064 r[dst].u.jsValue = temp;
2073 BEGIN_OPCODE(op_jmp_scopes) {
2074 /* jmp_scopes count(n) target(offset)
2076 Removes the a number of items from the current scope chain
2077 specified by immediate number count, then jumps to offset
2080 int count = (++vPC)->u.operand;
2081 int target = (++vPC)->u.operand;
2083 ScopeChainNode* tmp = scopeChain;
2086 setScopeChain(exec, scopeChain, tmp);
2091 BEGIN_OPCODE(op_catch) {
2092 ASSERT(exceptionValue);
2093 ASSERT(!exec->hadException());
2094 int r0 = (++vPC)->u.operand;
2095 r[r0].u.jsValue = exceptionValue;
2100 BEGIN_OPCODE(op_throw) {
2101 int e = (++vPC)->u.operand;
2102 exceptionValue = r[e].u.jsValue;
2103 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2105 *exception = exceptionValue;
2109 #if HAVE(COMPUTED_GOTO)
2110 // Hack around gcc performance quirk by performing an indirect goto
2111 // in order to set the vPC -- attempting to do so directly results in a
2112 // significant regression.
2113 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2121 BEGIN_OPCODE(op_new_error) {
2122 /* new_error dst(r) type(n) message(k)
2124 Constructs a new Error instance using the original
2125 constructor, using immediate number n as the type and
2126 constant message as the message string. The result is
2127 written to register dst.
2129 int dst = (++vPC)->u.operand;
2130 int type = (++vPC)->u.operand;
2131 int message = (++vPC)->u.operand;
2133 r[dst].u.jsValue = Error::create(exec, (ErrorType)type, k[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2138 BEGIN_OPCODE(op_end) {
2139 if (codeBlock->needsFullScopeChain) {
2140 ASSERT(scopeChain->refCount > 1);
2141 scopeChain->deref();
2143 int r0 = (++vPC)->u.operand;
2144 return r[r0].u.jsValue;
2146 BEGIN_OPCODE(op_put_getter) {
2147 /* put_getter base(r) property(id) function(r)
2149 Sets register function on register base as the getter named
2150 by identifier property. Base and function are assumed to be
2151 objects as this op should only be used for getters defined
2152 in object literal form.
2154 Unlike many opcodes, this one does not write any output to
2157 int base = (++vPC)->u.operand;
2158 int property = (++vPC)->u.operand;
2159 int function = (++vPC)->u.operand;
2161 ASSERT(r[base].u.jsValue->isObject());
2162 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2163 Identifier& ident = codeBlock->identifiers[property];
2164 ASSERT(r[function].u.jsValue->isObject());
2165 baseObj->defineGetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2170 BEGIN_OPCODE(op_put_setter) {
2171 /* put_setter base(r) property(id) function(r)
2173 Sets register function on register base as the setter named
2174 by identifier property. Base and function are assumed to be
2175 objects as this op should only be used for setters defined
2176 in object literal form.
2178 Unlike many opcodes, this one does not write any output to
2181 int base = (++vPC)->u.operand;
2182 int property = (++vPC)->u.operand;
2183 int function = (++vPC)->u.operand;
2185 ASSERT(r[base].u.jsValue->isObject());
2186 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2187 Identifier& ident = codeBlock->identifiers[property];
2188 ASSERT(r[function].u.jsValue->isObject());
2189 baseObj->defineSetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2194 BEGIN_OPCODE(op_jsr) {
2195 /* jsr retAddrDst(r) target(offset)
2197 Places the address of the next instruction into the retAddrDst
2198 register and jumps to offset target from the current instruction.
2200 int retAddrDst = (++vPC)->u.operand;
2201 int target = (++vPC)->u.operand;
2202 r[retAddrDst].u.vPC = vPC + 1;
2207 BEGIN_OPCODE(op_sret) {
2208 /* sret retAddrSrc(r)
2210 Jumps to the address stored in the retAddrSrc register. This
2211 differs from op_jmp because the target address is stored in a
2212 register, not as an immediate.
2214 int retAddrSrc = (++vPC)->u.operand;
2215 vPC = r[retAddrSrc].u.vPC;
2218 BEGIN_OPCODE(op_debug) {
2219 /* debug debugHookID(n) firstLine(n) lastLine(n)
2221 Notifies the debugger of the current state of execution:
2222 didEnterCallFrame; willLeaveCallFrame; or willExecuteStatement.
2224 This opcode is only generated while the debugger is attached.
2227 int registerOffset = r - (*registerBase);
2228 registerFile->setSafeForReentry(true);
2229 debug(exec, vPC, codeBlock, scopeChain, registerBase, r);
2230 registerFile->setSafeForReentry(false);
2231 r = (*registerBase) + registerOffset;
2237 exec->clearException();
2238 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2240 *exception = exceptionValue;
2249 #undef VM_CHECK_EXCEPTION
2252 JSValue* Machine::retrieveArguments(ExecState* exec, FunctionImp* function) const
2254 Register** registerBase;
2255 int callFrameOffset;
2257 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2260 Register* callFrame = (*registerBase) + callFrameOffset;
2261 JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue);
2263 CodeBlock* codeBlock = &function->body->generatedCode();
2264 activation = new JSActivation(function->body, registerBase, callFrameOffset + CallFrameHeaderSize + codeBlock->numLocals);
2265 callFrame[OptionalCalleeActivation].u.jsValue = activation;
2268 return activation->get(exec, exec->propertyNames().arguments);
2271 JSValue* Machine::retrieveCaller(ExecState* exec, FunctionImp* function) const
2273 Register** registerBase;
2274 int callFrameOffset;
2276 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2279 int callerFrameOffset;
2280 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callerFrameOffset))
2283 Register* callerFrame = (*registerBase) + callerFrameOffset;
2284 ASSERT(callerFrame[Callee].u.jsValue);
2285 return callerFrame[Callee].u.jsValue;
2288 bool Machine::getCallFrame(ExecState* exec, FunctionImp* function, Register**& registerBase, int& callFrameOffset) const
2290 callFrameOffset = exec->m_callFrameOffset;
2293 while (callFrameOffset < 0) {
2294 exec = exec->m_prev;
2297 callFrameOffset = exec->m_callFrameOffset;
2300 registerBase = exec->m_registerFile->basePointer();
2301 Register* callFrame = (*registerBase) + callFrameOffset;
2302 if (callFrame[Callee].u.jsValue == function)
2305 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callFrameOffset))
2306 callFrameOffset = -1;
2310 void Machine::getFunctionAndArguments(Register** registerBase, Register* callFrame, FunctionImp*& function, Register*& argv, int& argc)
2312 function = static_cast<FunctionImp*>(callFrame[Callee].u.jsValue);
2313 ASSERT(function->inherits(&FunctionImp::info));
2315 argv = (*registerBase) + callFrame[CallerRegisterOffset].u.i + callFrame[ArgumentStartRegister].u.i + 1; // skip "this"
2316 argc = callFrame[ArgumentCount].u.i - 1; // skip "this"