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)
100 if (JSImmediate::areBothImmediateNumbers(v1, v2))
101 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
107 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
108 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
110 if (wasNotString1 | wasNotString2)
113 return static_cast<const StringImp*>(p1)->value() < static_cast<const StringImp*>(p2)->value();
116 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
122 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
123 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
125 if (wasNotString1 | wasNotString2)
128 return !(static_cast<const StringImp*>(p2)->value() < static_cast<const StringImp*>(p1)->value());
131 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
133 // exception for the Date exception in defaultValue()
134 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
135 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
137 if (p1->isString() || p2->isString()) {
138 UString value = p1->toString(exec) + p2->toString(exec);
140 return throwOutOfMemoryError(exec);
141 return jsString(value);
144 return jsNumber(p1->toNumber(exec) + p2->toNumber(exec));
147 // Fast-path choices here are based on frequency data from SunSpider:
148 // <times> Add case: <t1> <t2>
149 // ---------------------------
150 // 5627160 Add case: 1 1
151 // 247427 Add case: 5 5
152 // 20901 Add case: 5 6
153 // 13978 Add case: 5 1
154 // 4000 Add case: 1 5
157 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
159 JSType t1 = v1->type();
160 JSType t2 = v2->type();
161 const unsigned bothTypes = (t1 << 3) | t2;
163 if (bothTypes == ((NumberType << 3) | NumberType))
164 return jsNumber(v1->uncheckedGetNumber() + v2->uncheckedGetNumber());
165 if (bothTypes == ((StringType << 3) | StringType)) {
166 UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
168 return throwOutOfMemoryError(exec);
169 return jsString(value);
172 // All other cases are pretty uncommon
173 return jsAddSlowCase(exec, v1, v2);
176 static JSValue* jsTypeStringForValue(JSValue* v)
180 return jsString("undefined");
182 return jsString("object");
184 return jsString("boolean");
186 return jsString("number");
188 return jsString("string");
191 // Return "undefined" for objects that should be treated
192 // as null when doing comparisons.
193 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
194 return jsString("undefined");
195 else if (static_cast<JSObject*>(v)->implementsCall())
196 return jsString("function");
199 return jsString("object");
203 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
205 int dst = (vPC + 1)->u.operand;
206 int property = (vPC + 2)->u.operand;
208 ScopeChainIterator iter = scopeChain->begin();
209 ScopeChainIterator end = scopeChain->end();
213 Identifier& ident = codeBlock->identifiers[property];
216 if (o->getPropertySlot(exec, ident, slot)) {
217 JSValue* result = slot.getValue(exec, o, ident);
218 exceptionValue = exec->exception();
221 r[dst].u.jsValue = result;
224 } while (++iter != end);
225 exceptionValue = createUndefinedVariableError(exec, ident);
229 static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
231 int dst = (vPC + 1)->u.operand;
232 int property = (vPC + 2)->u.operand;
233 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
235 ScopeChainIterator iter = scopeChain->begin();
236 ScopeChainIterator end = scopeChain->end();
243 Identifier& ident = codeBlock->identifiers[property];
246 if (o->getPropertySlot(exec, ident, slot)) {
247 JSValue* result = slot.getValue(exec, o, ident);
248 exceptionValue = exec->exception();
251 r[dst].u.jsValue = result;
254 } while (++iter != end);
255 exceptionValue = createUndefinedVariableError(exec, ident);
259 static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
261 int dst = (vPC + 1)->u.operand;
262 int property = (vPC + 2)->u.operand;
264 ScopeChainIterator iter = scopeChain->begin();
265 ScopeChainIterator next = iter;
267 ScopeChainIterator end = scopeChain->end();
271 Identifier& ident = codeBlock->identifiers[property];
275 if (next == end || base->getPropertySlot(exec, ident, slot)) {
276 r[dst].u.jsValue = base;
284 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
286 int baseDst = (vPC + 1)->u.operand;
287 int propDst = (vPC + 2)->u.operand;
288 int property = (vPC + 3)->u.operand;
290 ScopeChainIterator iter = scopeChain->begin();
291 ScopeChainIterator end = scopeChain->end();
293 // FIXME: add scopeDepthIsZero optimization
298 Identifier& ident = codeBlock->identifiers[property];
302 if (base->getPropertySlot(exec, ident, slot)) {
303 JSValue* result = slot.getValue(exec, base, ident);
304 exceptionValue = exec->exception();
307 r[propDst].u.jsValue = result;
308 r[baseDst].u.jsValue = base;
312 } while (iter != end);
314 exceptionValue = createUndefinedVariableError(exec, ident);
318 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
320 int baseDst = (vPC + 1)->u.operand;
321 int funcDst = (vPC + 2)->u.operand;
322 int property = (vPC + 3)->u.operand;
324 ScopeChainIterator iter = scopeChain->begin();
325 ScopeChainIterator end = scopeChain->end();
327 // FIXME: add scopeDepthIsZero optimization
332 Identifier& ident = codeBlock->identifiers[property];
336 if (base->getPropertySlot(exec, ident, slot)) {
337 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
338 // However, section 10.2.3 says that in the case where the value provided
339 // by the caller is null, the global object should be used. It also says
340 // that the section does not apply to internal functions, but for simplicity
341 // of implementation we use the global object anyway here. This guarantees
342 // that in host objects you always get a valid object for this.
343 // We also handle wrapper substitution for the global object at the same time.
344 JSObject* thisObj = base->toThisObject(exec);
345 JSValue* result = slot.getValue(exec, base, ident);
346 exceptionValue = exec->exception();
350 r[baseDst].u.jsValue = thisObj;
351 r[funcDst].u.jsValue = result;
355 } while (iter != end);
357 exceptionValue = createUndefinedVariableError(exec, ident);
361 ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, int registerOffset, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
363 callFrame[Machine::CallerCodeBlock].u.codeBlock = codeBlock;
364 callFrame[Machine::ReturnVPC].u.vPC = vPC + 1;
365 callFrame[Machine::CallerScopeChain].u.scopeChain = scopeChain;
366 callFrame[Machine::CallerRegisterOffset].u.i = registerOffset;
367 callFrame[Machine::ReturnValueRegister].u.i = returnValueRegister;
368 callFrame[Machine::ArgumentStartRegister].u.i = argv; // original argument vector (for the sake of the "arguments" object)
369 callFrame[Machine::ArgumentCount].u.i = argc; // original argument count (for the sake of the "arguments" object)
370 callFrame[Machine::CalledAsConstructor].u.i = calledAsConstructor;
371 callFrame[Machine::Callee].u.jsValue = function;
372 callFrame[Machine::OptionalCalleeActivation].u.jsValue = 0;
375 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register** registerBase, int registerOffset, int argv, int argc, JSValue*& exceptionValue)
378 int oldOffset = registerOffset;
379 registerOffset += argv + newCodeBlock->numLocals;
380 size_t size = registerOffset + newCodeBlock->numTemporaries;
382 if (argc == newCodeBlock->numParameters) { // correct number of arguments
383 if (!registerFile->grow(size)) {
384 exceptionValue = createStackOverflowError(exec);
385 return *registerBase + oldOffset;
387 r = (*registerBase) + registerOffset;
388 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
389 if (!registerFile->grow(size)) {
390 exceptionValue = createStackOverflowError(exec);
391 return *registerBase + oldOffset;
393 r = (*registerBase) + registerOffset;
395 int omittedArgCount = newCodeBlock->numParameters - argc;
396 Register* endOfParams = r - newCodeBlock->numVars;
397 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
398 (*it).u.jsValue = jsUndefined();
399 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
400 int shift = argc + Machine::CallFrameHeaderSize;
401 registerOffset += shift;
404 if (!registerFile->grow(size)) {
405 exceptionValue = createStackOverflowError(exec);
406 return *registerBase + oldOffset;
408 r = (*registerBase) + registerOffset;
410 Register* it = r - newCodeBlock->numLocals - Machine::CallFrameHeaderSize - shift;
411 Register* end = it + Machine::CallFrameHeaderSize + newCodeBlock->numParameters;
412 for ( ; it != end; ++it)
419 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register** registerBase, Register* r)
421 if (newCodeBlock->needsFullScopeChain) {
422 JSActivation* activation = new JSActivation(functionBodyNode, registerBase, r - (*registerBase));
423 r[Machine::OptionalCalleeActivation - Machine::CallFrameHeaderSize - newCodeBlock->numLocals].u.jsValue = activation;
425 return callDataScopeChain->copy()->push(activation);
428 return callDataScopeChain;
431 static NEVER_INLINE bool isNotObject(ExecState* exec, const Instruction*, CodeBlock*, JSValue* value, JSValue*& exceptionData)
433 if (value->isObject())
435 exceptionData = createNotAnObjectError(exec, value, 0);
439 static NEVER_INLINE JSValue* eval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
441 JSValue* x = argc >= 2 ? r[argv + 1].u.jsValue : jsUndefined();
446 UString s = x->toString(exec);
447 if (exec->hadException()) {
448 exceptionValue = exec->exception();
449 exec->clearException();
456 RefPtr<EvalNode> evalNode = parser().parse<EvalNode>(exec, UString(), 0, UStringSourceProvider::create(s), &sourceId, &errLine, &errMsg);
459 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
463 return machine().execute(evalNode.get(), exec, thisObj, registerFile, r - (*registerFile->basePointer()) + argv + argc, scopeChain, &exceptionValue);
468 ASSERT(JSLock::currentThreadIsHoldingLock());
469 static Machine machine;
476 privateExecute(InitializeAndReturn);
479 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
481 ScopeChain sc(scopeChain);
482 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(sc.bottom());
483 codeBlock->dump(globalObject->globalExec());
484 dumpRegisters(codeBlock, registerFile, r);
487 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
489 printf("Register frame: \n\n");
490 printf("----------------------------------------\n");
491 printf(" use | address | value \n");
492 printf("----------------------------------------\n");
497 if (isGlobalCallFrame(registerFile->basePointer(), r)) {
498 it = r - registerFile->numGlobalSlots();
502 printf("[global var] | %10p | %10p \n", it, (*it).u.jsValue);
505 printf("----------------------------------------\n");
508 it = r - codeBlock->numLocals - CallFrameHeaderSize;
509 end = it + CallFrameHeaderSize;
512 printf("[call frame] | %10p | %10p \n", it, (*it).u.jsValue);
515 printf("----------------------------------------\n");
518 end = it + codeBlock->numParameters;
521 printf("[param] | %10p | %10p \n", it, (*it).u.jsValue);
524 printf("----------------------------------------\n");
527 end = it + codeBlock->numVars;
530 printf("[var] | %10p | %10p \n", it, (*it).u.jsValue);
533 printf("----------------------------------------\n");
537 end = it + codeBlock->numTemporaries;
540 printf("[temp] | %10p | %10p \n", it, (*it).u.jsValue);
546 bool Machine::isOpcode(Opcode opcode)
548 #if HAVE(COMPUTED_GOTO)
549 return opcode != HashTraits<Opcode>::emptyValue()
550 && !HashTraits<Opcode>::isDeletedValue(opcode)
551 && m_opcodeIDTable.contains(opcode);
553 return opcode >= 0 && opcode <= op_end;
557 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction*& vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
559 CodeBlock* oldCodeBlock = codeBlock;
561 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
562 if (!isGlobalCallFrame(registerBase, r)) {
563 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
564 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
568 if (oldCodeBlock->needsFullScopeChain)
571 if (isGlobalCallFrame(registerBase, r))
574 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
576 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
580 // If this call frame created an activation, tear it off.
581 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
582 ASSERT(activation->isActivationObject());
583 activation->copyRegisters();
586 k = codeBlock->jsValues.data();
587 scopeChain = callFrame[CallerScopeChain].u.scopeChain;
588 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
589 r = (*registerBase) + callerRegisterOffset;
590 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
591 vPC = callFrame[ReturnVPC].u.vPC;
595 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction* vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
597 // Set up the exception object
599 if (exceptionValue->isObject()) {
600 JSObject* exception = static_cast<JSObject*>(exceptionValue);
601 if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
602 exception->put(exec, "line", jsNumber(codeBlock->lineNumberForVPC(vPC)));
603 exception->put(exec, "sourceURL", jsOwnedString(codeBlock->ownerNode->sourceURL()));
607 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
608 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
609 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
612 // Calculate an exception handler vPC, unwinding call frames as necessary.
615 Instruction* handlerVPC;
617 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth))
618 if (!unwindCallFrame(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r))
621 // Now unwind the scope chain within the exception handler's call frame.
623 ScopeChain sc(scopeChain);
624 int scopeDelta = depth(sc) - scopeDepth;
625 ASSERT(scopeDelta >= 0);
628 setScopeChain(exec, scopeChain, sc.node());
633 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, RegisterFileStack* registerFileStack, JSValue** exception)
635 if (m_reentryDepth >= MaxReentryDepth) {
636 *exception = createStackOverflowError(exec);
640 RegisterFile* registerFile = registerFileStack->pushGlobalRegisterFile();
641 ASSERT(registerFile->numGlobalSlots());
642 CodeBlock* codeBlock = &programNode->code(scopeChain, !registerFileStack->inImplicitCall());
643 registerFile->addGlobalSlots(codeBlock->numVars);
645 registerFile->uncheckedGrow(codeBlock->numTemporaries);
646 Register* r = (*registerFile->basePointer());
648 r[ProgramCodeThisRegister].u.jsValue = thisObj;
650 if (codeBlock->needsFullScopeChain)
651 scopeChain = scopeChain->copy();
653 ExecState newExec(exec, this, registerFile, scopeChain, -1);
656 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
659 registerFileStack->popGlobalRegisterFile();
663 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, FunctionImp* function, JSObject* thisObj, const List& args, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
665 if (m_reentryDepth >= MaxReentryDepth) {
666 *exception = createStackOverflowError(exec);
670 RegisterFile* registerFile = registerFileStack->current();
672 int argv = CallFrameHeaderSize;
673 int argc = args.size() + 1; // implicit "this" parameter
675 size_t oldSize = registerFile->size();
676 if (!registerFile->grow(oldSize + CallFrameHeaderSize + argc)) {
677 *exception = createStackOverflowError(exec);
681 Register** registerBase = registerFile->basePointer();
682 int registerOffset = oldSize;
683 int callFrameOffset = registerOffset;
684 Register* callFrame = (*registerBase) + callFrameOffset;
686 // put args in place, including "this"
687 Register* dst = callFrame + CallFrameHeaderSize;
688 (*dst).u.jsValue = thisObj;
690 List::const_iterator end = args.end();
691 for (List::const_iterator it = args.begin(); it != end; ++it)
692 (*++dst).u.jsValue = *it;
694 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
695 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, argv, argc, 0, function);
697 CodeBlock* newCodeBlock = &functionBodyNode->code(scopeChain);
698 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, *exception);
700 registerFile->shrink(oldSize);
704 scopeChain = scopeChainForCall(functionBodyNode, newCodeBlock, scopeChain, registerBase, r);
706 ExecState newExec(exec, this, registerFile, scopeChain, callFrameOffset);
709 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, newCodeBlock, exception);
712 registerFile->shrink(oldSize);
717 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFile* registerFile, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
719 if (m_reentryDepth >= MaxReentryDepth) {
720 *exception = createStackOverflowError(exec);
723 EvalCodeBlock* codeBlock = &evalNode->code(scopeChain);
725 JSVariableObject* variableObject;
726 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
728 if (node->object->isVariableObject()) {
729 variableObject = static_cast<JSVariableObject*>(node->object);
734 for (Vector<Identifier>::const_iterator iter = codeBlock->declaredVariableNames.begin(); iter != codeBlock->declaredVariableNames.end(); ++iter) {
735 Identifier ident = *iter;
737 if (!variableObject->hasProperty(exec, ident))
738 variableObject->put(exec, ident, jsUndefined());
741 ASSERT(codeBlock->functions.size() == codeBlock->declaredFunctionNames.size());
742 for (size_t i = 0; i < codeBlock->functions.size(); ++i)
743 variableObject->put(exec, codeBlock->declaredFunctionNames[i], codeBlock->functions[i]->makeFunction(exec, scopeChain));
745 size_t oldSize = registerFile->size();
746 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numTemporaries + CallFrameHeaderSize;
747 if (!registerFile->grow(newSize)) {
748 *exception = createStackOverflowError(exec);
752 Register* callFrame = *registerFile->basePointer() + registerOffset;
754 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
755 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, 0, 0, 0, 0);
757 Register* r = callFrame + CallFrameHeaderSize + codeBlock->numVars;
758 r[ProgramCodeThisRegister].u.jsValue = thisObj;
760 if (codeBlock->needsFullScopeChain)
761 scopeChain = scopeChain->copy();
763 ExecState newExec(exec, this, registerFile, scopeChain, -1);
766 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
769 registerFile->shrink(oldSize);
773 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
775 RegisterFile* registerFile = registerFileStack->current();
776 if (registerFile->safeForReentry())
777 return Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
778 registerFile = registerFileStack->pushFunctionRegisterFile();
779 JSValue* result = Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
780 registerFileStack->popFunctionRegisterFile();
784 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
786 scopeChain = newScopeChain;
787 exec->m_scopeChain = newScopeChain;
790 NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register** registerBase, Register* r)
792 int debugHookID = (++vPC)->u.operand;
793 int firstLine = (++vPC)->u.operand;
794 int lastLine = (++vPC)->u.operand;
796 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
800 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, 0, registerBase, r - *registerBase);
802 switch((DebugHookID)debugHookID) {
803 case DidEnterCallFrame: {
804 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
807 case WillLeaveCallFrame: {
808 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
811 case WillExecuteStatement: {
812 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
818 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
820 // One-time initialization of our address tables. We have to put this code
821 // here because our labels are only in scope inside this function.
822 if (flag == InitializeAndReturn) {
823 #if HAVE(COMPUTED_GOTO)
824 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
825 FOR_EACH_OPCODE_ID(ADD_OPCODE);
828 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
829 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
831 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
832 op_throw_end_indirect = &&op_throw_end;
833 op_call_indirect = &&op_call;
834 #endif // HAVE(COMPUTED_GOTO)
838 JSValue* exceptionValue = 0;
839 Instruction* handlerVPC = 0;
841 Register** registerBase = registerFile->basePointer();
842 Instruction* vPC = codeBlock->instructions.begin();
843 JSValue** k = codeBlock->jsValues.data();
845 registerFile->setSafeForReentry(false);
846 #define VM_CHECK_EXCEPTION() \
848 if (UNLIKELY(exec->hadException())) { \
849 exceptionValue = exec->exception(); \
854 #if HAVE(COMPUTED_GOTO)
855 #define NEXT_OPCODE goto *vPC->u.opcode
856 #define BEGIN_OPCODE(opcode) opcode:
859 #define NEXT_OPCODE continue
860 #define BEGIN_OPCODE(opcode) case opcode:
861 while(1) // iterator loop begins
862 switch (vPC->u.opcode)
865 BEGIN_OPCODE(op_load) {
866 /* load dst(r) src(k)
868 Copies constant src to register dst.
870 int dst = (++vPC)->u.operand;
871 int src = (++vPC)->u.operand;
872 r[dst].u.jsValue = k[src];
877 BEGIN_OPCODE(op_new_object) {
880 Constructs a new empty Object instance using the original
881 constructor, and puts the result in register dst.
883 int dst = (++vPC)->u.operand;
884 r[dst].u.jsValue = scopeChain->globalObject()->objectConstructor()->construct(exec, exec->emptyList());
889 BEGIN_OPCODE(op_new_array) {
892 Constructs a new empty Array instance using the original
893 constructor, and puts the result in register dst.
895 int dst = (++vPC)->u.operand;
896 r[dst].u.jsValue = scopeChain->globalObject()->arrayConstructor()->construct(exec, exec->emptyList());
901 BEGIN_OPCODE(op_new_regexp) {
902 /* new_regexp dst(r) regExp(re)
904 Constructs a new RegExp instance using the original
905 constructor from regexp regExp, and puts the result in
908 int dst = (++vPC)->u.operand;
909 int regExp = (++vPC)->u.operand;
910 r[dst].u.jsValue = new RegExpImp(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
915 BEGIN_OPCODE(op_mov) {
918 Copies register src to register dst.
920 int dst = (++vPC)->u.operand;
921 int src = (++vPC)->u.operand;
927 BEGIN_OPCODE(op_eq) {
928 /* eq dst(r) src1(r) src2(r)
930 Checks whether register src1 and register src2 are equal,
931 as with the ECMAScript '==' operator, and puts the result
932 as a boolean in register dst.
934 int dst = (++vPC)->u.operand;
935 int src1 = (++vPC)->u.operand;
936 int src2 = (++vPC)->u.operand;
937 JSValue* result = jsBoolean(equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
938 VM_CHECK_EXCEPTION();
939 r[dst].u.jsValue = result;
944 BEGIN_OPCODE(op_neq) {
945 /* neq dst(r) src1(r) src2(r)
947 Checks whether register src1 and register src2 are not
948 equal, as with the ECMAScript '!=' operator, and puts the
949 result as a boolean in register dst.
951 int dst = (++vPC)->u.operand;
952 int src1 = (++vPC)->u.operand;
953 int src2 = (++vPC)->u.operand;
954 JSValue* result = jsBoolean(!equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
955 VM_CHECK_EXCEPTION();
956 r[dst].u.jsValue = result;
961 BEGIN_OPCODE(op_stricteq) {
962 /* stricteq dst(r) src1(r) src2(r)
964 Checks whether register src1 and register src2 are strictly
965 equal, as with the ECMAScript '===' operator, and puts the
966 result as a boolean in register dst.
968 int dst = (++vPC)->u.operand;
969 int src1 = (++vPC)->u.operand;
970 int src2 = (++vPC)->u.operand;
971 r[dst].u.jsValue = jsBoolean(strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
976 BEGIN_OPCODE(op_nstricteq) {
977 /* nstricteq dst(r) src1(r) src2(r)
979 Checks whether register src1 and register src2 are not
980 strictly equal, as with the ECMAScript '!==' operator, and
981 puts the result as a boolean in register dst.
983 int dst = (++vPC)->u.operand;
984 int src1 = (++vPC)->u.operand;
985 int src2 = (++vPC)->u.operand;
986 r[dst].u.jsValue = jsBoolean(!strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
991 BEGIN_OPCODE(op_less) {
992 /* less dst(r) src1(r) src2(r)
994 Checks whether register src1 is less than register src2, as
995 with the ECMAScript '<' operator, and puts the result as
996 a boolean in register dst.
998 int dst = (++vPC)->u.operand;
999 int src1 = (++vPC)->u.operand;
1000 int src2 = (++vPC)->u.operand;
1001 JSValue* result = jsBoolean(jsLess(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1002 VM_CHECK_EXCEPTION();
1003 r[dst].u.jsValue = result;
1008 BEGIN_OPCODE(op_lesseq) {
1009 /* lesseq dst(r) src1(r) src2(r)
1011 Checks whether register src1 is less than or equal to
1012 register src2, as with the ECMAScript '<=' operator, and
1013 puts the result as a boolean in register dst.
1015 int dst = (++vPC)->u.operand;
1016 int src1 = (++vPC)->u.operand;
1017 int src2 = (++vPC)->u.operand;
1018 JSValue* result = jsBoolean(jsLessEq(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1019 VM_CHECK_EXCEPTION();
1020 r[dst].u.jsValue = result;
1025 BEGIN_OPCODE(op_pre_inc) {
1026 /* pre_inc srcDst(r)
1028 Converts register srcDst to number, adds one, and puts the result
1029 back in register srcDst.
1031 int srcDst = (++vPC)->u.operand;
1032 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) + 1);
1033 VM_CHECK_EXCEPTION();
1034 r[srcDst].u.jsValue = result;
1039 BEGIN_OPCODE(op_pre_dec) {
1040 /* pre_dec srcDst(r)
1042 Converts register srcDst to number, subtracts one, and puts the result
1043 back in register srcDst.
1045 int srcDst = (++vPC)->u.operand;
1046 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) - 1);
1047 VM_CHECK_EXCEPTION();
1048 r[srcDst].u.jsValue = result;
1053 BEGIN_OPCODE(op_post_inc) {
1054 /* post_inc dst(r) srcDst(r)
1056 Converts register srcDst to number. The number itself is
1057 written to register dst, and the number plus one is written
1058 back to register srcDst.
1060 int dst = (++vPC)->u.operand;
1061 int srcDst = (++vPC)->u.operand;
1062 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1063 VM_CHECK_EXCEPTION();
1065 r[dst].u.jsValue = number;
1066 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() + 1);
1071 BEGIN_OPCODE(op_post_dec) {
1072 /* post_dec dst(r) srcDst(r)
1074 Converts register srcDst to number. The number itself is
1075 written to register dst, and the number minus one is written
1076 back to register srcDst.
1078 int dst = (++vPC)->u.operand;
1079 int srcDst = (++vPC)->u.operand;
1080 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1081 VM_CHECK_EXCEPTION();
1083 r[dst].u.jsValue = number;
1084 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() - 1);
1089 BEGIN_OPCODE(op_to_jsnumber) {
1090 /* to_jsnumber dst(r) src(r)
1092 Converts register src to number, and puts the result
1095 int dst = (++vPC)->u.operand;
1096 int src = (++vPC)->u.operand;
1097 JSValue* result = r[src].u.jsValue->toJSNumber(exec);
1098 VM_CHECK_EXCEPTION();
1100 r[dst].u.jsValue = result;
1105 BEGIN_OPCODE(op_negate) {
1106 /* negate dst(r) src(r)
1108 Converts register src to number, negates it, and puts the
1109 result in register dst.
1111 int dst = (++vPC)->u.operand;
1112 int src = (++vPC)->u.operand;
1113 JSValue* result = jsNumber(-r[src].u.jsValue->toNumber(exec));
1114 VM_CHECK_EXCEPTION();
1115 r[dst].u.jsValue = result;
1120 BEGIN_OPCODE(op_add) {
1121 /* add dst(r) src1(r) src2(r)
1123 Adds register src1 and register src2, and puts the result
1124 in register dst. (JS add may be string concatenation or
1125 numeric add, depending on the types of the operands.)
1127 int dst = (++vPC)->u.operand;
1128 int src1 = (++vPC)->u.operand;
1129 int src2 = (++vPC)->u.operand;
1130 JSValue* result = jsAdd(exec, r[src1].u.jsValue, r[src2].u.jsValue);
1131 VM_CHECK_EXCEPTION();
1132 r[dst].u.jsValue = result;
1136 BEGIN_OPCODE(op_mul) {
1137 /* mul dst(r) src1(r) src2(r)
1139 Multiplies register src1 and register src2 (converted to
1140 numbers), and puts the product in register dst.
1142 int dst = (++vPC)->u.operand;
1143 int src1 = (++vPC)->u.operand;
1144 int src2 = (++vPC)->u.operand;
1145 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) * r[src2].u.jsValue->toNumber(exec));
1146 VM_CHECK_EXCEPTION();
1147 r[dst].u.jsValue = result;
1152 BEGIN_OPCODE(op_div) {
1153 /* div dst(r) dividend(r) divisor(r)
1155 Divides register dividend (converted to number) by the
1156 register divisor (converted to number), and puts the
1157 quotient in register dst.
1159 int dst = (++vPC)->u.operand;
1160 int dividend = (++vPC)->u.operand;
1161 int divisor = (++vPC)->u.operand;
1162 JSValue* result = jsNumber(r[dividend].u.jsValue->toNumber(exec) / r[divisor].u.jsValue->toNumber(exec));
1163 VM_CHECK_EXCEPTION();
1164 r[dst].u.jsValue = result;
1168 BEGIN_OPCODE(op_mod) {
1169 /* mod dst(r) dividend(r) divisor(r)
1171 Divides register dividend (converted to number) by
1172 register divisor (converted to number), and puts the
1173 remainder in register dst.
1175 int dst = (++vPC)->u.operand;
1176 int dividend = (++vPC)->u.operand;
1177 int divisor = (++vPC)->u.operand;
1178 double d = r[dividend].u.jsValue->toNumber(exec);
1179 JSValue* result = jsNumber(fmod(d, r[divisor].u.jsValue->toNumber(exec)));
1180 VM_CHECK_EXCEPTION();
1181 r[dst].u.jsValue = result;
1185 BEGIN_OPCODE(op_sub) {
1186 /* sub dst(r) src1(r) src2(r)
1188 Subtracts register src2 (converted to number) from register
1189 src1 (converted to number), and puts the difference in
1192 int dst = (++vPC)->u.operand;
1193 int src1 = (++vPC)->u.operand;
1194 int src2 = (++vPC)->u.operand;
1195 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) - r[src2].u.jsValue->toNumber(exec));
1196 VM_CHECK_EXCEPTION();
1197 r[dst].u.jsValue = result;
1201 BEGIN_OPCODE(op_lshift) {
1202 /* lshift dst(r) val(r) shift(r)
1204 Performs left shift of register val (converted to int32) by
1205 register shift (converted to uint32), and puts the result
1208 int dst = (++vPC)->u.operand;
1209 int val = (++vPC)->u.operand;
1210 int shift = (++vPC)->u.operand;
1211 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) << (r[shift].u.jsValue->toUInt32(exec)));
1212 VM_CHECK_EXCEPTION();
1213 r[dst].u.jsValue = result;
1218 BEGIN_OPCODE(op_rshift) {
1219 /* rshift dst(r) val(r) shift(r)
1221 Performs arithmetic right shift of register val (converted
1222 to int32) by register shift (converted to
1223 uint32), and puts the result in register dst.
1225 int dst = (++vPC)->u.operand;
1226 int val = (++vPC)->u.operand;
1227 int shift = (++vPC)->u.operand;
1228 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1229 VM_CHECK_EXCEPTION();
1230 r[dst].u.jsValue = result;
1235 BEGIN_OPCODE(op_urshift) {
1236 /* rshift dst(r) val(r) shift(r)
1238 Performs logical right shift of register val (converted
1239 to uint32) by register shift (converted to
1240 uint32), and puts the result in register dst.
1242 int dst = (++vPC)->u.operand;
1243 int val = (++vPC)->u.operand;
1244 int shift = (++vPC)->u.operand;
1245 JSValue* result = jsNumber((r[val].u.jsValue->toUInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1246 VM_CHECK_EXCEPTION();
1247 r[dst].u.jsValue = result;
1252 BEGIN_OPCODE(op_bitand) {
1253 /* bitand dst(r) src1(r) src2(r)
1255 Computes bitwise AND of register src1 (converted to int32)
1256 and register src2 (converted to int32), and puts the result
1259 int dst = (++vPC)->u.operand;
1260 int src1 = (++vPC)->u.operand;
1261 int src2 = (++vPC)->u.operand;
1262 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) & (r[src2].u.jsValue->toInt32(exec)));
1263 VM_CHECK_EXCEPTION();
1264 r[dst].u.jsValue = result;
1269 BEGIN_OPCODE(op_bitxor) {
1270 /* bitxor dst(r) src1(r) src2(r)
1272 Computes bitwise XOR of register src1 (converted to int32)
1273 and register src2 (converted to int32), and puts the result
1276 int dst = (++vPC)->u.operand;
1277 int src1 = (++vPC)->u.operand;
1278 int src2 = (++vPC)->u.operand;
1279 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) ^ (r[src2].u.jsValue->toInt32(exec)));
1280 VM_CHECK_EXCEPTION();
1281 r[dst].u.jsValue = result;
1286 BEGIN_OPCODE(op_bitor) {
1287 /* bitor dst(r) src1(r) src2(r)
1289 Computes bitwise OR of register src1 (converted to int32)
1290 and register src2 (converted to int32), and puts the
1291 result in register dst.
1293 int dst = (++vPC)->u.operand;
1294 int src1 = (++vPC)->u.operand;
1295 int src2 = (++vPC)->u.operand;
1296 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) | (r[src2].u.jsValue->toInt32(exec)));
1297 VM_CHECK_EXCEPTION();
1298 r[dst].u.jsValue = result;
1303 BEGIN_OPCODE(op_bitnot) {
1304 /* bitnot dst(r) src(r)
1306 Computes bitwise NOT of register src1 (converted to int32),
1307 and puts the result in register dst.
1309 int dst = (++vPC)->u.operand;
1310 int src = (++vPC)->u.operand;
1311 JSValue* result = jsNumber(~r[src].u.jsValue->toInt32(exec));
1312 VM_CHECK_EXCEPTION();
1313 r[dst].u.jsValue = result;
1318 BEGIN_OPCODE(op_not) {
1319 /* not dst(r) src1(r) src2(r)
1321 Computes logical NOT of register src1 (converted to
1322 boolean), and puts the result in register dst.
1324 int dst = (++vPC)->u.operand;
1325 int src = (++vPC)->u.operand;
1326 JSValue* result = jsBoolean(!r[src].u.jsValue->toBoolean(exec));
1327 VM_CHECK_EXCEPTION();
1328 r[dst].u.jsValue = result;
1333 BEGIN_OPCODE(op_instanceof) {
1334 /* instanceof dst(r) value(r) constructor(r)
1336 Tests whether register value is an instance of register
1337 constructor, and puts the boolean result in register dst.
1339 Raises an exception if register constructor is not an
1342 int dst = (++vPC)->u.operand;
1343 int value = (++vPC)->u.operand;
1344 int base = (++vPC)->u.operand;
1346 JSValue* baseVal = r[base].u.jsValue;
1348 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1351 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1352 r[dst].u.jsValue = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].u.jsValue) : false);
1357 BEGIN_OPCODE(op_typeof) {
1358 /* typeof dst(r) src(r)
1360 Determines the type string for src according to ECMAScript
1361 rules, and puts the result in register dst.
1363 int dst = (++vPC)->u.operand;
1364 int src = (++vPC)->u.operand;
1365 r[dst].u.jsValue = jsTypeStringForValue(r[src].u.jsValue);
1370 BEGIN_OPCODE(op_in) {
1371 /* in dst(r) property(r) base(r)
1373 Tests whether register base has a property named register
1374 property, and puts the boolean result in register dst.
1376 Raises an exception if register constructor is not an
1379 int dst = (++vPC)->u.operand;
1380 int property = (++vPC)->u.operand;
1381 int base = (++vPC)->u.operand;
1383 JSValue* baseVal = r[base].u.jsValue;
1384 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1387 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1389 JSValue* propName = r[property].u.jsValue;
1392 if (propName->getUInt32(i))
1393 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, i));
1395 Identifier property(propName->toString(exec));
1396 VM_CHECK_EXCEPTION();
1397 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, property));
1403 BEGIN_OPCODE(op_resolve) {
1404 /* resolve dst(r) property(id)
1406 Looks up the property named by identifier property in the
1407 scope chain, and writes the resulting value to register
1408 dst. If the property is not found, raises an exception.
1410 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1416 BEGIN_OPCODE(op_resolve_skip) {
1417 /* resolve_skip dst(r) property(id) skip(n)
1419 Looks up the property named by identifier property in the
1420 scope chain skipping the top 'skip' levels, and writes the resulting
1421 value to register dst. If the property is not found, raises an exception.
1423 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1430 BEGIN_OPCODE(op_get_scoped_var) {
1431 /* get_scoped_var dst(r) index(n) skip(n)
1433 Loads the contents of the index-th local from the scope skip nodes from
1434 the top of the scope chain, and places it in register dst
1436 int dst = (++vPC)->u.operand;
1437 int index = (++vPC)->u.operand;
1438 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1440 ScopeChainIterator iter = scopeChain->begin();
1441 ScopeChainIterator end = scopeChain->end();
1442 ASSERT(iter != end);
1445 ASSERT(iter != end);
1448 ASSERT((*iter)->isVariableObject());
1449 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1450 r[dst].u.jsValue = scope->valueAt(index);
1454 BEGIN_OPCODE(op_put_scoped_var) {
1455 /* put_scoped_var index(n) skip(n) value(r)
1458 int index = (++vPC)->u.operand;
1459 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1460 int value = (++vPC)->u.operand;
1462 ScopeChainIterator iter = scopeChain->begin();
1463 ScopeChainIterator end = scopeChain->end();
1464 ASSERT(iter != end);
1467 ASSERT(iter != end);
1470 ASSERT((*iter)->isVariableObject());
1471 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1472 scope->valueAt(index) = r[value].u.jsValue;
1476 BEGIN_OPCODE(op_resolve_base) {
1477 /* resolve_base dst(r) property(id)
1479 Searches the scope chain for an object containing
1480 identifier property, and if one is found, writes it to
1481 register dst. If none is found, the outermost scope (which
1482 will be the global object) is stored in register dst.
1484 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1489 BEGIN_OPCODE(op_resolve_with_base) {
1490 /* resolve_with_base baseDst(r) propDst(r) property(id)
1492 Searches the scope chain for an object containing
1493 identifier property, and if one is found, writes it to
1494 register srcDst, and the retrieved property value to register
1495 propDst. If the property is not found, raises an exception.
1497 This is more efficient than doing resolve_base followed by
1498 resolve, or resolve_base followed by get_by_id, as it
1499 avoids duplicate hash lookups.
1501 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1507 BEGIN_OPCODE(op_resolve_func) {
1508 /* resolve_func baseDst(r) funcDst(r) property(id)
1510 Searches the scope chain for an object containing
1511 identifier property, and if one is found, writes the
1512 appropriate object to use as "this" when calling its
1513 properties to register baseDst; and the retrieved property
1514 value to register propDst. If the property is not found,
1515 raises an exception.
1517 This differs from resolve_with_base, because the
1518 global this value will be substituted for activations or
1519 the global object, which is the right behavior for function
1520 calls but not for other property lookup.
1522 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1528 BEGIN_OPCODE(op_get_by_id) {
1529 /* get_by_id dst(r) base(r) property(id)
1531 Converts register base to Object, gets the property
1532 named by identifier property from the object, and puts the
1533 result in register dst.
1535 int dst = (++vPC)->u.operand;
1536 int base = (++vPC)->u.operand;
1537 int property = (++vPC)->u.operand;
1539 int registerOffset = r - (*registerBase);
1541 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1543 Identifier& ident = codeBlock->identifiers[property];
1544 JSValue *result = baseObj->get(exec, ident);
1545 ASSERT(registerOffset == (r - (*registerBase)));
1546 VM_CHECK_EXCEPTION();
1547 r[dst].u.jsValue = result;
1551 BEGIN_OPCODE(op_put_by_id) {
1552 /* put_by_id base(r) property(id) value(r)
1554 Sets register value on register base as the property named
1555 by identifier property. Base is converted to object first.
1557 Unlike many opcodes, this one does not write any output to
1560 int base = (++vPC)->u.operand;
1561 int property = (++vPC)->u.operand;
1562 int value = (++vPC)->u.operand;
1564 int registerOffset = r - (*registerBase);
1567 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1569 Identifier& ident = codeBlock->identifiers[property];
1570 baseObj->put(exec, ident, r[value].u.jsValue);
1571 ASSERT(registerOffset == (r - (*registerBase)));
1573 VM_CHECK_EXCEPTION();
1577 BEGIN_OPCODE(op_del_by_id) {
1578 /* del_by_id dst(r) base(r) property(id)
1580 Converts register base to Object, deletes the property
1581 named by identifier property from the object, and writes a
1582 boolean indicating success (if true) or failure (if false)
1585 int dst = (++vPC)->u.operand;
1586 int base = (++vPC)->u.operand;
1587 int property = (++vPC)->u.operand;
1589 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1591 Identifier& ident = codeBlock->identifiers[property];
1592 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1593 VM_CHECK_EXCEPTION();
1594 r[dst].u.jsValue = result;
1598 BEGIN_OPCODE(op_get_by_val) {
1599 /* get_by_val dst(r) base(r) property(r)
1601 Converts register base to Object, gets the property named
1602 by register property from the object, and puts the result
1603 in register dst. property is nominally converted to string
1604 but numbers are treated more efficiently.
1606 int dst = (++vPC)->u.operand;
1607 int base = (++vPC)->u.operand;
1608 int property = (++vPC)->u.operand;
1610 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1612 JSValue* subscript = r[property].u.jsValue;
1615 if (subscript->getUInt32(i))
1616 result = baseObj->get(exec, i);
1618 Identifier property;
1619 if (subscript->isObject()) {
1620 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1621 property = Identifier(subscript->toString(exec));
1623 property = Identifier(subscript->toString(exec));
1625 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a getter after an exception is thrown
1626 result = baseObj->get(exec, property);
1629 VM_CHECK_EXCEPTION();
1630 r[dst].u.jsValue = result;
1634 BEGIN_OPCODE(op_put_by_val) {
1635 /* put_by_val base(r) property(r) value(r)
1637 Sets register value on register base as the property named
1638 by register property. Base is converted to object
1639 first. register property is nominally converted to string
1640 but numbers are treated more efficiently.
1642 Unlike many opcodes, this one does not write any output to
1645 int base = (++vPC)->u.operand;
1646 int property = (++vPC)->u.operand;
1647 int value = (++vPC)->u.operand;
1649 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1651 JSValue* subscript = r[property].u.jsValue;
1654 if (subscript->getUInt32(i))
1655 baseObj->put(exec, i, r[value].u.jsValue);
1657 Identifier property;
1658 if (subscript->isObject()) {
1659 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1660 property = Identifier(subscript->toString(exec));
1662 property = Identifier(subscript->toString(exec));
1664 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a setter after an exception is thrown
1665 baseObj->put(exec, property, r[value].u.jsValue);
1668 VM_CHECK_EXCEPTION();
1672 BEGIN_OPCODE(op_del_by_val) {
1673 /* del_by_val dst(r) base(r) property(r)
1675 Converts register base to Object, deletes the property
1676 named by register property from the object, and writes a
1677 boolean indicating success (if true) or failure (if false)
1680 int dst = (++vPC)->u.operand;
1681 int base = (++vPC)->u.operand;
1682 int property = (++vPC)->u.operand;
1684 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1686 JSValue* subscript = r[property].u.jsValue;
1689 if (subscript->getUInt32(i))
1690 result = jsBoolean(baseObj->deleteProperty(exec, i));
1692 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1693 Identifier property(subscript->toString(exec));
1694 VM_CHECK_EXCEPTION();
1695 result = jsBoolean(baseObj->deleteProperty(exec, property));
1698 VM_CHECK_EXCEPTION();
1699 r[dst].u.jsValue = result;
1703 BEGIN_OPCODE(op_put_by_index) {
1704 /* put_by_index base(r) property(n) value(r)
1706 Sets register value on register base as the property named
1707 by the immediate number property. Base is converted to
1708 object first. register property is nominally converted to
1709 string but numbers are treated more efficiently.
1711 Unlike many opcodes, this one does not write any output to
1714 This opcode is mainly used to initialize array literals.
1716 int base = (++vPC)->u.operand;
1717 unsigned property = (++vPC)->u.operand;
1718 int value = (++vPC)->u.operand;
1720 r[base].u.jsObject->put(exec, property, r[value].u.jsValue);
1725 BEGIN_OPCODE(op_jmp) {
1726 /* jmp target(offset)
1728 Jumps unconditionally to offset target from the current
1731 int target = (++vPC)->u.operand;
1736 BEGIN_OPCODE(op_jtrue) {
1737 /* jtrue cond(r) target(offset)
1739 Jumps to offset target from the current instruction, if and
1740 only if register cond converts to boolean as true.
1742 int cond = (++vPC)->u.operand;
1743 int target = (++vPC)->u.operand;
1744 if (r[cond].u.jsValue->toBoolean(exec)) {
1752 BEGIN_OPCODE(op_jfalse) {
1753 /* jfalse cond(r) target(offset)
1755 Jumps to offset target from the current instruction, if and
1756 only if register cond converts to boolean as false.
1758 int cond = (++vPC)->u.operand;
1759 int target = (++vPC)->u.operand;
1760 if (!r[cond].u.jsValue->toBoolean(exec)) {
1768 BEGIN_OPCODE(op_new_func) {
1769 /* new_func dst(r) func(f)
1771 Constructs a new Function instance from function func and
1772 the current scope chain using the original Function
1773 constructor, using the rules for function declarations, and
1774 puts the result in register dst.
1776 int dst = (++vPC)->u.operand;
1777 int func = (++vPC)->u.operand;
1779 r[dst].u.jsValue = codeBlock->functions[func]->makeFunction(exec, scopeChain);
1784 BEGIN_OPCODE(op_new_func_exp) {
1785 /* new_func_exp dst(r) func(f)
1787 Constructs a new Function instance from function func and
1788 the current scope chain using the original Function
1789 constructor, using the rules for function expressions, and
1790 puts the result in register dst.
1792 int dst = (++vPC)->u.operand;
1793 int func = (++vPC)->u.operand;
1795 r[dst].u.jsValue = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
1800 BEGIN_OPCODE(op_call_eval) {
1801 int r0 = (++vPC)->u.operand;
1802 int r1 = (++vPC)->u.operand;
1803 int r2 = (++vPC)->u.operand;
1804 int argv = (++vPC)->u.operand;
1805 int argc = (++vPC)->u.operand;
1807 JSValue* v = r[r1].u.jsValue;
1808 JSValue* base = r[r2].u.jsValue;
1810 if (base == scopeChain->globalObject() && v == scopeChain->globalObject()->evalFunction()) {
1811 int registerOffset = r - (*registerBase);
1813 JSObject* thisObject = r[codeBlock->thisRegister].u.jsObject;
1815 registerFile->setSafeForReentry(true);
1816 JSValue* result = eval(exec, thisObject, scopeChain, registerFile, r, argv, argc, exceptionValue);
1817 registerFile->setSafeForReentry(false);
1818 r = (*registerBase) + registerOffset;
1823 r[r0].u.jsValue = result;
1829 // We didn't find the blessed version of eval, so reset vPC and process
1830 // this instruction as a normal function call, supplying the proper 'this'
1833 r[r2].u.jsValue = base->toObject(exec)->toThisObject(exec);
1835 #if HAVE(COMPUTED_GOTO)
1836 // Hack around gcc performance quirk by performing an indirect goto
1837 // in order to set the vPC -- attempting to do so directly results in a
1838 // significant regression.
1839 goto *op_call_indirect; // indirect goto -> op_call
1841 // fall through to op_call
1843 BEGIN_OPCODE(op_call) {
1844 int r0 = (++vPC)->u.operand;
1845 int r1 = (++vPC)->u.operand;
1846 int r2 = (++vPC)->u.operand;
1847 int argv = (++vPC)->u.operand;
1848 int argc = (++vPC)->u.operand;
1850 JSValue* v = r[r1].u.jsValue;
1853 CallType callType = v->getCallData(callData);
1855 if (callType == CallTypeJS) {
1856 int registerOffset = r - (*registerBase);
1857 Register* callFrame = r + argv - CallFrameHeaderSize;
1858 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
1860 r[argv].u.jsValue = r2 == missingThisObjectMarker() ? exec->globalThisValue() : r[r2].u.jsValue; // "this" value
1861 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, r0, argv, argc, 0, v);
1863 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
1864 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
1866 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
1867 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
1868 if (UNLIKELY(exceptionValue != 0))
1871 codeBlock = newCodeBlock;
1872 exec->m_callFrameOffset = callFrameOffset;
1873 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
1874 k = codeBlock->jsValues.data();
1875 vPC = codeBlock->instructions.begin();
1880 if (callType == CallTypeNative) {
1881 int registerOffset = r - (*registerBase);
1883 r[argv].u.jsValue = r2 == missingThisObjectMarker() ? exec->globalThisValue() : (r[r2].u.jsValue)->toObject(exec); // "this" value
1884 JSObject* thisObj = static_cast<JSObject*>(r[argv].u.jsValue);
1886 List args(&r[argv + 1].u.jsValue, argc - 1);
1888 registerFile->setSafeForReentry(true);
1889 JSValue* returnValue = static_cast<JSObject*>(v)->callAsFunction(exec, thisObj, args);
1890 registerFile->setSafeForReentry(false);
1892 r = (*registerBase) + registerOffset;
1893 r[r0].u.jsValue = returnValue;
1895 VM_CHECK_EXCEPTION();
1901 ASSERT(callType == CallTypeNone);
1903 exceptionValue = createNotAFunctionError(exec, v, 0);
1906 BEGIN_OPCODE(op_ret) {
1907 int r1 = (++vPC)->u.operand;
1909 CodeBlock* oldCodeBlock = codeBlock;
1911 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
1912 JSValue* returnValue = r[r1].u.jsValue;
1914 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
1915 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
1916 ASSERT(activation->isActivationObject());
1917 activation->copyRegisters();
1920 if (codeBlock->needsFullScopeChain)
1921 scopeChain->deref();
1923 if (callFrame[CalledAsConstructor].u.i && !returnValue->isObject()) {
1924 JSValue* thisObject = callFrame[CallFrameHeaderSize].u.jsValue;
1925 returnValue = thisObject;
1928 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
1932 k = codeBlock->jsValues.data();
1933 vPC = callFrame[ReturnVPC].u.vPC;
1934 setScopeChain(exec, scopeChain, callFrame[CallerScopeChain].u.scopeChain);
1935 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
1936 r = (*registerBase) + callerRegisterOffset;
1937 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
1938 int r0 = callFrame[ReturnValueRegister].u.i;
1939 r[r0].u.jsValue = returnValue;
1943 BEGIN_OPCODE(op_construct) {
1944 int r0 = (++vPC)->u.operand;
1945 int r1 = (++vPC)->u.operand;
1946 int argv = (++vPC)->u.operand;
1947 int argc = (++vPC)->u.operand;
1949 JSValue* v = r[r1].u.jsValue;
1951 ConstructData constructData;
1952 ConstructType constructType = v->getConstructData(constructData);
1954 // Removing this line of code causes a measurable regression on squirrelfish.
1955 JSObject* constructor = static_cast<JSObject*>(v);
1957 if (constructType == ConstructTypeJS) {
1958 int registerOffset = r - (*registerBase);
1959 Register* callFrame = r + argv - CallFrameHeaderSize;
1960 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
1962 JSObject* prototype;
1963 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
1965 prototype = static_cast<JSObject*>(p);
1967 prototype = scopeChain->globalObject()->objectPrototype();
1968 JSObject* newObject = new JSObject(prototype);
1969 r[argv].u.jsValue = newObject; // "this" value
1971 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, r0, argv, argc, 1, constructor);
1973 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
1974 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
1976 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
1977 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
1981 codeBlock = newCodeBlock;
1982 exec->m_callFrameOffset = callFrameOffset;
1983 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
1984 k = codeBlock->jsValues.data();
1985 vPC = codeBlock->instructions.begin();
1990 if (constructType == ConstructTypeNative) {
1991 int registerOffset = r - (*registerBase);
1993 List args(&r[argv + 1].u.jsValue, argc - 1);
1994 registerFile->setSafeForReentry(true);
1995 JSValue* returnValue = constructor->construct(exec, args);
1996 registerFile->setSafeForReentry(false);
1998 r = (*registerBase) + registerOffset;
1999 VM_CHECK_EXCEPTION();
2000 r[r0].u.jsValue = returnValue;
2006 ASSERT(constructType == ConstructTypeNone);
2008 exceptionValue = createNotAConstructorError(exec, v, 0);
2011 BEGIN_OPCODE(op_push_scope) {
2012 /* push_scope scope(r)
2014 Converts register scope to object, and pushes it onto the top
2015 of the current scope chain.
2017 int scope = (++vPC)->u.operand;
2018 JSValue* v = r[scope].u.jsValue;
2019 JSObject* o = v->toObject(exec);
2020 VM_CHECK_EXCEPTION();
2022 setScopeChain(exec, scopeChain, scopeChain->push(o));
2027 BEGIN_OPCODE(op_pop_scope) {
2030 Removes the top item from the current scope chain.
2032 setScopeChain(exec, scopeChain, scopeChain->pop());
2037 BEGIN_OPCODE(op_get_pnames) {
2038 /* get_pnames dst(r) base(r)
2040 Creates a property name list for register base and puts it
2041 in register dst. This is not a true JavaScript value, just
2042 a synthetic value used to keep the iteration state in a
2045 int dst = (++vPC)->u.operand;
2046 int base = (++vPC)->u.operand;
2048 r[dst].u.jsPropertyNameIterator = JSPropertyNameIterator::create(exec, r[base].u.jsValue);
2052 BEGIN_OPCODE(op_next_pname) {
2053 /* next_pname dst(r) iter(r) target(offset)
2055 Tries to copies the next name from property name list in
2056 register iter. If there are names left, then copies one to
2057 register dst, and jumps to offset target. If there are none
2058 left, invalidates the iterator and continues to the next
2061 int dst = (++vPC)->u.operand;
2062 int iter = (++vPC)->u.operand;
2063 int target = (++vPC)->u.operand;
2065 JSPropertyNameIterator* it = r[iter].u.jsPropertyNameIterator;
2066 if (JSValue* temp = it->next(exec)) {
2067 r[dst].u.jsValue = temp;
2076 BEGIN_OPCODE(op_jmp_scopes) {
2077 /* jmp_scopes count(n) target(offset)
2079 Removes the a number of items from the current scope chain
2080 specified by immediate number count, then jumps to offset
2083 int count = (++vPC)->u.operand;
2084 int target = (++vPC)->u.operand;
2086 ScopeChainNode* tmp = scopeChain;
2089 setScopeChain(exec, scopeChain, tmp);
2094 BEGIN_OPCODE(op_catch) {
2095 ASSERT(exceptionValue);
2096 ASSERT(!exec->hadException());
2097 int r0 = (++vPC)->u.operand;
2098 r[r0].u.jsValue = exceptionValue;
2103 BEGIN_OPCODE(op_throw) {
2104 int e = (++vPC)->u.operand;
2105 exceptionValue = r[e].u.jsValue;
2106 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2108 *exception = exceptionValue;
2112 #if HAVE(COMPUTED_GOTO)
2113 // Hack around gcc performance quirk by performing an indirect goto
2114 // in order to set the vPC -- attempting to do so directly results in a
2115 // significant regression.
2116 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2124 BEGIN_OPCODE(op_new_error) {
2125 /* new_error dst(r) type(n) message(k)
2127 Constructs a new Error instance using the original
2128 constructor, using immediate number n as the type and
2129 constant message as the message string. The result is
2130 written to register dst.
2132 int dst = (++vPC)->u.operand;
2133 int type = (++vPC)->u.operand;
2134 int message = (++vPC)->u.operand;
2136 r[dst].u.jsValue = Error::create(exec, (ErrorType)type, k[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2141 BEGIN_OPCODE(op_end) {
2142 if (codeBlock->needsFullScopeChain) {
2143 ASSERT(scopeChain->refCount > 1);
2144 scopeChain->deref();
2146 int r0 = (++vPC)->u.operand;
2147 return r[r0].u.jsValue;
2149 BEGIN_OPCODE(op_put_getter) {
2150 /* put_getter base(r) property(id) function(r)
2152 Sets register function on register base as the getter named
2153 by identifier property. Base and function are assumed to be
2154 objects as this op should only be used for getters defined
2155 in object literal form.
2157 Unlike many opcodes, this one does not write any output to
2160 int base = (++vPC)->u.operand;
2161 int property = (++vPC)->u.operand;
2162 int function = (++vPC)->u.operand;
2164 ASSERT(r[base].u.jsValue->isObject());
2165 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2166 Identifier& ident = codeBlock->identifiers[property];
2167 ASSERT(r[function].u.jsValue->isObject());
2168 baseObj->defineGetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2173 BEGIN_OPCODE(op_put_setter) {
2174 /* put_setter base(r) property(id) function(r)
2176 Sets register function on register base as the setter named
2177 by identifier property. Base and function are assumed to be
2178 objects as this op should only be used for setters defined
2179 in object literal form.
2181 Unlike many opcodes, this one does not write any output to
2184 int base = (++vPC)->u.operand;
2185 int property = (++vPC)->u.operand;
2186 int function = (++vPC)->u.operand;
2188 ASSERT(r[base].u.jsValue->isObject());
2189 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2190 Identifier& ident = codeBlock->identifiers[property];
2191 ASSERT(r[function].u.jsValue->isObject());
2192 baseObj->defineSetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2197 BEGIN_OPCODE(op_jsr) {
2198 /* jsr retAddrDst(r) target(offset)
2200 Places the address of the next instruction into the retAddrDst
2201 register and jumps to offset target from the current instruction.
2203 int retAddrDst = (++vPC)->u.operand;
2204 int target = (++vPC)->u.operand;
2205 r[retAddrDst].u.vPC = vPC + 1;
2210 BEGIN_OPCODE(op_sret) {
2211 /* sret retAddrSrc(r)
2213 Jumps to the address stored in the retAddrSrc register. This
2214 differs from op_jmp because the target address is stored in a
2215 register, not as an immediate.
2217 int retAddrSrc = (++vPC)->u.operand;
2218 vPC = r[retAddrSrc].u.vPC;
2221 BEGIN_OPCODE(op_debug) {
2222 /* debug debugHookID(n) firstLine(n) lastLine(n)
2224 Notifies the debugger of the current state of execution:
2225 didEnterCallFrame; willLeaveCallFrame; or willExecuteStatement.
2227 This opcode is only generated while the debugger is attached.
2230 int registerOffset = r - (*registerBase);
2231 registerFile->setSafeForReentry(true);
2232 debug(exec, vPC, codeBlock, scopeChain, registerBase, r);
2233 registerFile->setSafeForReentry(false);
2234 r = (*registerBase) + registerOffset;
2240 exec->clearException();
2241 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2243 *exception = exceptionValue;
2252 #undef VM_CHECK_EXCEPTION
2255 JSValue* Machine::retrieveArguments(ExecState* exec, FunctionImp* function) const
2257 Register** registerBase;
2258 int callFrameOffset;
2260 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2263 Register* callFrame = (*registerBase) + callFrameOffset;
2264 JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue);
2266 CodeBlock* codeBlock = &function->body->generatedCode();
2267 activation = new JSActivation(function->body, registerBase, callFrameOffset + CallFrameHeaderSize + codeBlock->numLocals);
2268 callFrame[OptionalCalleeActivation].u.jsValue = activation;
2271 return activation->get(exec, exec->propertyNames().arguments);
2274 JSValue* Machine::retrieveCaller(ExecState* exec, FunctionImp* function) const
2276 Register** registerBase;
2277 int callFrameOffset;
2279 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2282 int callerFrameOffset;
2283 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callerFrameOffset))
2286 Register* callerFrame = (*registerBase) + callerFrameOffset;
2287 ASSERT(callerFrame[Callee].u.jsValue);
2288 return callerFrame[Callee].u.jsValue;
2291 bool Machine::getCallFrame(ExecState* exec, FunctionImp* function, Register**& registerBase, int& callFrameOffset) const
2293 callFrameOffset = exec->m_callFrameOffset;
2296 while (callFrameOffset < 0) {
2297 exec = exec->m_prev;
2300 callFrameOffset = exec->m_callFrameOffset;
2303 registerBase = exec->m_registerFile->basePointer();
2304 Register* callFrame = (*registerBase) + callFrameOffset;
2305 if (callFrame[Callee].u.jsValue == function)
2308 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callFrameOffset))
2309 callFrameOffset = -1;
2313 void Machine::getFunctionAndArguments(Register** registerBase, Register* callFrame, FunctionImp*& function, Register*& argv, int& argc)
2315 function = static_cast<FunctionImp*>(callFrame[Callee].u.jsValue);
2316 ASSERT(function->inherits(&FunctionImp::info));
2318 argv = (*registerBase) + callFrame[CallerRegisterOffset].u.i + callFrame[ArgumentStartRegister].u.i + 1; // skip "this"
2319 argc = callFrame[ArgumentCount].u.i - 1; // skip "this"