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"
43 #include "array_object.h"
47 #include "object_object.h"
48 #include "operations.h"
49 #include "operations.h"
50 #include "regexp_object.h"
54 __builtin_expect ((x), 0)
61 #if HAVE(COMPUTED_GOTO)
62 static void* op_throw_end_indirect;
63 static void* op_call_indirect;
66 // Retrieves the offset of a calling function within the current register file.
67 bool getCallerFunctionOffset(Register** registerBase, int callOffset, int& callerOffset)
69 Register* callFrame = (*registerBase) + callOffset;
71 CodeBlock* callerCodeBlock = callFrame[Machine::CallerCodeBlock].u.codeBlock;
72 if (!callerCodeBlock) // test for top frame of re-entrant function call
75 callerOffset = callFrame[Machine::CallerRegisterOffset].u.i - callerCodeBlock->numLocals - Machine::CallFrameHeaderSize;
76 if (callerOffset < 0) // test for global frame
79 Register* callerCallFrame = (*registerBase) + callerOffset;
80 if (!callerCallFrame[Machine::CallerCodeBlock].u.codeBlock) // test for eval frame
86 // Returns the depth of the scope chain within a given call frame.
87 static int depth(ScopeChain& sc)
90 ScopeChainIterator iter = sc.begin();
91 ScopeChainIterator end = sc.end();
92 while (!(*iter)->isVariableObject()) {
99 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
101 if (JSImmediate::areBothImmediateNumbers(v1, v2))
102 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
108 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
109 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
111 if (wasNotString1 | wasNotString2)
114 return static_cast<const StringImp*>(p1)->value() < static_cast<const StringImp*>(p2)->value();
117 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
123 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
124 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
126 if (wasNotString1 | wasNotString2)
129 return !(static_cast<const StringImp*>(p2)->value() < static_cast<const StringImp*>(p1)->value());
132 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
134 // exception for the Date exception in defaultValue()
135 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
136 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
138 if (p1->isString() || p2->isString()) {
139 UString value = p1->toString(exec) + p2->toString(exec);
141 return throwOutOfMemoryError(exec);
142 return jsString(value);
145 return jsNumber(p1->toNumber(exec) + p2->toNumber(exec));
148 // Fast-path choices here are based on frequency data from SunSpider:
149 // <times> Add case: <t1> <t2>
150 // ---------------------------
151 // 5627160 Add case: 1 1
152 // 247427 Add case: 5 5
153 // 20901 Add case: 5 6
154 // 13978 Add case: 5 1
155 // 4000 Add case: 1 5
158 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
160 JSType t1 = v1->type();
161 JSType t2 = v2->type();
162 const unsigned bothTypes = (t1 << 3) | t2;
164 if (bothTypes == ((NumberType << 3) | NumberType))
165 return jsNumber(v1->uncheckedGetNumber() + v2->uncheckedGetNumber());
166 if (bothTypes == ((StringType << 3) | StringType)) {
167 UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
169 return throwOutOfMemoryError(exec);
170 return jsString(value);
173 // All other cases are pretty uncommon
174 return jsAddSlowCase(exec, v1, v2);
177 static JSValue* jsTypeStringForValue(JSValue* v)
181 return jsString("undefined");
183 return jsString("object");
185 return jsString("boolean");
187 return jsString("number");
189 return jsString("string");
192 // Return "undefined" for objects that should be treated
193 // as null when doing comparisons.
194 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
195 return jsString("undefined");
196 else if (static_cast<JSObject*>(v)->implementsCall())
197 return jsString("function");
200 return jsString("object");
204 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
206 int dst = (vPC + 1)->u.operand;
207 int property = (vPC + 2)->u.operand;
209 ScopeChainIterator iter = scopeChain->begin();
210 ScopeChainIterator end = scopeChain->end();
214 Identifier& ident = codeBlock->identifiers[property];
217 if (o->getPropertySlot(exec, ident, slot)) {
218 JSValue* result = slot.getValue(exec, o, ident);
219 exceptionValue = exec->exception();
222 r[dst].u.jsValue = result;
225 } while (++iter != end);
226 exceptionValue = createUndefinedVariableError(exec, ident);
230 static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
232 int dst = (vPC + 1)->u.operand;
233 int property = (vPC + 2)->u.operand;
234 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
236 ScopeChainIterator iter = scopeChain->begin();
237 ScopeChainIterator end = scopeChain->end();
244 Identifier& ident = codeBlock->identifiers[property];
247 if (o->getPropertySlot(exec, ident, slot)) {
248 JSValue* result = slot.getValue(exec, o, ident);
249 exceptionValue = exec->exception();
252 r[dst].u.jsValue = result;
255 } while (++iter != end);
256 exceptionValue = createUndefinedVariableError(exec, ident);
260 static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
262 int dst = (vPC + 1)->u.operand;
263 int property = (vPC + 2)->u.operand;
265 ScopeChainIterator iter = scopeChain->begin();
266 ScopeChainIterator next = iter;
268 ScopeChainIterator end = scopeChain->end();
272 Identifier& ident = codeBlock->identifiers[property];
276 if (next == end || base->getPropertySlot(exec, ident, slot)) {
277 r[dst].u.jsValue = base;
285 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
287 int baseDst = (vPC + 1)->u.operand;
288 int propDst = (vPC + 2)->u.operand;
289 int property = (vPC + 3)->u.operand;
291 ScopeChainIterator iter = scopeChain->begin();
292 ScopeChainIterator end = scopeChain->end();
294 // FIXME: add scopeDepthIsZero optimization
299 Identifier& ident = codeBlock->identifiers[property];
303 if (base->getPropertySlot(exec, ident, slot)) {
304 JSValue* result = slot.getValue(exec, base, ident);
305 exceptionValue = exec->exception();
308 r[propDst].u.jsValue = result;
309 r[baseDst].u.jsValue = base;
313 } while (iter != end);
315 exceptionValue = createUndefinedVariableError(exec, ident);
319 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
321 int baseDst = (vPC + 1)->u.operand;
322 int funcDst = (vPC + 2)->u.operand;
323 int property = (vPC + 3)->u.operand;
325 ScopeChainIterator iter = scopeChain->begin();
326 ScopeChainIterator end = scopeChain->end();
328 // FIXME: add scopeDepthIsZero optimization
333 Identifier& ident = codeBlock->identifiers[property];
337 if (base->getPropertySlot(exec, ident, slot)) {
338 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
339 // However, section 10.2.3 says that in the case where the value provided
340 // by the caller is null, the global object should be used. It also says
341 // that the section does not apply to internal functions, but for simplicity
342 // of implementation we use the global object anyway here. This guarantees
343 // that in host objects you always get a valid object for this.
344 // We also handle wrapper substitution for the global object at the same time.
345 JSObject* thisObj = base->toThisObject(exec);
346 JSValue* result = slot.getValue(exec, base, ident);
347 exceptionValue = exec->exception();
351 r[baseDst].u.jsValue = thisObj;
352 r[funcDst].u.jsValue = result;
356 } while (iter != end);
358 exceptionValue = createUndefinedVariableError(exec, ident);
362 ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, int registerOffset, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
364 callFrame[Machine::CallerCodeBlock].u.codeBlock = codeBlock;
365 callFrame[Machine::ReturnVPC].u.vPC = vPC + 1;
366 callFrame[Machine::CallerScopeChain].u.scopeChain = scopeChain;
367 callFrame[Machine::CallerRegisterOffset].u.i = registerOffset;
368 callFrame[Machine::ReturnValueRegister].u.i = returnValueRegister;
369 callFrame[Machine::ArgumentStartRegister].u.i = argv; // original argument vector (for the sake of the "arguments" object)
370 callFrame[Machine::ArgumentCount].u.i = argc; // original argument count (for the sake of the "arguments" object)
371 callFrame[Machine::CalledAsConstructor].u.i = calledAsConstructor;
372 callFrame[Machine::Callee].u.jsValue = function;
373 callFrame[Machine::OptionalCalleeActivation].u.jsValue = 0;
376 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register** registerBase, int registerOffset, int argv, int argc, JSValue*& exceptionValue)
379 int oldOffset = registerOffset;
380 registerOffset += argv + newCodeBlock->numLocals;
381 size_t size = registerOffset + newCodeBlock->numTemporaries;
383 if (argc == newCodeBlock->numParameters) { // correct number of arguments
384 if (!registerFile->grow(size)) {
385 exceptionValue = createStackOverflowError(exec);
386 return *registerBase + oldOffset;
388 r = (*registerBase) + registerOffset;
389 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
390 if (!registerFile->grow(size)) {
391 exceptionValue = createStackOverflowError(exec);
392 return *registerBase + oldOffset;
394 r = (*registerBase) + registerOffset;
396 int omittedArgCount = newCodeBlock->numParameters - argc;
397 Register* endOfParams = r - newCodeBlock->numVars;
398 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
399 (*it).u.jsValue = jsUndefined();
400 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
401 int shift = argc + Machine::CallFrameHeaderSize;
402 registerOffset += shift;
405 if (!registerFile->grow(size)) {
406 exceptionValue = createStackOverflowError(exec);
407 return *registerBase + oldOffset;
409 r = (*registerBase) + registerOffset;
411 Register* it = r - newCodeBlock->numLocals - Machine::CallFrameHeaderSize - shift;
412 Register* end = it + Machine::CallFrameHeaderSize + newCodeBlock->numParameters;
413 for ( ; it != end; ++it)
420 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register** registerBase, Register* r)
422 if (newCodeBlock->needsFullScopeChain) {
423 JSActivation* activation = new JSActivation(functionBodyNode, registerBase, r - (*registerBase));
424 r[Machine::OptionalCalleeActivation - Machine::CallFrameHeaderSize - newCodeBlock->numLocals].u.jsValue = activation;
426 return callDataScopeChain->copy()->push(activation);
429 return callDataScopeChain;
432 static NEVER_INLINE bool isNotObject(ExecState* exec, const Instruction*, CodeBlock*, JSValue* value, JSValue*& exceptionData)
434 if (value->isObject())
436 exceptionData = createNotAnObjectError(exec, value, 0);
440 #if JAVASCRIPT_PROFILING
441 static NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* evalFunction, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
443 Profiler::profiler()->willExecute(exec, evalFunction);
445 static NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
449 JSValue* x = argc >= 2 ? r[argv + 1].u.jsValue : jsUndefined();
454 UString s = x->toString(exec);
455 if (exec->hadException()) {
456 exceptionValue = exec->exception();
457 exec->clearException();
464 RefPtr<EvalNode> evalNode = parser().parse<EvalNode>(exec, UString(), 0, UStringSourceProvider::create(s), &sourceId, &errLine, &errMsg);
467 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
471 #if JAVASCRIPT_PROFILING
472 JSValue* result = machine().execute(evalNode.get(), exec, thisObj, registerFile, r - (*registerFile->basePointer()) + argv + argc, scopeChain, &exceptionValue);
474 Profiler::profiler()->didExecute(exec, evalFunction);
478 return machine().execute(evalNode.get(), exec, thisObj, registerFile, r - (*registerFile->basePointer()) + argv + argc, scopeChain, &exceptionValue);
484 ASSERT(JSLock::currentThreadIsHoldingLock());
485 static Machine machine;
492 privateExecute(InitializeAndReturn);
495 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
497 ScopeChain sc(scopeChain);
498 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(sc.bottom());
499 codeBlock->dump(globalObject->globalExec());
500 dumpRegisters(codeBlock, registerFile, r);
503 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
505 printf("Register frame: \n\n");
506 printf("----------------------------------------\n");
507 printf(" use | address | value \n");
508 printf("----------------------------------------\n");
513 if (isGlobalCallFrame(registerFile->basePointer(), r)) {
514 it = r - registerFile->numGlobalSlots();
518 printf("[global var] | %10p | %10p \n", it, (*it).u.jsValue);
521 printf("----------------------------------------\n");
524 it = r - codeBlock->numLocals - CallFrameHeaderSize;
525 end = it + CallFrameHeaderSize;
528 printf("[call frame] | %10p | %10p \n", it, (*it).u.jsValue);
531 printf("----------------------------------------\n");
534 end = it + codeBlock->numParameters;
537 printf("[param] | %10p | %10p \n", it, (*it).u.jsValue);
540 printf("----------------------------------------\n");
543 end = it + codeBlock->numVars;
546 printf("[var] | %10p | %10p \n", it, (*it).u.jsValue);
549 printf("----------------------------------------\n");
553 end = it + codeBlock->numTemporaries;
556 printf("[temp] | %10p | %10p \n", it, (*it).u.jsValue);
562 bool Machine::isOpcode(Opcode opcode)
564 #if HAVE(COMPUTED_GOTO)
565 return opcode != HashTraits<Opcode>::emptyValue()
566 && !HashTraits<Opcode>::isDeletedValue(opcode)
567 && m_opcodeIDTable.contains(opcode);
569 return opcode >= 0 && opcode <= op_end;
573 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction*& vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
575 CodeBlock* oldCodeBlock = codeBlock;
577 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
578 if (!isGlobalCallFrame(registerBase, r)) {
579 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
580 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
584 if (oldCodeBlock->needsFullScopeChain)
587 if (isGlobalCallFrame(registerBase, r))
590 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
592 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
596 // If this call frame created an activation, tear it off.
597 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
598 ASSERT(activation->isActivationObject());
599 activation->copyRegisters();
602 k = codeBlock->jsValues.data();
603 scopeChain = callFrame[CallerScopeChain].u.scopeChain;
604 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
605 r = (*registerBase) + callerRegisterOffset;
606 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
607 vPC = callFrame[ReturnVPC].u.vPC;
609 #if JAVASCRIPT_PROFILING
610 Profiler::profiler()->didExecute(exec, callFrame[Callee].u.jsObject);
615 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction* vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
617 // Set up the exception object
619 if (exceptionValue->isObject()) {
620 JSObject* exception = static_cast<JSObject*>(exceptionValue);
621 if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
622 exception->put(exec, "line", jsNumber(codeBlock->lineNumberForVPC(vPC)));
623 exception->put(exec, "sourceURL", jsOwnedString(codeBlock->ownerNode->sourceURL()));
627 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
628 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
629 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
632 // Calculate an exception handler vPC, unwinding call frames as necessary.
635 Instruction* handlerVPC;
637 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth))
638 if (!unwindCallFrame(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r))
641 // Now unwind the scope chain within the exception handler's call frame.
643 ScopeChain sc(scopeChain);
644 int scopeDelta = depth(sc) - scopeDepth;
645 ASSERT(scopeDelta >= 0);
648 setScopeChain(exec, scopeChain, sc.node());
653 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, RegisterFileStack* registerFileStack, JSValue** exception)
655 if (m_reentryDepth >= MaxReentryDepth) {
656 *exception = createStackOverflowError(exec);
660 #if JAVASCRIPT_PROFILING
661 Profiler::profiler()->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
664 RegisterFile* registerFile = registerFileStack->pushGlobalRegisterFile();
665 ASSERT(registerFile->numGlobalSlots());
666 CodeBlock* codeBlock = &programNode->code(scopeChain, !registerFileStack->inImplicitCall());
667 registerFile->addGlobalSlots(codeBlock->numVars);
669 registerFile->uncheckedGrow(codeBlock->numTemporaries);
670 Register* r = (*registerFile->basePointer());
672 r[ProgramCodeThisRegister].u.jsValue = thisObj;
674 if (codeBlock->needsFullScopeChain)
675 scopeChain = scopeChain->copy();
677 ExecState newExec(exec, this, registerFile, scopeChain, -1);
680 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
683 registerFileStack->popGlobalRegisterFile();
685 #if JAVASCRIPT_PROFILING
686 Profiler::profiler()->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
692 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, FunctionImp* function, JSObject* thisObj, const List& args, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
694 if (m_reentryDepth >= MaxReentryDepth) {
695 *exception = createStackOverflowError(exec);
699 #if JAVASCRIPT_PROFILING
700 Profiler::profiler()->willExecute(exec, function);
703 RegisterFile* registerFile = registerFileStack->current();
705 int argv = CallFrameHeaderSize;
706 int argc = args.size() + 1; // implicit "this" parameter
708 size_t oldSize = registerFile->size();
709 if (!registerFile->grow(oldSize + CallFrameHeaderSize + argc)) {
710 *exception = createStackOverflowError(exec);
714 Register** registerBase = registerFile->basePointer();
715 int registerOffset = oldSize;
716 int callFrameOffset = registerOffset;
717 Register* callFrame = (*registerBase) + callFrameOffset;
719 // put args in place, including "this"
720 Register* dst = callFrame + CallFrameHeaderSize;
721 (*dst).u.jsValue = thisObj;
723 List::const_iterator end = args.end();
724 for (List::const_iterator it = args.begin(); it != end; ++it)
725 (*++dst).u.jsValue = *it;
727 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
728 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, argv, argc, 0, function);
730 CodeBlock* newCodeBlock = &functionBodyNode->code(scopeChain);
731 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, *exception);
733 registerFile->shrink(oldSize);
737 scopeChain = scopeChainForCall(functionBodyNode, newCodeBlock, scopeChain, registerBase, r);
739 ExecState newExec(exec, this, registerFile, scopeChain, callFrameOffset);
742 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, newCodeBlock, exception);
745 registerFile->shrink(oldSize);
749 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFile* registerFile, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
751 if (m_reentryDepth >= MaxReentryDepth) {
752 *exception = createStackOverflowError(exec);
756 #if JAVASCRIPT_PROFILING
757 Profiler::profiler()->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
760 EvalCodeBlock* codeBlock = &evalNode->code(scopeChain);
762 JSVariableObject* variableObject;
763 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
765 if (node->object->isVariableObject()) {
766 variableObject = static_cast<JSVariableObject*>(node->object);
771 for (Vector<Identifier>::const_iterator iter = codeBlock->declaredVariableNames.begin(); iter != codeBlock->declaredVariableNames.end(); ++iter) {
772 Identifier ident = *iter;
774 if (!variableObject->hasProperty(exec, ident))
775 variableObject->put(exec, ident, jsUndefined());
778 ASSERT(codeBlock->functions.size() == codeBlock->declaredFunctionNames.size());
779 for (size_t i = 0; i < codeBlock->functions.size(); ++i)
780 variableObject->put(exec, codeBlock->declaredFunctionNames[i], codeBlock->functions[i]->makeFunction(exec, scopeChain));
782 size_t oldSize = registerFile->size();
783 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numTemporaries + CallFrameHeaderSize;
784 if (!registerFile->grow(newSize)) {
785 *exception = createStackOverflowError(exec);
789 Register* callFrame = *registerFile->basePointer() + registerOffset;
791 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
792 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, 0, 0, 0, 0);
794 Register* r = callFrame + CallFrameHeaderSize + codeBlock->numVars;
795 r[ProgramCodeThisRegister].u.jsValue = thisObj;
797 if (codeBlock->needsFullScopeChain)
798 scopeChain = scopeChain->copy();
800 ExecState newExec(exec, this, registerFile, scopeChain, -1);
803 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
806 registerFile->shrink(oldSize);
808 #if JAVASCRIPT_PROFILING
809 Profiler::profiler()->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
815 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
817 RegisterFile* registerFile = registerFileStack->current();
818 if (registerFile->safeForReentry())
819 return Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
820 registerFile = registerFileStack->pushFunctionRegisterFile();
821 JSValue* result = Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
822 registerFileStack->popFunctionRegisterFile();
826 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
828 scopeChain = newScopeChain;
829 exec->m_scopeChain = newScopeChain;
832 NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register** registerBase, Register* r)
834 int debugHookID = (++vPC)->u.operand;
835 int firstLine = (++vPC)->u.operand;
836 int lastLine = (++vPC)->u.operand;
838 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
842 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, 0, registerBase, r - *registerBase);
844 switch((DebugHookID)debugHookID) {
845 case DidEnterCallFrame: {
846 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
849 case WillLeaveCallFrame: {
850 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
853 case WillExecuteStatement: {
854 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
860 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
862 // One-time initialization of our address tables. We have to put this code
863 // here because our labels are only in scope inside this function.
864 if (flag == InitializeAndReturn) {
865 #if HAVE(COMPUTED_GOTO)
866 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
867 FOR_EACH_OPCODE_ID(ADD_OPCODE);
870 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
871 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
873 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
874 op_throw_end_indirect = &&op_throw_end;
875 op_call_indirect = &&op_call;
876 #endif // HAVE(COMPUTED_GOTO)
880 JSValue* exceptionValue = 0;
881 Instruction* handlerVPC = 0;
883 Register** registerBase = registerFile->basePointer();
884 Instruction* vPC = codeBlock->instructions.begin();
885 JSValue** k = codeBlock->jsValues.data();
887 registerFile->setSafeForReentry(false);
888 #define VM_CHECK_EXCEPTION() \
890 if (UNLIKELY(exec->hadException())) { \
891 exceptionValue = exec->exception(); \
896 #if HAVE(COMPUTED_GOTO)
897 #define NEXT_OPCODE goto *vPC->u.opcode
898 #define BEGIN_OPCODE(opcode) opcode:
901 #define NEXT_OPCODE continue
902 #define BEGIN_OPCODE(opcode) case opcode:
903 while(1) // iterator loop begins
904 switch (vPC->u.opcode)
907 BEGIN_OPCODE(op_load) {
908 /* load dst(r) src(k)
910 Copies constant src to register dst.
912 int dst = (++vPC)->u.operand;
913 int src = (++vPC)->u.operand;
914 r[dst].u.jsValue = k[src];
919 BEGIN_OPCODE(op_new_object) {
922 Constructs a new empty Object instance using the original
923 constructor, and puts the result in register dst.
925 int dst = (++vPC)->u.operand;
926 r[dst].u.jsValue = scopeChain->globalObject()->objectConstructor()->construct(exec, exec->emptyList());
931 BEGIN_OPCODE(op_new_array) {
934 Constructs a new empty Array instance using the original
935 constructor, and puts the result in register dst.
937 int dst = (++vPC)->u.operand;
938 r[dst].u.jsValue = scopeChain->globalObject()->arrayConstructor()->construct(exec, exec->emptyList());
943 BEGIN_OPCODE(op_new_regexp) {
944 /* new_regexp dst(r) regExp(re)
946 Constructs a new RegExp instance using the original
947 constructor from regexp regExp, and puts the result in
950 int dst = (++vPC)->u.operand;
951 int regExp = (++vPC)->u.operand;
952 r[dst].u.jsValue = new RegExpImp(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
957 BEGIN_OPCODE(op_mov) {
960 Copies register src to register dst.
962 int dst = (++vPC)->u.operand;
963 int src = (++vPC)->u.operand;
969 BEGIN_OPCODE(op_eq) {
970 /* eq dst(r) src1(r) src2(r)
972 Checks whether register src1 and register src2 are equal,
973 as with the ECMAScript '==' operator, and puts the result
974 as a boolean in register dst.
976 int dst = (++vPC)->u.operand;
977 int src1 = (++vPC)->u.operand;
978 int src2 = (++vPC)->u.operand;
979 JSValue* result = jsBoolean(equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
980 VM_CHECK_EXCEPTION();
981 r[dst].u.jsValue = result;
986 BEGIN_OPCODE(op_neq) {
987 /* neq dst(r) src1(r) src2(r)
989 Checks whether register src1 and register src2 are not
990 equal, as with the ECMAScript '!=' operator, and puts the
991 result as a boolean in register dst.
993 int dst = (++vPC)->u.operand;
994 int src1 = (++vPC)->u.operand;
995 int src2 = (++vPC)->u.operand;
996 JSValue* result = jsBoolean(!equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
997 VM_CHECK_EXCEPTION();
998 r[dst].u.jsValue = result;
1003 BEGIN_OPCODE(op_stricteq) {
1004 /* stricteq dst(r) src1(r) src2(r)
1006 Checks whether register src1 and register src2 are strictly
1007 equal, as with the ECMAScript '===' operator, and puts the
1008 result as a boolean in register dst.
1010 int dst = (++vPC)->u.operand;
1011 int src1 = (++vPC)->u.operand;
1012 int src2 = (++vPC)->u.operand;
1013 r[dst].u.jsValue = jsBoolean(strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
1018 BEGIN_OPCODE(op_nstricteq) {
1019 /* nstricteq dst(r) src1(r) src2(r)
1021 Checks whether register src1 and register src2 are not
1022 strictly equal, as with the ECMAScript '!==' operator, and
1023 puts the result as a boolean in register dst.
1025 int dst = (++vPC)->u.operand;
1026 int src1 = (++vPC)->u.operand;
1027 int src2 = (++vPC)->u.operand;
1028 r[dst].u.jsValue = jsBoolean(!strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
1033 BEGIN_OPCODE(op_less) {
1034 /* less dst(r) src1(r) src2(r)
1036 Checks whether register src1 is less than register src2, as
1037 with the ECMAScript '<' operator, and puts the result as
1038 a boolean in register dst.
1040 int dst = (++vPC)->u.operand;
1041 int src1 = (++vPC)->u.operand;
1042 int src2 = (++vPC)->u.operand;
1043 JSValue* result = jsBoolean(jsLess(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1044 VM_CHECK_EXCEPTION();
1045 r[dst].u.jsValue = result;
1050 BEGIN_OPCODE(op_lesseq) {
1051 /* lesseq dst(r) src1(r) src2(r)
1053 Checks whether register src1 is less than or equal to
1054 register src2, as with the ECMAScript '<=' operator, and
1055 puts the result as a boolean in register dst.
1057 int dst = (++vPC)->u.operand;
1058 int src1 = (++vPC)->u.operand;
1059 int src2 = (++vPC)->u.operand;
1060 JSValue* result = jsBoolean(jsLessEq(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1061 VM_CHECK_EXCEPTION();
1062 r[dst].u.jsValue = result;
1067 BEGIN_OPCODE(op_pre_inc) {
1068 /* pre_inc srcDst(r)
1070 Converts register srcDst to number, adds one, and puts the result
1071 back in register srcDst.
1073 int srcDst = (++vPC)->u.operand;
1074 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) + 1);
1075 VM_CHECK_EXCEPTION();
1076 r[srcDst].u.jsValue = result;
1081 BEGIN_OPCODE(op_pre_dec) {
1082 /* pre_dec srcDst(r)
1084 Converts register srcDst to number, subtracts one, and puts the result
1085 back in register srcDst.
1087 int srcDst = (++vPC)->u.operand;
1088 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) - 1);
1089 VM_CHECK_EXCEPTION();
1090 r[srcDst].u.jsValue = result;
1095 BEGIN_OPCODE(op_post_inc) {
1096 /* post_inc dst(r) srcDst(r)
1098 Converts register srcDst to number. The number itself is
1099 written to register dst, and the number plus one is written
1100 back to register srcDst.
1102 int dst = (++vPC)->u.operand;
1103 int srcDst = (++vPC)->u.operand;
1104 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1105 VM_CHECK_EXCEPTION();
1107 r[dst].u.jsValue = number;
1108 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() + 1);
1113 BEGIN_OPCODE(op_post_dec) {
1114 /* post_dec dst(r) srcDst(r)
1116 Converts register srcDst to number. The number itself is
1117 written to register dst, and the number minus one is written
1118 back to register srcDst.
1120 int dst = (++vPC)->u.operand;
1121 int srcDst = (++vPC)->u.operand;
1122 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1123 VM_CHECK_EXCEPTION();
1125 r[dst].u.jsValue = number;
1126 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() - 1);
1131 BEGIN_OPCODE(op_to_jsnumber) {
1132 /* to_jsnumber dst(r) src(r)
1134 Converts register src to number, and puts the result
1137 int dst = (++vPC)->u.operand;
1138 int src = (++vPC)->u.operand;
1139 JSValue* result = r[src].u.jsValue->toJSNumber(exec);
1140 VM_CHECK_EXCEPTION();
1142 r[dst].u.jsValue = result;
1147 BEGIN_OPCODE(op_negate) {
1148 /* negate dst(r) src(r)
1150 Converts register src to number, negates it, and puts the
1151 result in register dst.
1153 int dst = (++vPC)->u.operand;
1154 int src = (++vPC)->u.operand;
1155 JSValue* result = jsNumber(-r[src].u.jsValue->toNumber(exec));
1156 VM_CHECK_EXCEPTION();
1157 r[dst].u.jsValue = result;
1162 BEGIN_OPCODE(op_add) {
1163 /* add dst(r) src1(r) src2(r)
1165 Adds register src1 and register src2, and puts the result
1166 in register dst. (JS add may be string concatenation or
1167 numeric add, depending on the types of the operands.)
1169 int dst = (++vPC)->u.operand;
1170 int src1 = (++vPC)->u.operand;
1171 int src2 = (++vPC)->u.operand;
1172 JSValue* result = jsAdd(exec, r[src1].u.jsValue, r[src2].u.jsValue);
1173 VM_CHECK_EXCEPTION();
1174 r[dst].u.jsValue = result;
1178 BEGIN_OPCODE(op_mul) {
1179 /* mul dst(r) src1(r) src2(r)
1181 Multiplies register src1 and register src2 (converted to
1182 numbers), and puts the product in register dst.
1184 int dst = (++vPC)->u.operand;
1185 int src1 = (++vPC)->u.operand;
1186 int src2 = (++vPC)->u.operand;
1187 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) * r[src2].u.jsValue->toNumber(exec));
1188 VM_CHECK_EXCEPTION();
1189 r[dst].u.jsValue = result;
1194 BEGIN_OPCODE(op_div) {
1195 /* div dst(r) dividend(r) divisor(r)
1197 Divides register dividend (converted to number) by the
1198 register divisor (converted to number), and puts the
1199 quotient in register dst.
1201 int dst = (++vPC)->u.operand;
1202 int dividend = (++vPC)->u.operand;
1203 int divisor = (++vPC)->u.operand;
1204 JSValue* result = jsNumber(r[dividend].u.jsValue->toNumber(exec) / r[divisor].u.jsValue->toNumber(exec));
1205 VM_CHECK_EXCEPTION();
1206 r[dst].u.jsValue = result;
1210 BEGIN_OPCODE(op_mod) {
1211 /* mod dst(r) dividend(r) divisor(r)
1213 Divides register dividend (converted to number) by
1214 register divisor (converted to number), and puts the
1215 remainder in register dst.
1217 int dst = (++vPC)->u.operand;
1218 int dividend = (++vPC)->u.operand;
1219 int divisor = (++vPC)->u.operand;
1220 double d = r[dividend].u.jsValue->toNumber(exec);
1221 JSValue* result = jsNumber(fmod(d, r[divisor].u.jsValue->toNumber(exec)));
1222 VM_CHECK_EXCEPTION();
1223 r[dst].u.jsValue = result;
1227 BEGIN_OPCODE(op_sub) {
1228 /* sub dst(r) src1(r) src2(r)
1230 Subtracts register src2 (converted to number) from register
1231 src1 (converted to number), and puts the difference in
1234 int dst = (++vPC)->u.operand;
1235 int src1 = (++vPC)->u.operand;
1236 int src2 = (++vPC)->u.operand;
1237 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) - r[src2].u.jsValue->toNumber(exec));
1238 VM_CHECK_EXCEPTION();
1239 r[dst].u.jsValue = result;
1243 BEGIN_OPCODE(op_lshift) {
1244 /* lshift dst(r) val(r) shift(r)
1246 Performs left shift of register val (converted to int32) by
1247 register shift (converted to uint32), and puts the result
1250 int dst = (++vPC)->u.operand;
1251 int val = (++vPC)->u.operand;
1252 int shift = (++vPC)->u.operand;
1253 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) << (r[shift].u.jsValue->toUInt32(exec)));
1254 VM_CHECK_EXCEPTION();
1255 r[dst].u.jsValue = result;
1260 BEGIN_OPCODE(op_rshift) {
1261 /* rshift dst(r) val(r) shift(r)
1263 Performs arithmetic right shift of register val (converted
1264 to int32) by register shift (converted to
1265 uint32), and puts the result in register dst.
1267 int dst = (++vPC)->u.operand;
1268 int val = (++vPC)->u.operand;
1269 int shift = (++vPC)->u.operand;
1270 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1271 VM_CHECK_EXCEPTION();
1272 r[dst].u.jsValue = result;
1277 BEGIN_OPCODE(op_urshift) {
1278 /* rshift dst(r) val(r) shift(r)
1280 Performs logical right shift of register val (converted
1281 to uint32) by register shift (converted to
1282 uint32), and puts the result in register dst.
1284 int dst = (++vPC)->u.operand;
1285 int val = (++vPC)->u.operand;
1286 int shift = (++vPC)->u.operand;
1287 JSValue* result = jsNumber((r[val].u.jsValue->toUInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1288 VM_CHECK_EXCEPTION();
1289 r[dst].u.jsValue = result;
1294 BEGIN_OPCODE(op_bitand) {
1295 /* bitand dst(r) src1(r) src2(r)
1297 Computes bitwise AND of register src1 (converted to int32)
1298 and register src2 (converted to int32), and puts the result
1301 int dst = (++vPC)->u.operand;
1302 int src1 = (++vPC)->u.operand;
1303 int src2 = (++vPC)->u.operand;
1304 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) & (r[src2].u.jsValue->toInt32(exec)));
1305 VM_CHECK_EXCEPTION();
1306 r[dst].u.jsValue = result;
1311 BEGIN_OPCODE(op_bitxor) {
1312 /* bitxor dst(r) src1(r) src2(r)
1314 Computes bitwise XOR of register src1 (converted to int32)
1315 and register src2 (converted to int32), and puts the result
1318 int dst = (++vPC)->u.operand;
1319 int src1 = (++vPC)->u.operand;
1320 int src2 = (++vPC)->u.operand;
1321 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) ^ (r[src2].u.jsValue->toInt32(exec)));
1322 VM_CHECK_EXCEPTION();
1323 r[dst].u.jsValue = result;
1328 BEGIN_OPCODE(op_bitor) {
1329 /* bitor dst(r) src1(r) src2(r)
1331 Computes bitwise OR of register src1 (converted to int32)
1332 and register src2 (converted to int32), and puts the
1333 result in register dst.
1335 int dst = (++vPC)->u.operand;
1336 int src1 = (++vPC)->u.operand;
1337 int src2 = (++vPC)->u.operand;
1338 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) | (r[src2].u.jsValue->toInt32(exec)));
1339 VM_CHECK_EXCEPTION();
1340 r[dst].u.jsValue = result;
1345 BEGIN_OPCODE(op_bitnot) {
1346 /* bitnot dst(r) src(r)
1348 Computes bitwise NOT of register src1 (converted to int32),
1349 and puts the result in register dst.
1351 int dst = (++vPC)->u.operand;
1352 int src = (++vPC)->u.operand;
1353 JSValue* result = jsNumber(~r[src].u.jsValue->toInt32(exec));
1354 VM_CHECK_EXCEPTION();
1355 r[dst].u.jsValue = result;
1360 BEGIN_OPCODE(op_not) {
1361 /* not dst(r) src1(r) src2(r)
1363 Computes logical NOT of register src1 (converted to
1364 boolean), and puts the result in register dst.
1366 int dst = (++vPC)->u.operand;
1367 int src = (++vPC)->u.operand;
1368 JSValue* result = jsBoolean(!r[src].u.jsValue->toBoolean(exec));
1369 VM_CHECK_EXCEPTION();
1370 r[dst].u.jsValue = result;
1375 BEGIN_OPCODE(op_instanceof) {
1376 /* instanceof dst(r) value(r) constructor(r)
1378 Tests whether register value is an instance of register
1379 constructor, and puts the boolean result in register dst.
1381 Raises an exception if register constructor is not an
1384 int dst = (++vPC)->u.operand;
1385 int value = (++vPC)->u.operand;
1386 int base = (++vPC)->u.operand;
1388 JSValue* baseVal = r[base].u.jsValue;
1390 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1393 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1394 r[dst].u.jsValue = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].u.jsValue) : false);
1399 BEGIN_OPCODE(op_typeof) {
1400 /* typeof dst(r) src(r)
1402 Determines the type string for src according to ECMAScript
1403 rules, and puts the result in register dst.
1405 int dst = (++vPC)->u.operand;
1406 int src = (++vPC)->u.operand;
1407 r[dst].u.jsValue = jsTypeStringForValue(r[src].u.jsValue);
1412 BEGIN_OPCODE(op_in) {
1413 /* in dst(r) property(r) base(r)
1415 Tests whether register base has a property named register
1416 property, and puts the boolean result in register dst.
1418 Raises an exception if register constructor is not an
1421 int dst = (++vPC)->u.operand;
1422 int property = (++vPC)->u.operand;
1423 int base = (++vPC)->u.operand;
1425 JSValue* baseVal = r[base].u.jsValue;
1426 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1429 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1431 JSValue* propName = r[property].u.jsValue;
1434 if (propName->getUInt32(i))
1435 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, i));
1437 Identifier property(propName->toString(exec));
1438 VM_CHECK_EXCEPTION();
1439 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, property));
1445 BEGIN_OPCODE(op_resolve) {
1446 /* resolve dst(r) property(id)
1448 Looks up the property named by identifier property in the
1449 scope chain, and writes the resulting value to register
1450 dst. If the property is not found, raises an exception.
1452 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1458 BEGIN_OPCODE(op_resolve_skip) {
1459 /* resolve_skip dst(r) property(id) skip(n)
1461 Looks up the property named by identifier property in the
1462 scope chain skipping the top 'skip' levels, and writes the resulting
1463 value to register dst. If the property is not found, raises an exception.
1465 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1472 BEGIN_OPCODE(op_get_scoped_var) {
1473 /* get_scoped_var dst(r) index(n) skip(n)
1475 Loads the contents of the index-th local from the scope skip nodes from
1476 the top of the scope chain, and places it in register dst
1478 int dst = (++vPC)->u.operand;
1479 int index = (++vPC)->u.operand;
1480 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1482 ScopeChainIterator iter = scopeChain->begin();
1483 ScopeChainIterator end = scopeChain->end();
1484 ASSERT(iter != end);
1487 ASSERT(iter != end);
1490 ASSERT((*iter)->isVariableObject());
1491 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1492 r[dst].u.jsValue = scope->valueAt(index);
1496 BEGIN_OPCODE(op_put_scoped_var) {
1497 /* put_scoped_var index(n) skip(n) value(r)
1500 int index = (++vPC)->u.operand;
1501 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1502 int value = (++vPC)->u.operand;
1504 ScopeChainIterator iter = scopeChain->begin();
1505 ScopeChainIterator end = scopeChain->end();
1506 ASSERT(iter != end);
1509 ASSERT(iter != end);
1512 ASSERT((*iter)->isVariableObject());
1513 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1514 scope->valueAt(index) = r[value].u.jsValue;
1518 BEGIN_OPCODE(op_resolve_base) {
1519 /* resolve_base dst(r) property(id)
1521 Searches the scope chain for an object containing
1522 identifier property, and if one is found, writes it to
1523 register dst. If none is found, the outermost scope (which
1524 will be the global object) is stored in register dst.
1526 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1531 BEGIN_OPCODE(op_resolve_with_base) {
1532 /* resolve_with_base baseDst(r) propDst(r) property(id)
1534 Searches the scope chain for an object containing
1535 identifier property, and if one is found, writes it to
1536 register srcDst, and the retrieved property value to register
1537 propDst. If the property is not found, raises an exception.
1539 This is more efficient than doing resolve_base followed by
1540 resolve, or resolve_base followed by get_by_id, as it
1541 avoids duplicate hash lookups.
1543 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1549 BEGIN_OPCODE(op_resolve_func) {
1550 /* resolve_func baseDst(r) funcDst(r) property(id)
1552 Searches the scope chain for an object containing
1553 identifier property, and if one is found, writes the
1554 appropriate object to use as "this" when calling its
1555 properties to register baseDst; and the retrieved property
1556 value to register propDst. If the property is not found,
1557 raises an exception.
1559 This differs from resolve_with_base, because the
1560 global this value will be substituted for activations or
1561 the global object, which is the right behavior for function
1562 calls but not for other property lookup.
1564 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1570 BEGIN_OPCODE(op_get_by_id) {
1571 /* get_by_id dst(r) base(r) property(id)
1573 Converts register base to Object, gets the property
1574 named by identifier property from the object, and puts the
1575 result in register dst.
1577 int dst = (++vPC)->u.operand;
1578 int base = (++vPC)->u.operand;
1579 int property = (++vPC)->u.operand;
1581 int registerOffset = r - (*registerBase);
1583 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1585 Identifier& ident = codeBlock->identifiers[property];
1586 JSValue *result = baseObj->get(exec, ident);
1587 ASSERT(registerOffset == (r - (*registerBase)));
1588 VM_CHECK_EXCEPTION();
1589 r[dst].u.jsValue = result;
1593 BEGIN_OPCODE(op_put_by_id) {
1594 /* put_by_id base(r) property(id) value(r)
1596 Sets register value on register base as the property named
1597 by identifier property. Base is converted to object first.
1599 Unlike many opcodes, this one does not write any output to
1602 int base = (++vPC)->u.operand;
1603 int property = (++vPC)->u.operand;
1604 int value = (++vPC)->u.operand;
1606 int registerOffset = r - (*registerBase);
1609 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1611 Identifier& ident = codeBlock->identifiers[property];
1612 baseObj->put(exec, ident, r[value].u.jsValue);
1613 ASSERT(registerOffset == (r - (*registerBase)));
1615 VM_CHECK_EXCEPTION();
1619 BEGIN_OPCODE(op_del_by_id) {
1620 /* del_by_id dst(r) base(r) property(id)
1622 Converts register base to Object, deletes the property
1623 named by identifier property from the object, and writes a
1624 boolean indicating success (if true) or failure (if false)
1627 int dst = (++vPC)->u.operand;
1628 int base = (++vPC)->u.operand;
1629 int property = (++vPC)->u.operand;
1631 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1633 Identifier& ident = codeBlock->identifiers[property];
1634 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1635 VM_CHECK_EXCEPTION();
1636 r[dst].u.jsValue = result;
1640 BEGIN_OPCODE(op_get_by_val) {
1641 /* get_by_val dst(r) base(r) property(r)
1643 Converts register base to Object, gets the property named
1644 by register property from the object, and puts the result
1645 in register dst. property is nominally converted to string
1646 but numbers are treated more efficiently.
1648 int dst = (++vPC)->u.operand;
1649 int base = (++vPC)->u.operand;
1650 int property = (++vPC)->u.operand;
1652 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1654 JSValue* subscript = r[property].u.jsValue;
1657 if (subscript->getUInt32(i))
1658 result = baseObj->get(exec, i);
1660 Identifier property;
1661 if (subscript->isObject()) {
1662 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1663 property = Identifier(subscript->toString(exec));
1665 property = Identifier(subscript->toString(exec));
1667 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a getter after an exception is thrown
1668 result = baseObj->get(exec, property);
1671 VM_CHECK_EXCEPTION();
1672 r[dst].u.jsValue = result;
1676 BEGIN_OPCODE(op_put_by_val) {
1677 /* put_by_val base(r) property(r) value(r)
1679 Sets register value on register base as the property named
1680 by register property. Base is converted to object
1681 first. register property is nominally converted to string
1682 but numbers are treated more efficiently.
1684 Unlike many opcodes, this one does not write any output to
1687 int base = (++vPC)->u.operand;
1688 int property = (++vPC)->u.operand;
1689 int value = (++vPC)->u.operand;
1691 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1693 JSValue* subscript = r[property].u.jsValue;
1696 if (subscript->getUInt32(i))
1697 baseObj->put(exec, i, r[value].u.jsValue);
1699 Identifier property;
1700 if (subscript->isObject()) {
1701 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1702 property = Identifier(subscript->toString(exec));
1704 property = Identifier(subscript->toString(exec));
1706 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a setter after an exception is thrown
1707 baseObj->put(exec, property, r[value].u.jsValue);
1710 VM_CHECK_EXCEPTION();
1714 BEGIN_OPCODE(op_del_by_val) {
1715 /* del_by_val dst(r) base(r) property(r)
1717 Converts register base to Object, deletes the property
1718 named by register property from the object, and writes a
1719 boolean indicating success (if true) or failure (if false)
1722 int dst = (++vPC)->u.operand;
1723 int base = (++vPC)->u.operand;
1724 int property = (++vPC)->u.operand;
1726 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1728 JSValue* subscript = r[property].u.jsValue;
1731 if (subscript->getUInt32(i))
1732 result = jsBoolean(baseObj->deleteProperty(exec, i));
1734 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1735 Identifier property(subscript->toString(exec));
1736 VM_CHECK_EXCEPTION();
1737 result = jsBoolean(baseObj->deleteProperty(exec, property));
1740 VM_CHECK_EXCEPTION();
1741 r[dst].u.jsValue = result;
1745 BEGIN_OPCODE(op_put_by_index) {
1746 /* put_by_index base(r) property(n) value(r)
1748 Sets register value on register base as the property named
1749 by the immediate number property. Base is converted to
1750 object first. register property is nominally converted to
1751 string but numbers are treated more efficiently.
1753 Unlike many opcodes, this one does not write any output to
1756 This opcode is mainly used to initialize array literals.
1758 int base = (++vPC)->u.operand;
1759 unsigned property = (++vPC)->u.operand;
1760 int value = (++vPC)->u.operand;
1762 r[base].u.jsObject->put(exec, property, r[value].u.jsValue);
1767 BEGIN_OPCODE(op_jmp) {
1768 /* jmp target(offset)
1770 Jumps unconditionally to offset target from the current
1773 int target = (++vPC)->u.operand;
1778 BEGIN_OPCODE(op_jtrue) {
1779 /* jtrue cond(r) target(offset)
1781 Jumps to offset target from the current instruction, if and
1782 only if register cond converts to boolean as true.
1784 int cond = (++vPC)->u.operand;
1785 int target = (++vPC)->u.operand;
1786 if (r[cond].u.jsValue->toBoolean(exec)) {
1794 BEGIN_OPCODE(op_jfalse) {
1795 /* jfalse cond(r) target(offset)
1797 Jumps to offset target from the current instruction, if and
1798 only if register cond converts to boolean as false.
1800 int cond = (++vPC)->u.operand;
1801 int target = (++vPC)->u.operand;
1802 if (!r[cond].u.jsValue->toBoolean(exec)) {
1810 BEGIN_OPCODE(op_new_func) {
1811 /* new_func dst(r) func(f)
1813 Constructs a new Function instance from function func and
1814 the current scope chain using the original Function
1815 constructor, using the rules for function declarations, and
1816 puts the result in register dst.
1818 int dst = (++vPC)->u.operand;
1819 int func = (++vPC)->u.operand;
1821 r[dst].u.jsValue = codeBlock->functions[func]->makeFunction(exec, scopeChain);
1826 BEGIN_OPCODE(op_new_func_exp) {
1827 /* new_func_exp dst(r) func(f)
1829 Constructs a new Function instance from function func and
1830 the current scope chain using the original Function
1831 constructor, using the rules for function expressions, and
1832 puts the result in register dst.
1834 int dst = (++vPC)->u.operand;
1835 int func = (++vPC)->u.operand;
1837 r[dst].u.jsValue = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
1842 BEGIN_OPCODE(op_call_eval) {
1843 int dst = (++vPC)->u.operand;
1844 int func = (++vPC)->u.operand;
1845 int base = (++vPC)->u.operand;
1846 int argv = (++vPC)->u.operand;
1847 int argc = (++vPC)->u.operand;
1849 JSValue* funcVal = r[func].u.jsValue;
1850 JSValue* baseVal = r[base].u.jsValue;
1852 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
1853 int registerOffset = r - (*registerBase);
1855 JSObject* thisObject = r[codeBlock->thisRegister].u.jsObject;
1857 registerFile->setSafeForReentry(true);
1858 #if JAVASCRIPT_PROFILING
1859 JSValue* result = callEval(exec, static_cast<JSObject*>(funcVal), thisObject, scopeChain, registerFile, r, argv, argc, exceptionValue);
1861 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, argv, argc, exceptionValue);
1863 registerFile->setSafeForReentry(false);
1864 r = (*registerBase) + registerOffset;
1869 r[dst].u.jsValue = result;
1875 // We didn't find the blessed version of eval, so reset vPC and process
1876 // this instruction as a normal function call, supplying the proper 'this'
1879 r[base].u.jsValue = baseVal->toObject(exec)->toThisObject(exec);
1881 #if HAVE(COMPUTED_GOTO)
1882 // Hack around gcc performance quirk by performing an indirect goto
1883 // in order to set the vPC -- attempting to do so directly results in a
1884 // significant regression.
1885 goto *op_call_indirect; // indirect goto -> op_call
1887 // fall through to op_call
1889 BEGIN_OPCODE(op_call) {
1890 int dst = (++vPC)->u.operand;
1891 int func = (++vPC)->u.operand;
1892 int base = (++vPC)->u.operand;
1893 int argv = (++vPC)->u.operand;
1894 int argc = (++vPC)->u.operand;
1896 JSValue* v = r[func].u.jsValue;
1899 CallType callType = v->getCallData(callData);
1901 if (callType == CallTypeJS) {
1902 #if JAVASCRIPT_PROFILING
1903 Profiler::profiler()->willExecute(exec, static_cast<JSObject*>(v));
1905 int registerOffset = r - (*registerBase);
1906 Register* callFrame = r + argv - CallFrameHeaderSize;
1907 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
1909 r[argv].u.jsValue = base == missingThisObjectMarker() ? exec->globalThisValue() : r[base].u.jsValue; // "this" value
1910 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, dst, argv, argc, 0, v);
1912 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
1913 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
1915 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
1916 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
1917 if (UNLIKELY(exceptionValue != 0))
1920 codeBlock = newCodeBlock;
1921 exec->m_callFrameOffset = callFrameOffset;
1922 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
1923 k = codeBlock->jsValues.data();
1924 vPC = codeBlock->instructions.begin();
1929 if (callType == CallTypeNative) {
1930 #if JAVASCRIPT_PROFILING
1931 Profiler::profiler()->willExecute(exec, static_cast<JSObject*>(v));
1933 int registerOffset = r - (*registerBase);
1935 r[argv].u.jsValue = base == missingThisObjectMarker() ? exec->globalThisValue() : (r[base].u.jsValue)->toObject(exec); // "this" value
1936 JSObject* thisObj = static_cast<JSObject*>(r[argv].u.jsValue);
1938 List args(&r[argv + 1].u.jsValue, argc - 1);
1940 registerFile->setSafeForReentry(true);
1941 JSValue* returnValue = static_cast<JSObject*>(v)->callAsFunction(exec, thisObj, args);
1942 registerFile->setSafeForReentry(false);
1944 r = (*registerBase) + registerOffset;
1945 r[dst].u.jsValue = returnValue;
1947 #if JAVASCRIPT_PROFILING
1948 Profiler::profiler()->didExecute(exec, static_cast<JSObject*>(v));
1950 VM_CHECK_EXCEPTION();
1956 ASSERT(callType == CallTypeNone);
1958 exceptionValue = createNotAFunctionError(exec, v, 0);
1961 BEGIN_OPCODE(op_ret) {
1962 int r1 = (++vPC)->u.operand;
1964 CodeBlock* oldCodeBlock = codeBlock;
1966 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
1967 JSValue* returnValue = r[r1].u.jsValue;
1969 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
1970 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
1971 ASSERT(activation->isActivationObject());
1972 activation->copyRegisters();
1975 if (codeBlock->needsFullScopeChain)
1976 scopeChain->deref();
1978 if (callFrame[CalledAsConstructor].u.i && !returnValue->isObject()) {
1979 JSValue* thisObject = callFrame[CallFrameHeaderSize].u.jsValue;
1980 returnValue = thisObject;
1983 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
1987 k = codeBlock->jsValues.data();
1988 vPC = callFrame[ReturnVPC].u.vPC;
1989 setScopeChain(exec, scopeChain, callFrame[CallerScopeChain].u.scopeChain);
1990 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
1991 r = (*registerBase) + callerRegisterOffset;
1992 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
1993 int r0 = callFrame[ReturnValueRegister].u.i;
1994 r[r0].u.jsValue = returnValue;
1996 #if JAVASCRIPT_PROFILING
1997 Profiler::profiler()->didExecute(exec, callFrame[Callee].u.jsObject);
2001 BEGIN_OPCODE(op_construct) {
2002 int dst = (++vPC)->u.operand;
2003 int func = (++vPC)->u.operand;
2004 int argv = (++vPC)->u.operand;
2005 int argc = (++vPC)->u.operand;
2007 JSValue* funcVal = r[func].u.jsValue;
2009 ConstructData constructData;
2010 ConstructType constructType = funcVal->getConstructData(constructData);
2012 // Removing this line of code causes a measurable regression on squirrelfish.
2013 JSObject* constructor = static_cast<JSObject*>(funcVal);
2015 if (constructType == ConstructTypeJS) {
2016 #if JAVASCRIPT_PROFILING
2017 Profiler::profiler()->willExecute(exec, constructor);
2019 int registerOffset = r - (*registerBase);
2020 Register* callFrame = r + argv - CallFrameHeaderSize;
2021 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
2023 JSObject* prototype;
2024 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
2026 prototype = static_cast<JSObject*>(p);
2028 prototype = scopeChain->globalObject()->objectPrototype();
2029 JSObject* newObject = new JSObject(prototype);
2030 r[argv].u.jsValue = newObject; // "this" value
2032 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, dst, argv, argc, 1, constructor);
2034 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
2035 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
2037 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
2038 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
2042 codeBlock = newCodeBlock;
2043 exec->m_callFrameOffset = callFrameOffset;
2044 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
2045 k = codeBlock->jsValues.data();
2046 vPC = codeBlock->instructions.begin();
2051 if (constructType == ConstructTypeNative) {
2052 #if JAVASCRIPT_PROFILING
2053 Profiler::profiler()->willExecute(exec, constructor);
2055 int registerOffset = r - (*registerBase);
2057 List args(&r[argv + 1].u.jsValue, argc - 1);
2058 registerFile->setSafeForReentry(true);
2059 JSValue* returnValue = constructor->construct(exec, args);
2060 registerFile->setSafeForReentry(false);
2062 r = (*registerBase) + registerOffset;
2063 VM_CHECK_EXCEPTION();
2064 r[dst].u.jsValue = returnValue;
2066 #if JAVASCRIPT_PROFILING
2067 Profiler::profiler()->didExecute(exec, constructor);
2073 ASSERT(constructType == ConstructTypeNone);
2075 exceptionValue = createNotAConstructorError(exec, funcVal, 0);
2078 BEGIN_OPCODE(op_push_scope) {
2079 /* push_scope scope(r)
2081 Converts register scope to object, and pushes it onto the top
2082 of the current scope chain.
2084 int scope = (++vPC)->u.operand;
2085 JSValue* v = r[scope].u.jsValue;
2086 JSObject* o = v->toObject(exec);
2087 VM_CHECK_EXCEPTION();
2089 setScopeChain(exec, scopeChain, scopeChain->push(o));
2094 BEGIN_OPCODE(op_pop_scope) {
2097 Removes the top item from the current scope chain.
2099 setScopeChain(exec, scopeChain, scopeChain->pop());
2104 BEGIN_OPCODE(op_get_pnames) {
2105 /* get_pnames dst(r) base(r)
2107 Creates a property name list for register base and puts it
2108 in register dst. This is not a true JavaScript value, just
2109 a synthetic value used to keep the iteration state in a
2112 int dst = (++vPC)->u.operand;
2113 int base = (++vPC)->u.operand;
2115 r[dst].u.jsPropertyNameIterator = JSPropertyNameIterator::create(exec, r[base].u.jsValue);
2119 BEGIN_OPCODE(op_next_pname) {
2120 /* next_pname dst(r) iter(r) target(offset)
2122 Tries to copies the next name from property name list in
2123 register iter. If there are names left, then copies one to
2124 register dst, and jumps to offset target. If there are none
2125 left, invalidates the iterator and continues to the next
2128 int dst = (++vPC)->u.operand;
2129 int iter = (++vPC)->u.operand;
2130 int target = (++vPC)->u.operand;
2132 JSPropertyNameIterator* it = r[iter].u.jsPropertyNameIterator;
2133 if (JSValue* temp = it->next(exec)) {
2134 r[dst].u.jsValue = temp;
2143 BEGIN_OPCODE(op_jmp_scopes) {
2144 /* jmp_scopes count(n) target(offset)
2146 Removes the a number of items from the current scope chain
2147 specified by immediate number count, then jumps to offset
2150 int count = (++vPC)->u.operand;
2151 int target = (++vPC)->u.operand;
2153 ScopeChainNode* tmp = scopeChain;
2156 setScopeChain(exec, scopeChain, tmp);
2161 BEGIN_OPCODE(op_catch) {
2162 ASSERT(exceptionValue);
2163 ASSERT(!exec->hadException());
2164 int r0 = (++vPC)->u.operand;
2165 r[r0].u.jsValue = exceptionValue;
2170 BEGIN_OPCODE(op_throw) {
2171 int e = (++vPC)->u.operand;
2172 exceptionValue = r[e].u.jsValue;
2173 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2175 *exception = exceptionValue;
2179 #if HAVE(COMPUTED_GOTO)
2180 // Hack around gcc performance quirk by performing an indirect goto
2181 // in order to set the vPC -- attempting to do so directly results in a
2182 // significant regression.
2183 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2191 BEGIN_OPCODE(op_new_error) {
2192 /* new_error dst(r) type(n) message(k)
2194 Constructs a new Error instance using the original
2195 constructor, using immediate number n as the type and
2196 constant message as the message string. The result is
2197 written to register dst.
2199 int dst = (++vPC)->u.operand;
2200 int type = (++vPC)->u.operand;
2201 int message = (++vPC)->u.operand;
2203 r[dst].u.jsValue = Error::create(exec, (ErrorType)type, k[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2208 BEGIN_OPCODE(op_end) {
2209 if (codeBlock->needsFullScopeChain) {
2210 ASSERT(scopeChain->refCount > 1);
2211 scopeChain->deref();
2213 int r0 = (++vPC)->u.operand;
2214 return r[r0].u.jsValue;
2216 BEGIN_OPCODE(op_put_getter) {
2217 /* put_getter base(r) property(id) function(r)
2219 Sets register function on register base as the getter named
2220 by identifier property. Base and function are assumed to be
2221 objects as this op should only be used for getters defined
2222 in object literal form.
2224 Unlike many opcodes, this one does not write any output to
2227 int base = (++vPC)->u.operand;
2228 int property = (++vPC)->u.operand;
2229 int function = (++vPC)->u.operand;
2231 ASSERT(r[base].u.jsValue->isObject());
2232 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2233 Identifier& ident = codeBlock->identifiers[property];
2234 ASSERT(r[function].u.jsValue->isObject());
2235 baseObj->defineGetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2240 BEGIN_OPCODE(op_put_setter) {
2241 /* put_setter base(r) property(id) function(r)
2243 Sets register function on register base as the setter named
2244 by identifier property. Base and function are assumed to be
2245 objects as this op should only be used for setters defined
2246 in object literal form.
2248 Unlike many opcodes, this one does not write any output to
2251 int base = (++vPC)->u.operand;
2252 int property = (++vPC)->u.operand;
2253 int function = (++vPC)->u.operand;
2255 ASSERT(r[base].u.jsValue->isObject());
2256 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2257 Identifier& ident = codeBlock->identifiers[property];
2258 ASSERT(r[function].u.jsValue->isObject());
2259 baseObj->defineSetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2264 BEGIN_OPCODE(op_jsr) {
2265 /* jsr retAddrDst(r) target(offset)
2267 Places the address of the next instruction into the retAddrDst
2268 register and jumps to offset target from the current instruction.
2270 int retAddrDst = (++vPC)->u.operand;
2271 int target = (++vPC)->u.operand;
2272 r[retAddrDst].u.vPC = vPC + 1;
2277 BEGIN_OPCODE(op_sret) {
2278 /* sret retAddrSrc(r)
2280 Jumps to the address stored in the retAddrSrc register. This
2281 differs from op_jmp because the target address is stored in a
2282 register, not as an immediate.
2284 int retAddrSrc = (++vPC)->u.operand;
2285 vPC = r[retAddrSrc].u.vPC;
2288 BEGIN_OPCODE(op_debug) {
2289 /* debug debugHookID(n) firstLine(n) lastLine(n)
2291 Notifies the debugger of the current state of execution:
2292 didEnterCallFrame; willLeaveCallFrame; or willExecuteStatement.
2294 This opcode is only generated while the debugger is attached.
2297 int registerOffset = r - (*registerBase);
2298 registerFile->setSafeForReentry(true);
2299 debug(exec, vPC, codeBlock, scopeChain, registerBase, r);
2300 registerFile->setSafeForReentry(false);
2301 r = (*registerBase) + registerOffset;
2307 exec->clearException();
2308 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2310 *exception = exceptionValue;
2319 #undef VM_CHECK_EXCEPTION
2322 JSValue* Machine::retrieveArguments(ExecState* exec, FunctionImp* function) const
2324 Register** registerBase;
2325 int callFrameOffset;
2327 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2330 Register* callFrame = (*registerBase) + callFrameOffset;
2331 JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue);
2333 CodeBlock* codeBlock = &function->body->generatedCode();
2334 activation = new JSActivation(function->body, registerBase, callFrameOffset + CallFrameHeaderSize + codeBlock->numLocals);
2335 callFrame[OptionalCalleeActivation].u.jsValue = activation;
2338 return activation->get(exec, exec->propertyNames().arguments);
2341 JSValue* Machine::retrieveCaller(ExecState* exec, FunctionImp* function) const
2343 Register** registerBase;
2344 int callFrameOffset;
2346 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2349 int callerFrameOffset;
2350 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callerFrameOffset))
2353 Register* callerFrame = (*registerBase) + callerFrameOffset;
2354 ASSERT(callerFrame[Callee].u.jsValue);
2355 return callerFrame[Callee].u.jsValue;
2358 bool Machine::getCallFrame(ExecState* exec, FunctionImp* function, Register**& registerBase, int& callFrameOffset) const
2360 callFrameOffset = exec->m_callFrameOffset;
2363 while (callFrameOffset < 0) {
2364 exec = exec->m_prev;
2367 callFrameOffset = exec->m_callFrameOffset;
2370 registerBase = exec->m_registerFile->basePointer();
2371 Register* callFrame = (*registerBase) + callFrameOffset;
2372 if (callFrame[Callee].u.jsValue == function)
2375 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callFrameOffset))
2376 callFrameOffset = -1;
2380 void Machine::getFunctionAndArguments(Register** registerBase, Register* callFrame, FunctionImp*& function, Register*& argv, int& argc)
2382 function = static_cast<FunctionImp*>(callFrame[Callee].u.jsValue);
2383 ASSERT(function->inherits(&FunctionImp::info));
2385 argv = (*registerBase) + callFrame[CallerRegisterOffset].u.i + callFrame[ArgumentStartRegister].u.i + 1; // skip "this"
2386 argc = callFrame[ArgumentCount].u.i - 1; // skip "this"