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 static NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
442 Profiler** profiler = Profiler::enabledProfilerReference();
443 JSObject* evalFunction = scopeChain->globalObject()->evalFunction();
445 (*profiler)->willExecute(exec, evalFunction);
447 JSValue* x = argc >= 2 ? r[argv + 1].u.jsValue : jsUndefined();
452 UString s = x->toString(exec);
453 if (exec->hadException()) {
454 exceptionValue = exec->exception();
455 exec->clearException();
462 RefPtr<EvalNode> evalNode = parser().parse<EvalNode>(exec, UString(), 0, UStringSourceProvider::create(s), &sourceId, &errLine, &errMsg);
465 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
469 JSValue* result = machine().execute(evalNode.get(), exec, thisObj, registerFile, r - (*registerFile->basePointer()) + argv + argc, scopeChain, &exceptionValue);
472 (*profiler)->didExecute(exec, evalFunction);
479 ASSERT(JSLock::currentThreadIsHoldingLock());
480 static Machine machine;
487 privateExecute(InitializeAndReturn);
490 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
492 ScopeChain sc(scopeChain);
493 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(sc.bottom());
494 codeBlock->dump(globalObject->globalExec());
495 dumpRegisters(codeBlock, registerFile, r);
498 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
500 printf("Register frame: \n\n");
501 printf("----------------------------------------\n");
502 printf(" use | address | value \n");
503 printf("----------------------------------------\n");
508 if (isGlobalCallFrame(registerFile->basePointer(), r)) {
509 it = r - registerFile->numGlobalSlots();
513 printf("[global var] | %10p | %10p \n", it, (*it).u.jsValue);
516 printf("----------------------------------------\n");
519 it = r - codeBlock->numLocals - CallFrameHeaderSize;
520 end = it + CallFrameHeaderSize;
523 printf("[call frame] | %10p | %10p \n", it, (*it).u.jsValue);
526 printf("----------------------------------------\n");
529 end = it + codeBlock->numParameters;
532 printf("[param] | %10p | %10p \n", it, (*it).u.jsValue);
535 printf("----------------------------------------\n");
538 end = it + codeBlock->numVars;
541 printf("[var] | %10p | %10p \n", it, (*it).u.jsValue);
544 printf("----------------------------------------\n");
548 end = it + codeBlock->numTemporaries;
551 printf("[temp] | %10p | %10p \n", it, (*it).u.jsValue);
557 bool Machine::isOpcode(Opcode opcode)
559 #if HAVE(COMPUTED_GOTO)
560 return opcode != HashTraits<Opcode>::emptyValue()
561 && !HashTraits<Opcode>::isDeletedValue(opcode)
562 && m_opcodeIDTable.contains(opcode);
564 return opcode >= 0 && opcode <= op_end;
568 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction*& vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
570 CodeBlock* oldCodeBlock = codeBlock;
572 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
573 if (!isGlobalCallFrame(registerBase, r)) {
574 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
575 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
579 if (oldCodeBlock->needsFullScopeChain)
582 if (isGlobalCallFrame(registerBase, r))
585 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
587 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
591 // If this call frame created an activation, tear it off.
592 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
593 ASSERT(activation->isActivationObject());
594 activation->copyRegisters();
597 k = codeBlock->jsValues.data();
598 scopeChain = callFrame[CallerScopeChain].u.scopeChain;
599 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
600 r = (*registerBase) + callerRegisterOffset;
601 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
602 vPC = callFrame[ReturnVPC].u.vPC;
604 if (Profiler* profiler = *Profiler::enabledProfilerReference())
605 profiler->didExecute(exec, callFrame[Callee].u.jsObject);
609 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction* vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
611 // Set up the exception object
613 if (exceptionValue->isObject()) {
614 JSObject* exception = static_cast<JSObject*>(exceptionValue);
615 if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
616 exception->put(exec, "line", jsNumber(codeBlock->lineNumberForVPC(vPC)));
617 exception->put(exec, "sourceURL", jsOwnedString(codeBlock->ownerNode->sourceURL()));
621 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
622 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
623 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
626 // Calculate an exception handler vPC, unwinding call frames as necessary.
629 Instruction* handlerVPC;
631 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth))
632 if (!unwindCallFrame(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r))
635 // Now unwind the scope chain within the exception handler's call frame.
637 ScopeChain sc(scopeChain);
638 int scopeDelta = depth(sc) - scopeDepth;
639 ASSERT(scopeDelta >= 0);
642 setScopeChain(exec, scopeChain, sc.node());
647 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, RegisterFileStack* registerFileStack, JSValue** exception)
649 if (m_reentryDepth >= MaxReentryDepth) {
650 *exception = createStackOverflowError(exec);
654 RegisterFile* registerFile = registerFileStack->pushGlobalRegisterFile();
655 ASSERT(registerFile->numGlobalSlots());
656 CodeBlock* codeBlock = &programNode->code(scopeChain, !registerFileStack->inImplicitCall());
657 registerFile->addGlobalSlots(codeBlock->numVars);
659 registerFile->uncheckedGrow(codeBlock->numTemporaries);
660 Register* r = (*registerFile->basePointer());
662 r[ProgramCodeThisRegister].u.jsValue = thisObj;
664 if (codeBlock->needsFullScopeChain)
665 scopeChain = scopeChain->copy();
667 Profiler** profiler = Profiler::enabledProfilerReference();
669 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
671 ExecState newExec(exec, this, registerFile, scopeChain, -1);
674 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
677 registerFileStack->popGlobalRegisterFile();
680 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
685 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, FunctionImp* function, JSObject* thisObj, const List& args, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
687 if (m_reentryDepth >= MaxReentryDepth) {
688 *exception = createStackOverflowError(exec);
692 RegisterFile* registerFile = registerFileStack->current();
694 int argv = CallFrameHeaderSize;
695 int argc = args.size() + 1; // implicit "this" parameter
697 size_t oldSize = registerFile->size();
698 if (!registerFile->grow(oldSize + CallFrameHeaderSize + argc)) {
699 *exception = createStackOverflowError(exec);
703 Register** registerBase = registerFile->basePointer();
704 int registerOffset = oldSize;
705 int callFrameOffset = registerOffset;
706 Register* callFrame = (*registerBase) + callFrameOffset;
708 // put args in place, including "this"
709 Register* dst = callFrame + CallFrameHeaderSize;
710 (*dst).u.jsValue = thisObj;
712 List::const_iterator end = args.end();
713 for (List::const_iterator it = args.begin(); it != end; ++it)
714 (*++dst).u.jsValue = *it;
716 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
717 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, argv, argc, 0, function);
719 CodeBlock* newCodeBlock = &functionBodyNode->code(scopeChain);
720 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, *exception);
722 registerFile->shrink(oldSize);
726 scopeChain = scopeChainForCall(functionBodyNode, newCodeBlock, scopeChain, registerBase, r);
728 ExecState newExec(exec, this, registerFile, scopeChain, callFrameOffset);
730 Profiler** profiler = Profiler::enabledProfilerReference();
732 (*profiler)->willExecute(exec, function);
735 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, newCodeBlock, exception);
739 (*profiler)->didExecute(exec, function);
741 registerFile->shrink(oldSize);
745 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFile* registerFile, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
747 if (m_reentryDepth >= MaxReentryDepth) {
748 *exception = createStackOverflowError(exec);
752 EvalCodeBlock* codeBlock = &evalNode->code(scopeChain);
754 JSVariableObject* variableObject;
755 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
757 if (node->object->isVariableObject()) {
758 variableObject = static_cast<JSVariableObject*>(node->object);
763 for (Vector<Identifier>::const_iterator iter = codeBlock->declaredVariableNames.begin(); iter != codeBlock->declaredVariableNames.end(); ++iter) {
764 Identifier ident = *iter;
766 if (!variableObject->hasProperty(exec, ident))
767 variableObject->put(exec, ident, jsUndefined());
770 ASSERT(codeBlock->functions.size() == codeBlock->declaredFunctionNames.size());
771 for (size_t i = 0; i < codeBlock->functions.size(); ++i)
772 variableObject->put(exec, codeBlock->declaredFunctionNames[i], codeBlock->functions[i]->makeFunction(exec, scopeChain));
774 size_t oldSize = registerFile->size();
775 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numTemporaries + CallFrameHeaderSize;
776 if (!registerFile->grow(newSize)) {
777 *exception = createStackOverflowError(exec);
781 Register* callFrame = *registerFile->basePointer() + registerOffset;
783 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
784 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, 0, 0, 0, 0);
786 Register* r = callFrame + CallFrameHeaderSize + codeBlock->numVars;
787 r[ProgramCodeThisRegister].u.jsValue = thisObj;
789 if (codeBlock->needsFullScopeChain)
790 scopeChain = scopeChain->copy();
792 Profiler** profiler = Profiler::enabledProfilerReference();
794 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
796 ExecState newExec(exec, this, registerFile, scopeChain, -1);
799 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
802 registerFile->shrink(oldSize);
805 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
810 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
812 RegisterFile* registerFile = registerFileStack->current();
813 if (registerFile->safeForReentry())
814 return Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
815 registerFile = registerFileStack->pushFunctionRegisterFile();
816 JSValue* result = Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
817 registerFileStack->popFunctionRegisterFile();
821 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
823 scopeChain = newScopeChain;
824 exec->m_scopeChain = newScopeChain;
827 NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register** registerBase, Register* r)
829 int debugHookID = (++vPC)->u.operand;
830 int firstLine = (++vPC)->u.operand;
831 int lastLine = (++vPC)->u.operand;
833 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
837 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, 0, registerBase, r - *registerBase);
839 switch((DebugHookID)debugHookID) {
840 case DidEnterCallFrame: {
841 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
844 case WillLeaveCallFrame: {
845 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
848 case WillExecuteStatement: {
849 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
855 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
857 // One-time initialization of our address tables. We have to put this code
858 // here because our labels are only in scope inside this function.
859 if (flag == InitializeAndReturn) {
860 #if HAVE(COMPUTED_GOTO)
861 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
862 FOR_EACH_OPCODE_ID(ADD_OPCODE);
865 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
866 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
868 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
869 op_throw_end_indirect = &&op_throw_end;
870 op_call_indirect = &&op_call;
871 #endif // HAVE(COMPUTED_GOTO)
875 JSValue* exceptionValue = 0;
876 Instruction* handlerVPC = 0;
878 Register** registerBase = registerFile->basePointer();
879 Instruction* vPC = codeBlock->instructions.begin();
880 JSValue** k = codeBlock->jsValues.data();
881 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
883 #if HAVE(COMPUTED_GOTO)
884 // Yet another hack around GCC's various foibles, in this case fetching the
885 // profiler reference results in a regression. Removing this indirection
886 // results in a 0.8% regression.
887 goto *(&&profilerFetchHack);
891 registerFile->setSafeForReentry(false);
892 #define VM_CHECK_EXCEPTION() \
894 if (UNLIKELY(exec->hadException())) { \
895 exceptionValue = exec->exception(); \
900 #if HAVE(COMPUTED_GOTO)
901 #define NEXT_OPCODE goto *vPC->u.opcode
902 #define BEGIN_OPCODE(opcode) opcode:
905 #define NEXT_OPCODE continue
906 #define BEGIN_OPCODE(opcode) case opcode:
907 while(1) // iterator loop begins
908 switch (vPC->u.opcode)
911 BEGIN_OPCODE(op_load) {
912 /* load dst(r) src(k)
914 Copies constant src to register dst.
916 int dst = (++vPC)->u.operand;
917 int src = (++vPC)->u.operand;
918 r[dst].u.jsValue = k[src];
923 BEGIN_OPCODE(op_new_object) {
926 Constructs a new empty Object instance using the original
927 constructor, and puts the result in register dst.
929 int dst = (++vPC)->u.operand;
930 r[dst].u.jsValue = scopeChain->globalObject()->objectConstructor()->construct(exec, exec->emptyList());
935 BEGIN_OPCODE(op_new_array) {
938 Constructs a new empty Array instance using the original
939 constructor, and puts the result in register dst.
941 int dst = (++vPC)->u.operand;
942 r[dst].u.jsValue = scopeChain->globalObject()->arrayConstructor()->construct(exec, exec->emptyList());
947 BEGIN_OPCODE(op_new_regexp) {
948 /* new_regexp dst(r) regExp(re)
950 Constructs a new RegExp instance using the original
951 constructor from regexp regExp, and puts the result in
954 int dst = (++vPC)->u.operand;
955 int regExp = (++vPC)->u.operand;
956 r[dst].u.jsValue = new RegExpImp(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
961 BEGIN_OPCODE(op_mov) {
964 Copies register src to register dst.
966 int dst = (++vPC)->u.operand;
967 int src = (++vPC)->u.operand;
973 BEGIN_OPCODE(op_eq) {
974 /* eq dst(r) src1(r) src2(r)
976 Checks whether register src1 and register src2 are equal,
977 as with the ECMAScript '==' operator, and puts the result
978 as a boolean in register dst.
980 int dst = (++vPC)->u.operand;
981 int src1 = (++vPC)->u.operand;
982 int src2 = (++vPC)->u.operand;
983 JSValue* result = jsBoolean(equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
984 VM_CHECK_EXCEPTION();
985 r[dst].u.jsValue = result;
990 BEGIN_OPCODE(op_neq) {
991 /* neq dst(r) src1(r) src2(r)
993 Checks whether register src1 and register src2 are not
994 equal, as with the ECMAScript '!=' operator, and puts the
995 result as a boolean in register dst.
997 int dst = (++vPC)->u.operand;
998 int src1 = (++vPC)->u.operand;
999 int src2 = (++vPC)->u.operand;
1000 JSValue* result = jsBoolean(!equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1001 VM_CHECK_EXCEPTION();
1002 r[dst].u.jsValue = result;
1007 BEGIN_OPCODE(op_stricteq) {
1008 /* stricteq dst(r) src1(r) src2(r)
1010 Checks whether register src1 and register src2 are strictly
1011 equal, as with the ECMAScript '===' operator, and puts the
1012 result as a boolean in register dst.
1014 int dst = (++vPC)->u.operand;
1015 int src1 = (++vPC)->u.operand;
1016 int src2 = (++vPC)->u.operand;
1017 r[dst].u.jsValue = jsBoolean(strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
1022 BEGIN_OPCODE(op_nstricteq) {
1023 /* nstricteq dst(r) src1(r) src2(r)
1025 Checks whether register src1 and register src2 are not
1026 strictly equal, as with the ECMAScript '!==' operator, and
1027 puts the result as a boolean in register dst.
1029 int dst = (++vPC)->u.operand;
1030 int src1 = (++vPC)->u.operand;
1031 int src2 = (++vPC)->u.operand;
1032 r[dst].u.jsValue = jsBoolean(!strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
1037 BEGIN_OPCODE(op_less) {
1038 /* less dst(r) src1(r) src2(r)
1040 Checks whether register src1 is less than register src2, as
1041 with the ECMAScript '<' operator, and puts the result as
1042 a boolean in register dst.
1044 int dst = (++vPC)->u.operand;
1045 int src1 = (++vPC)->u.operand;
1046 int src2 = (++vPC)->u.operand;
1047 JSValue* result = jsBoolean(jsLess(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1048 VM_CHECK_EXCEPTION();
1049 r[dst].u.jsValue = result;
1054 BEGIN_OPCODE(op_lesseq) {
1055 /* lesseq dst(r) src1(r) src2(r)
1057 Checks whether register src1 is less than or equal to
1058 register src2, as with the ECMAScript '<=' operator, and
1059 puts the result as a boolean in register dst.
1061 int dst = (++vPC)->u.operand;
1062 int src1 = (++vPC)->u.operand;
1063 int src2 = (++vPC)->u.operand;
1064 JSValue* result = jsBoolean(jsLessEq(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1065 VM_CHECK_EXCEPTION();
1066 r[dst].u.jsValue = result;
1071 BEGIN_OPCODE(op_pre_inc) {
1072 /* pre_inc srcDst(r)
1074 Converts register srcDst to number, adds one, and puts the result
1075 back in register srcDst.
1077 int srcDst = (++vPC)->u.operand;
1078 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) + 1);
1079 VM_CHECK_EXCEPTION();
1080 r[srcDst].u.jsValue = result;
1085 BEGIN_OPCODE(op_pre_dec) {
1086 /* pre_dec srcDst(r)
1088 Converts register srcDst to number, subtracts one, and puts the result
1089 back in register srcDst.
1091 int srcDst = (++vPC)->u.operand;
1092 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) - 1);
1093 VM_CHECK_EXCEPTION();
1094 r[srcDst].u.jsValue = result;
1099 BEGIN_OPCODE(op_post_inc) {
1100 /* post_inc dst(r) srcDst(r)
1102 Converts register srcDst to number. The number itself is
1103 written to register dst, and the number plus one is written
1104 back to register srcDst.
1106 int dst = (++vPC)->u.operand;
1107 int srcDst = (++vPC)->u.operand;
1108 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1109 VM_CHECK_EXCEPTION();
1111 r[dst].u.jsValue = number;
1112 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() + 1);
1117 BEGIN_OPCODE(op_post_dec) {
1118 /* post_dec dst(r) srcDst(r)
1120 Converts register srcDst to number. The number itself is
1121 written to register dst, and the number minus one is written
1122 back to register srcDst.
1124 int dst = (++vPC)->u.operand;
1125 int srcDst = (++vPC)->u.operand;
1126 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1127 VM_CHECK_EXCEPTION();
1129 r[dst].u.jsValue = number;
1130 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() - 1);
1135 BEGIN_OPCODE(op_to_jsnumber) {
1136 /* to_jsnumber dst(r) src(r)
1138 Converts register src to number, and puts the result
1141 int dst = (++vPC)->u.operand;
1142 int src = (++vPC)->u.operand;
1143 JSValue* result = r[src].u.jsValue->toJSNumber(exec);
1144 VM_CHECK_EXCEPTION();
1146 r[dst].u.jsValue = result;
1151 BEGIN_OPCODE(op_negate) {
1152 /* negate dst(r) src(r)
1154 Converts register src to number, negates it, and puts the
1155 result in register dst.
1157 int dst = (++vPC)->u.operand;
1158 int src = (++vPC)->u.operand;
1159 JSValue* result = jsNumber(-r[src].u.jsValue->toNumber(exec));
1160 VM_CHECK_EXCEPTION();
1161 r[dst].u.jsValue = result;
1166 BEGIN_OPCODE(op_add) {
1167 /* add dst(r) src1(r) src2(r)
1169 Adds register src1 and register src2, and puts the result
1170 in register dst. (JS add may be string concatenation or
1171 numeric add, depending on the types of the operands.)
1173 int dst = (++vPC)->u.operand;
1174 int src1 = (++vPC)->u.operand;
1175 int src2 = (++vPC)->u.operand;
1176 JSValue* result = jsAdd(exec, r[src1].u.jsValue, r[src2].u.jsValue);
1177 VM_CHECK_EXCEPTION();
1178 r[dst].u.jsValue = result;
1182 BEGIN_OPCODE(op_mul) {
1183 /* mul dst(r) src1(r) src2(r)
1185 Multiplies register src1 and register src2 (converted to
1186 numbers), and puts the product in register dst.
1188 int dst = (++vPC)->u.operand;
1189 int src1 = (++vPC)->u.operand;
1190 int src2 = (++vPC)->u.operand;
1191 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) * r[src2].u.jsValue->toNumber(exec));
1192 VM_CHECK_EXCEPTION();
1193 r[dst].u.jsValue = result;
1198 BEGIN_OPCODE(op_div) {
1199 /* div dst(r) dividend(r) divisor(r)
1201 Divides register dividend (converted to number) by the
1202 register divisor (converted to number), and puts the
1203 quotient in register dst.
1205 int dst = (++vPC)->u.operand;
1206 int dividend = (++vPC)->u.operand;
1207 int divisor = (++vPC)->u.operand;
1208 JSValue* result = jsNumber(r[dividend].u.jsValue->toNumber(exec) / r[divisor].u.jsValue->toNumber(exec));
1209 VM_CHECK_EXCEPTION();
1210 r[dst].u.jsValue = result;
1214 BEGIN_OPCODE(op_mod) {
1215 /* mod dst(r) dividend(r) divisor(r)
1217 Divides register dividend (converted to number) by
1218 register divisor (converted to number), and puts the
1219 remainder in register dst.
1221 int dst = (++vPC)->u.operand;
1222 int dividend = (++vPC)->u.operand;
1223 int divisor = (++vPC)->u.operand;
1224 double d = r[dividend].u.jsValue->toNumber(exec);
1225 JSValue* result = jsNumber(fmod(d, r[divisor].u.jsValue->toNumber(exec)));
1226 VM_CHECK_EXCEPTION();
1227 r[dst].u.jsValue = result;
1231 BEGIN_OPCODE(op_sub) {
1232 /* sub dst(r) src1(r) src2(r)
1234 Subtracts register src2 (converted to number) from register
1235 src1 (converted to number), and puts the difference in
1238 int dst = (++vPC)->u.operand;
1239 int src1 = (++vPC)->u.operand;
1240 int src2 = (++vPC)->u.operand;
1241 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) - r[src2].u.jsValue->toNumber(exec));
1242 VM_CHECK_EXCEPTION();
1243 r[dst].u.jsValue = result;
1247 BEGIN_OPCODE(op_lshift) {
1248 /* lshift dst(r) val(r) shift(r)
1250 Performs left shift of register val (converted to int32) by
1251 register shift (converted to uint32), and puts the result
1254 int dst = (++vPC)->u.operand;
1255 int val = (++vPC)->u.operand;
1256 int shift = (++vPC)->u.operand;
1257 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) << (r[shift].u.jsValue->toUInt32(exec)));
1258 VM_CHECK_EXCEPTION();
1259 r[dst].u.jsValue = result;
1264 BEGIN_OPCODE(op_rshift) {
1265 /* rshift dst(r) val(r) shift(r)
1267 Performs arithmetic right shift of register val (converted
1268 to int32) by register shift (converted to
1269 uint32), and puts the result in register dst.
1271 int dst = (++vPC)->u.operand;
1272 int val = (++vPC)->u.operand;
1273 int shift = (++vPC)->u.operand;
1274 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1275 VM_CHECK_EXCEPTION();
1276 r[dst].u.jsValue = result;
1281 BEGIN_OPCODE(op_urshift) {
1282 /* rshift dst(r) val(r) shift(r)
1284 Performs logical right shift of register val (converted
1285 to uint32) by register shift (converted to
1286 uint32), and puts the result in register dst.
1288 int dst = (++vPC)->u.operand;
1289 int val = (++vPC)->u.operand;
1290 int shift = (++vPC)->u.operand;
1291 JSValue* result = jsNumber((r[val].u.jsValue->toUInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1292 VM_CHECK_EXCEPTION();
1293 r[dst].u.jsValue = result;
1298 BEGIN_OPCODE(op_bitand) {
1299 /* bitand dst(r) src1(r) src2(r)
1301 Computes bitwise AND of register src1 (converted to int32)
1302 and register src2 (converted to int32), and puts the result
1305 int dst = (++vPC)->u.operand;
1306 int src1 = (++vPC)->u.operand;
1307 int src2 = (++vPC)->u.operand;
1308 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) & (r[src2].u.jsValue->toInt32(exec)));
1309 VM_CHECK_EXCEPTION();
1310 r[dst].u.jsValue = result;
1315 BEGIN_OPCODE(op_bitxor) {
1316 /* bitxor dst(r) src1(r) src2(r)
1318 Computes bitwise XOR of register src1 (converted to int32)
1319 and register src2 (converted to int32), and puts the result
1322 int dst = (++vPC)->u.operand;
1323 int src1 = (++vPC)->u.operand;
1324 int src2 = (++vPC)->u.operand;
1325 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) ^ (r[src2].u.jsValue->toInt32(exec)));
1326 VM_CHECK_EXCEPTION();
1327 r[dst].u.jsValue = result;
1332 BEGIN_OPCODE(op_bitor) {
1333 /* bitor dst(r) src1(r) src2(r)
1335 Computes bitwise OR of register src1 (converted to int32)
1336 and register src2 (converted to int32), and puts the
1337 result in register dst.
1339 int dst = (++vPC)->u.operand;
1340 int src1 = (++vPC)->u.operand;
1341 int src2 = (++vPC)->u.operand;
1342 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) | (r[src2].u.jsValue->toInt32(exec)));
1343 VM_CHECK_EXCEPTION();
1344 r[dst].u.jsValue = result;
1349 BEGIN_OPCODE(op_bitnot) {
1350 /* bitnot dst(r) src(r)
1352 Computes bitwise NOT of register src1 (converted to int32),
1353 and puts the result in register dst.
1355 int dst = (++vPC)->u.operand;
1356 int src = (++vPC)->u.operand;
1357 JSValue* result = jsNumber(~r[src].u.jsValue->toInt32(exec));
1358 VM_CHECK_EXCEPTION();
1359 r[dst].u.jsValue = result;
1364 BEGIN_OPCODE(op_not) {
1365 /* not dst(r) src1(r) src2(r)
1367 Computes logical NOT of register src1 (converted to
1368 boolean), and puts the result in register dst.
1370 int dst = (++vPC)->u.operand;
1371 int src = (++vPC)->u.operand;
1372 JSValue* result = jsBoolean(!r[src].u.jsValue->toBoolean(exec));
1373 VM_CHECK_EXCEPTION();
1374 r[dst].u.jsValue = result;
1379 BEGIN_OPCODE(op_instanceof) {
1380 /* instanceof dst(r) value(r) constructor(r)
1382 Tests whether register value is an instance of register
1383 constructor, and puts the boolean result in register dst.
1385 Raises an exception if register constructor is not an
1388 int dst = (++vPC)->u.operand;
1389 int value = (++vPC)->u.operand;
1390 int base = (++vPC)->u.operand;
1392 JSValue* baseVal = r[base].u.jsValue;
1394 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1397 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1398 r[dst].u.jsValue = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].u.jsValue) : false);
1403 BEGIN_OPCODE(op_typeof) {
1404 /* typeof dst(r) src(r)
1406 Determines the type string for src according to ECMAScript
1407 rules, and puts the result in register dst.
1409 int dst = (++vPC)->u.operand;
1410 int src = (++vPC)->u.operand;
1411 r[dst].u.jsValue = jsTypeStringForValue(r[src].u.jsValue);
1416 BEGIN_OPCODE(op_in) {
1417 /* in dst(r) property(r) base(r)
1419 Tests whether register base has a property named register
1420 property, and puts the boolean result in register dst.
1422 Raises an exception if register constructor is not an
1425 int dst = (++vPC)->u.operand;
1426 int property = (++vPC)->u.operand;
1427 int base = (++vPC)->u.operand;
1429 JSValue* baseVal = r[base].u.jsValue;
1430 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1433 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1435 JSValue* propName = r[property].u.jsValue;
1438 if (propName->getUInt32(i))
1439 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, i));
1441 Identifier property(propName->toString(exec));
1442 VM_CHECK_EXCEPTION();
1443 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, property));
1449 BEGIN_OPCODE(op_resolve) {
1450 /* resolve dst(r) property(id)
1452 Looks up the property named by identifier property in the
1453 scope chain, and writes the resulting value to register
1454 dst. If the property is not found, raises an exception.
1456 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1462 BEGIN_OPCODE(op_resolve_skip) {
1463 /* resolve_skip dst(r) property(id) skip(n)
1465 Looks up the property named by identifier property in the
1466 scope chain skipping the top 'skip' levels, and writes the resulting
1467 value to register dst. If the property is not found, raises an exception.
1469 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1476 BEGIN_OPCODE(op_get_scoped_var) {
1477 /* get_scoped_var dst(r) index(n) skip(n)
1479 Loads the contents of the index-th local from the scope skip nodes from
1480 the top of the scope chain, and places it in register dst
1482 int dst = (++vPC)->u.operand;
1483 int index = (++vPC)->u.operand;
1484 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1486 ScopeChainIterator iter = scopeChain->begin();
1487 ScopeChainIterator end = scopeChain->end();
1488 ASSERT(iter != end);
1491 ASSERT(iter != end);
1494 ASSERT((*iter)->isVariableObject());
1495 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1496 r[dst].u.jsValue = scope->valueAt(index);
1500 BEGIN_OPCODE(op_put_scoped_var) {
1501 /* put_scoped_var index(n) skip(n) value(r)
1504 int index = (++vPC)->u.operand;
1505 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1506 int value = (++vPC)->u.operand;
1508 ScopeChainIterator iter = scopeChain->begin();
1509 ScopeChainIterator end = scopeChain->end();
1510 ASSERT(iter != end);
1513 ASSERT(iter != end);
1516 ASSERT((*iter)->isVariableObject());
1517 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1518 scope->valueAt(index) = r[value].u.jsValue;
1522 BEGIN_OPCODE(op_resolve_base) {
1523 /* resolve_base dst(r) property(id)
1525 Searches the scope chain for an object containing
1526 identifier property, and if one is found, writes it to
1527 register dst. If none is found, the outermost scope (which
1528 will be the global object) is stored in register dst.
1530 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1535 BEGIN_OPCODE(op_resolve_with_base) {
1536 /* resolve_with_base baseDst(r) propDst(r) property(id)
1538 Searches the scope chain for an object containing
1539 identifier property, and if one is found, writes it to
1540 register srcDst, and the retrieved property value to register
1541 propDst. If the property is not found, raises an exception.
1543 This is more efficient than doing resolve_base followed by
1544 resolve, or resolve_base followed by get_by_id, as it
1545 avoids duplicate hash lookups.
1547 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1553 BEGIN_OPCODE(op_resolve_func) {
1554 /* resolve_func baseDst(r) funcDst(r) property(id)
1556 Searches the scope chain for an object containing
1557 identifier property, and if one is found, writes the
1558 appropriate object to use as "this" when calling its
1559 properties to register baseDst; and the retrieved property
1560 value to register propDst. If the property is not found,
1561 raises an exception.
1563 This differs from resolve_with_base, because the
1564 global this value will be substituted for activations or
1565 the global object, which is the right behavior for function
1566 calls but not for other property lookup.
1568 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1574 BEGIN_OPCODE(op_get_by_id) {
1575 /* get_by_id dst(r) base(r) property(id)
1577 Converts register base to Object, gets the property
1578 named by identifier property from the object, and puts the
1579 result in register dst.
1581 int dst = (++vPC)->u.operand;
1582 int base = (++vPC)->u.operand;
1583 int property = (++vPC)->u.operand;
1585 int registerOffset = r - (*registerBase);
1587 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1589 Identifier& ident = codeBlock->identifiers[property];
1590 JSValue *result = baseObj->get(exec, ident);
1591 ASSERT(registerOffset == (r - (*registerBase)));
1592 VM_CHECK_EXCEPTION();
1593 r[dst].u.jsValue = result;
1597 BEGIN_OPCODE(op_put_by_id) {
1598 /* put_by_id base(r) property(id) value(r)
1600 Sets register value on register base as the property named
1601 by identifier property. Base is converted to object first.
1603 Unlike many opcodes, this one does not write any output to
1606 int base = (++vPC)->u.operand;
1607 int property = (++vPC)->u.operand;
1608 int value = (++vPC)->u.operand;
1610 int registerOffset = r - (*registerBase);
1613 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1615 Identifier& ident = codeBlock->identifiers[property];
1616 baseObj->put(exec, ident, r[value].u.jsValue);
1617 ASSERT(registerOffset == (r - (*registerBase)));
1619 VM_CHECK_EXCEPTION();
1623 BEGIN_OPCODE(op_del_by_id) {
1624 /* del_by_id dst(r) base(r) property(id)
1626 Converts register base to Object, deletes the property
1627 named by identifier property from the object, and writes a
1628 boolean indicating success (if true) or failure (if false)
1631 int dst = (++vPC)->u.operand;
1632 int base = (++vPC)->u.operand;
1633 int property = (++vPC)->u.operand;
1635 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1637 Identifier& ident = codeBlock->identifiers[property];
1638 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1639 VM_CHECK_EXCEPTION();
1640 r[dst].u.jsValue = result;
1644 BEGIN_OPCODE(op_get_by_val) {
1645 /* get_by_val dst(r) base(r) property(r)
1647 Converts register base to Object, gets the property named
1648 by register property from the object, and puts the result
1649 in register dst. property is nominally converted to string
1650 but numbers are treated more efficiently.
1652 int dst = (++vPC)->u.operand;
1653 int base = (++vPC)->u.operand;
1654 int property = (++vPC)->u.operand;
1656 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1658 JSValue* subscript = r[property].u.jsValue;
1661 if (subscript->getUInt32(i))
1662 result = baseObj->get(exec, i);
1664 Identifier property;
1665 if (subscript->isObject()) {
1666 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1667 property = Identifier(subscript->toString(exec));
1669 property = Identifier(subscript->toString(exec));
1671 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a getter after an exception is thrown
1672 result = baseObj->get(exec, property);
1675 VM_CHECK_EXCEPTION();
1676 r[dst].u.jsValue = result;
1680 BEGIN_OPCODE(op_put_by_val) {
1681 /* put_by_val base(r) property(r) value(r)
1683 Sets register value on register base as the property named
1684 by register property. Base is converted to object
1685 first. register property is nominally converted to string
1686 but numbers are treated more efficiently.
1688 Unlike many opcodes, this one does not write any output to
1691 int base = (++vPC)->u.operand;
1692 int property = (++vPC)->u.operand;
1693 int value = (++vPC)->u.operand;
1695 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1697 JSValue* subscript = r[property].u.jsValue;
1700 if (subscript->getUInt32(i))
1701 baseObj->put(exec, i, r[value].u.jsValue);
1703 Identifier property;
1704 if (subscript->isObject()) {
1705 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1706 property = Identifier(subscript->toString(exec));
1708 property = Identifier(subscript->toString(exec));
1710 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a setter after an exception is thrown
1711 baseObj->put(exec, property, r[value].u.jsValue);
1714 VM_CHECK_EXCEPTION();
1718 BEGIN_OPCODE(op_del_by_val) {
1719 /* del_by_val dst(r) base(r) property(r)
1721 Converts register base to Object, deletes the property
1722 named by register property from the object, and writes a
1723 boolean indicating success (if true) or failure (if false)
1726 int dst = (++vPC)->u.operand;
1727 int base = (++vPC)->u.operand;
1728 int property = (++vPC)->u.operand;
1730 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1732 JSValue* subscript = r[property].u.jsValue;
1735 if (subscript->getUInt32(i))
1736 result = jsBoolean(baseObj->deleteProperty(exec, i));
1738 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1739 Identifier property(subscript->toString(exec));
1740 VM_CHECK_EXCEPTION();
1741 result = jsBoolean(baseObj->deleteProperty(exec, property));
1744 VM_CHECK_EXCEPTION();
1745 r[dst].u.jsValue = result;
1749 BEGIN_OPCODE(op_put_by_index) {
1750 /* put_by_index base(r) property(n) value(r)
1752 Sets register value on register base as the property named
1753 by the immediate number property. Base is converted to
1754 object first. register property is nominally converted to
1755 string but numbers are treated more efficiently.
1757 Unlike many opcodes, this one does not write any output to
1760 This opcode is mainly used to initialize array literals.
1762 int base = (++vPC)->u.operand;
1763 unsigned property = (++vPC)->u.operand;
1764 int value = (++vPC)->u.operand;
1766 r[base].u.jsObject->put(exec, property, r[value].u.jsValue);
1771 BEGIN_OPCODE(op_jmp) {
1772 /* jmp target(offset)
1774 Jumps unconditionally to offset target from the current
1777 int target = (++vPC)->u.operand;
1782 BEGIN_OPCODE(op_jtrue) {
1783 /* jtrue cond(r) target(offset)
1785 Jumps to offset target from the current instruction, if and
1786 only if register cond converts to boolean as true.
1788 int cond = (++vPC)->u.operand;
1789 int target = (++vPC)->u.operand;
1790 if (r[cond].u.jsValue->toBoolean(exec)) {
1798 BEGIN_OPCODE(op_jfalse) {
1799 /* jfalse cond(r) target(offset)
1801 Jumps to offset target from the current instruction, if and
1802 only if register cond converts to boolean as false.
1804 int cond = (++vPC)->u.operand;
1805 int target = (++vPC)->u.operand;
1806 if (!r[cond].u.jsValue->toBoolean(exec)) {
1814 BEGIN_OPCODE(op_new_func) {
1815 /* new_func dst(r) func(f)
1817 Constructs a new Function instance from function func and
1818 the current scope chain using the original Function
1819 constructor, using the rules for function declarations, and
1820 puts the result in register dst.
1822 int dst = (++vPC)->u.operand;
1823 int func = (++vPC)->u.operand;
1825 r[dst].u.jsValue = codeBlock->functions[func]->makeFunction(exec, scopeChain);
1830 BEGIN_OPCODE(op_new_func_exp) {
1831 /* new_func_exp dst(r) func(f)
1833 Constructs a new Function instance from function func and
1834 the current scope chain using the original Function
1835 constructor, using the rules for function expressions, and
1836 puts the result in register dst.
1838 int dst = (++vPC)->u.operand;
1839 int func = (++vPC)->u.operand;
1841 r[dst].u.jsValue = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
1846 BEGIN_OPCODE(op_call_eval) {
1847 int dst = (++vPC)->u.operand;
1848 int func = (++vPC)->u.operand;
1849 int base = (++vPC)->u.operand;
1850 int argv = (++vPC)->u.operand;
1851 int argc = (++vPC)->u.operand;
1853 JSValue* funcVal = r[func].u.jsValue;
1854 JSValue* baseVal = r[base].u.jsValue;
1856 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
1857 int registerOffset = r - (*registerBase);
1859 JSObject* thisObject = r[codeBlock->thisRegister].u.jsObject;
1861 registerFile->setSafeForReentry(true);
1863 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, argv, argc, exceptionValue);
1865 registerFile->setSafeForReentry(false);
1866 r = (*registerBase) + registerOffset;
1871 r[dst].u.jsValue = result;
1877 // We didn't find the blessed version of eval, so reset vPC and process
1878 // this instruction as a normal function call, supplying the proper 'this'
1881 r[base].u.jsValue = baseVal->toObject(exec)->toThisObject(exec);
1883 #if HAVE(COMPUTED_GOTO)
1884 // Hack around gcc performance quirk by performing an indirect goto
1885 // in order to set the vPC -- attempting to do so directly results in a
1886 // significant regression.
1887 goto *op_call_indirect; // indirect goto -> op_call
1889 // fall through to op_call
1891 BEGIN_OPCODE(op_call) {
1892 int dst = (++vPC)->u.operand;
1893 int func = (++vPC)->u.operand;
1894 int base = (++vPC)->u.operand;
1895 int argv = (++vPC)->u.operand;
1896 int argc = (++vPC)->u.operand;
1898 JSValue* v = r[func].u.jsValue;
1901 CallType callType = v->getCallData(callData);
1903 if (callType == CallTypeJS) {
1904 if (*enabledProfilerReference)
1905 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
1906 int registerOffset = r - (*registerBase);
1907 Register* callFrame = r + argv - CallFrameHeaderSize;
1908 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
1910 r[argv].u.jsValue = base == missingThisObjectMarker() ? exec->globalThisValue() : r[base].u.jsValue; // "this" value
1911 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, dst, argv, argc, 0, v);
1913 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
1914 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
1916 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
1917 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
1918 if (UNLIKELY(exceptionValue != 0))
1921 codeBlock = newCodeBlock;
1922 exec->m_callFrameOffset = callFrameOffset;
1923 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
1924 k = codeBlock->jsValues.data();
1925 vPC = codeBlock->instructions.begin();
1930 if (callType == CallTypeNative) {
1931 if (*enabledProfilerReference)
1932 (*enabledProfilerReference)->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 (*enabledProfilerReference)
1948 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
1949 VM_CHECK_EXCEPTION();
1955 ASSERT(callType == CallTypeNone);
1957 exceptionValue = createNotAFunctionError(exec, v, 0);
1960 BEGIN_OPCODE(op_ret) {
1961 int r1 = (++vPC)->u.operand;
1963 CodeBlock* oldCodeBlock = codeBlock;
1965 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
1966 JSValue* returnValue = r[r1].u.jsValue;
1968 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
1969 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
1970 ASSERT(activation->isActivationObject());
1971 activation->copyRegisters();
1974 if (codeBlock->needsFullScopeChain)
1975 scopeChain->deref();
1977 if (callFrame[CalledAsConstructor].u.i && !returnValue->isObject()) {
1978 JSValue* thisObject = callFrame[CallFrameHeaderSize].u.jsValue;
1979 returnValue = thisObject;
1982 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
1986 k = codeBlock->jsValues.data();
1987 vPC = callFrame[ReturnVPC].u.vPC;
1988 setScopeChain(exec, scopeChain, callFrame[CallerScopeChain].u.scopeChain);
1989 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
1990 r = (*registerBase) + callerRegisterOffset;
1991 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
1992 int r0 = callFrame[ReturnValueRegister].u.i;
1993 r[r0].u.jsValue = returnValue;
1995 if (*enabledProfilerReference)
1996 (*enabledProfilerReference)->didExecute(exec, callFrame[Callee].u.jsObject);
2000 BEGIN_OPCODE(op_construct) {
2001 int dst = (++vPC)->u.operand;
2002 int func = (++vPC)->u.operand;
2003 int argv = (++vPC)->u.operand;
2004 int argc = (++vPC)->u.operand;
2006 JSValue* funcVal = r[func].u.jsValue;
2008 ConstructData constructData;
2009 ConstructType constructType = funcVal->getConstructData(constructData);
2011 // Removing this line of code causes a measurable regression on squirrelfish.
2012 JSObject* constructor = static_cast<JSObject*>(funcVal);
2014 if (constructType == ConstructTypeJS) {
2015 if (*enabledProfilerReference)
2016 (*enabledProfilerReference)->willExecute(exec, constructor);
2018 int registerOffset = r - (*registerBase);
2019 Register* callFrame = r + argv - CallFrameHeaderSize;
2020 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
2022 JSObject* prototype;
2023 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
2025 prototype = static_cast<JSObject*>(p);
2027 prototype = scopeChain->globalObject()->objectPrototype();
2028 JSObject* newObject = new JSObject(prototype);
2029 r[argv].u.jsValue = newObject; // "this" value
2031 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, dst, argv, argc, 1, constructor);
2033 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
2034 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
2036 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
2037 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
2041 codeBlock = newCodeBlock;
2042 exec->m_callFrameOffset = callFrameOffset;
2043 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
2044 k = codeBlock->jsValues.data();
2045 vPC = codeBlock->instructions.begin();
2050 if (constructType == ConstructTypeNative) {
2051 if (*enabledProfilerReference)
2052 (*enabledProfilerReference)->willExecute(exec, constructor);
2054 int registerOffset = r - (*registerBase);
2056 List args(&r[argv + 1].u.jsValue, argc - 1);
2057 registerFile->setSafeForReentry(true);
2058 JSValue* returnValue = constructor->construct(exec, args);
2059 registerFile->setSafeForReentry(false);
2061 r = (*registerBase) + registerOffset;
2062 VM_CHECK_EXCEPTION();
2063 r[dst].u.jsValue = returnValue;
2065 if (*enabledProfilerReference)
2066 (*enabledProfilerReference)->didExecute(exec, constructor);
2072 ASSERT(constructType == ConstructTypeNone);
2074 exceptionValue = createNotAConstructorError(exec, funcVal, 0);
2077 BEGIN_OPCODE(op_push_scope) {
2078 /* push_scope scope(r)
2080 Converts register scope to object, and pushes it onto the top
2081 of the current scope chain.
2083 int scope = (++vPC)->u.operand;
2084 JSValue* v = r[scope].u.jsValue;
2085 JSObject* o = v->toObject(exec);
2086 VM_CHECK_EXCEPTION();
2088 setScopeChain(exec, scopeChain, scopeChain->push(o));
2093 BEGIN_OPCODE(op_pop_scope) {
2096 Removes the top item from the current scope chain.
2098 setScopeChain(exec, scopeChain, scopeChain->pop());
2103 BEGIN_OPCODE(op_get_pnames) {
2104 /* get_pnames dst(r) base(r)
2106 Creates a property name list for register base and puts it
2107 in register dst. This is not a true JavaScript value, just
2108 a synthetic value used to keep the iteration state in a
2111 int dst = (++vPC)->u.operand;
2112 int base = (++vPC)->u.operand;
2114 r[dst].u.jsPropertyNameIterator = JSPropertyNameIterator::create(exec, r[base].u.jsValue);
2118 BEGIN_OPCODE(op_next_pname) {
2119 /* next_pname dst(r) iter(r) target(offset)
2121 Tries to copies the next name from property name list in
2122 register iter. If there are names left, then copies one to
2123 register dst, and jumps to offset target. If there are none
2124 left, invalidates the iterator and continues to the next
2127 int dst = (++vPC)->u.operand;
2128 int iter = (++vPC)->u.operand;
2129 int target = (++vPC)->u.operand;
2131 JSPropertyNameIterator* it = r[iter].u.jsPropertyNameIterator;
2132 if (JSValue* temp = it->next(exec)) {
2133 r[dst].u.jsValue = temp;
2142 BEGIN_OPCODE(op_jmp_scopes) {
2143 /* jmp_scopes count(n) target(offset)
2145 Removes the a number of items from the current scope chain
2146 specified by immediate number count, then jumps to offset
2149 int count = (++vPC)->u.operand;
2150 int target = (++vPC)->u.operand;
2152 ScopeChainNode* tmp = scopeChain;
2155 setScopeChain(exec, scopeChain, tmp);
2160 BEGIN_OPCODE(op_catch) {
2161 ASSERT(exceptionValue);
2162 ASSERT(!exec->hadException());
2163 int r0 = (++vPC)->u.operand;
2164 r[r0].u.jsValue = exceptionValue;
2169 BEGIN_OPCODE(op_throw) {
2170 int e = (++vPC)->u.operand;
2171 exceptionValue = r[e].u.jsValue;
2172 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2174 *exception = exceptionValue;
2178 #if HAVE(COMPUTED_GOTO)
2179 // Hack around gcc performance quirk by performing an indirect goto
2180 // in order to set the vPC -- attempting to do so directly results in a
2181 // significant regression.
2182 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2190 BEGIN_OPCODE(op_new_error) {
2191 /* new_error dst(r) type(n) message(k)
2193 Constructs a new Error instance using the original
2194 constructor, using immediate number n as the type and
2195 constant message as the message string. The result is
2196 written to register dst.
2198 int dst = (++vPC)->u.operand;
2199 int type = (++vPC)->u.operand;
2200 int message = (++vPC)->u.operand;
2202 r[dst].u.jsValue = Error::create(exec, (ErrorType)type, k[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2207 BEGIN_OPCODE(op_end) {
2208 if (codeBlock->needsFullScopeChain) {
2209 ASSERT(scopeChain->refCount > 1);
2210 scopeChain->deref();
2212 int r0 = (++vPC)->u.operand;
2213 return r[r0].u.jsValue;
2215 BEGIN_OPCODE(op_put_getter) {
2216 /* put_getter base(r) property(id) function(r)
2218 Sets register function on register base as the getter named
2219 by identifier property. Base and function are assumed to be
2220 objects as this op should only be used for getters defined
2221 in object literal form.
2223 Unlike many opcodes, this one does not write any output to
2226 int base = (++vPC)->u.operand;
2227 int property = (++vPC)->u.operand;
2228 int function = (++vPC)->u.operand;
2230 ASSERT(r[base].u.jsValue->isObject());
2231 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2232 Identifier& ident = codeBlock->identifiers[property];
2233 ASSERT(r[function].u.jsValue->isObject());
2234 baseObj->defineGetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2239 BEGIN_OPCODE(op_put_setter) {
2240 /* put_setter base(r) property(id) function(r)
2242 Sets register function on register base as the setter named
2243 by identifier property. Base and function are assumed to be
2244 objects as this op should only be used for setters defined
2245 in object literal form.
2247 Unlike many opcodes, this one does not write any output to
2250 int base = (++vPC)->u.operand;
2251 int property = (++vPC)->u.operand;
2252 int function = (++vPC)->u.operand;
2254 ASSERT(r[base].u.jsValue->isObject());
2255 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2256 Identifier& ident = codeBlock->identifiers[property];
2257 ASSERT(r[function].u.jsValue->isObject());
2258 baseObj->defineSetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2263 BEGIN_OPCODE(op_jsr) {
2264 /* jsr retAddrDst(r) target(offset)
2266 Places the address of the next instruction into the retAddrDst
2267 register and jumps to offset target from the current instruction.
2269 int retAddrDst = (++vPC)->u.operand;
2270 int target = (++vPC)->u.operand;
2271 r[retAddrDst].u.vPC = vPC + 1;
2276 BEGIN_OPCODE(op_sret) {
2277 /* sret retAddrSrc(r)
2279 Jumps to the address stored in the retAddrSrc register. This
2280 differs from op_jmp because the target address is stored in a
2281 register, not as an immediate.
2283 int retAddrSrc = (++vPC)->u.operand;
2284 vPC = r[retAddrSrc].u.vPC;
2287 BEGIN_OPCODE(op_debug) {
2288 /* debug debugHookID(n) firstLine(n) lastLine(n)
2290 Notifies the debugger of the current state of execution:
2291 didEnterCallFrame; willLeaveCallFrame; or willExecuteStatement.
2293 This opcode is only generated while the debugger is attached.
2296 int registerOffset = r - (*registerBase);
2297 registerFile->setSafeForReentry(true);
2298 debug(exec, vPC, codeBlock, scopeChain, registerBase, r);
2299 registerFile->setSafeForReentry(false);
2300 r = (*registerBase) + registerOffset;
2306 exec->clearException();
2307 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2309 *exception = exceptionValue;
2318 #undef VM_CHECK_EXCEPTION
2321 JSValue* Machine::retrieveArguments(ExecState* exec, FunctionImp* function) const
2323 Register** registerBase;
2324 int callFrameOffset;
2326 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2329 Register* callFrame = (*registerBase) + callFrameOffset;
2330 JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue);
2332 CodeBlock* codeBlock = &function->body->generatedCode();
2333 activation = new JSActivation(function->body, registerBase, callFrameOffset + CallFrameHeaderSize + codeBlock->numLocals);
2334 callFrame[OptionalCalleeActivation].u.jsValue = activation;
2337 return activation->get(exec, exec->propertyNames().arguments);
2340 JSValue* Machine::retrieveCaller(ExecState* exec, FunctionImp* function) const
2342 Register** registerBase;
2343 int callFrameOffset;
2345 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2348 int callerFrameOffset;
2349 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callerFrameOffset))
2352 Register* callerFrame = (*registerBase) + callerFrameOffset;
2353 ASSERT(callerFrame[Callee].u.jsValue);
2354 return callerFrame[Callee].u.jsValue;
2357 bool Machine::getCallFrame(ExecState* exec, FunctionImp* function, Register**& registerBase, int& callFrameOffset) const
2359 callFrameOffset = exec->m_callFrameOffset;
2362 while (callFrameOffset < 0) {
2363 exec = exec->m_prev;
2366 callFrameOffset = exec->m_callFrameOffset;
2369 registerBase = exec->m_registerFile->basePointer();
2370 Register* callFrame = (*registerBase) + callFrameOffset;
2371 if (callFrame[Callee].u.jsValue == function)
2374 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callFrameOffset))
2375 callFrameOffset = -1;
2379 void Machine::getFunctionAndArguments(Register** registerBase, Register* callFrame, FunctionImp*& function, Register*& argv, int& argc)
2381 function = static_cast<FunctionImp*>(callFrame[Callee].u.jsValue);
2382 ASSERT(function->inherits(&FunctionImp::info));
2384 argv = (*registerBase) + callFrame[CallerRegisterOffset].u.i + callFrame[ArgumentStartRegister].u.i + 1; // skip "this"
2385 argc = callFrame[ArgumentCount].u.i - 1; // skip "this"