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 #if JAVASCRIPT_PROFILING
443 Profiler** profiler = Profiler::enabledProfilerReference();
444 JSObject* evalFunction = scopeChain->globalObject()->evalFunction();
446 (*profiler)->willExecute(exec, evalFunction);
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);
475 (*profiler)->didExecute(exec, evalFunction);
479 return machine().execute(evalNode.get(), exec, thisObj, registerFile, r - (*registerFile->basePointer()) + argv + argc, scopeChain, &exceptionValue);
485 ASSERT(JSLock::currentThreadIsHoldingLock());
486 static Machine machine;
493 privateExecute(InitializeAndReturn);
496 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
498 ScopeChain sc(scopeChain);
499 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(sc.bottom());
500 codeBlock->dump(globalObject->globalExec());
501 dumpRegisters(codeBlock, registerFile, r);
504 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
506 printf("Register frame: \n\n");
507 printf("----------------------------------------\n");
508 printf(" use | address | value \n");
509 printf("----------------------------------------\n");
514 if (isGlobalCallFrame(registerFile->basePointer(), r)) {
515 it = r - registerFile->numGlobalSlots();
519 printf("[global var] | %10p | %10p \n", it, (*it).u.jsValue);
522 printf("----------------------------------------\n");
525 it = r - codeBlock->numLocals - CallFrameHeaderSize;
526 end = it + CallFrameHeaderSize;
529 printf("[call frame] | %10p | %10p \n", it, (*it).u.jsValue);
532 printf("----------------------------------------\n");
535 end = it + codeBlock->numParameters;
538 printf("[param] | %10p | %10p \n", it, (*it).u.jsValue);
541 printf("----------------------------------------\n");
544 end = it + codeBlock->numVars;
547 printf("[var] | %10p | %10p \n", it, (*it).u.jsValue);
550 printf("----------------------------------------\n");
554 end = it + codeBlock->numTemporaries;
557 printf("[temp] | %10p | %10p \n", it, (*it).u.jsValue);
563 bool Machine::isOpcode(Opcode opcode)
565 #if HAVE(COMPUTED_GOTO)
566 return opcode != HashTraits<Opcode>::emptyValue()
567 && !HashTraits<Opcode>::isDeletedValue(opcode)
568 && m_opcodeIDTable.contains(opcode);
570 return opcode >= 0 && opcode <= op_end;
574 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction*& vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
576 CodeBlock* oldCodeBlock = codeBlock;
578 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
579 if (!isGlobalCallFrame(registerBase, r)) {
580 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
581 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
585 if (oldCodeBlock->needsFullScopeChain)
588 if (isGlobalCallFrame(registerBase, r))
591 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
593 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
597 // If this call frame created an activation, tear it off.
598 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
599 ASSERT(activation->isActivationObject());
600 activation->copyRegisters();
603 k = codeBlock->jsValues.data();
604 scopeChain = callFrame[CallerScopeChain].u.scopeChain;
605 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
606 r = (*registerBase) + callerRegisterOffset;
607 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
608 vPC = callFrame[ReturnVPC].u.vPC;
610 #if JAVASCRIPT_PROFILING
611 if (Profiler* profiler = *Profiler::enabledProfilerReference())
612 profiler->didExecute(exec, callFrame[Callee].u.jsObject);
617 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction* vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
619 // Set up the exception object
621 if (exceptionValue->isObject()) {
622 JSObject* exception = static_cast<JSObject*>(exceptionValue);
623 if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
624 exception->put(exec, "line", jsNumber(codeBlock->lineNumberForVPC(vPC)));
625 exception->put(exec, "sourceURL", jsOwnedString(codeBlock->ownerNode->sourceURL()));
629 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
630 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
631 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
634 // Calculate an exception handler vPC, unwinding call frames as necessary.
637 Instruction* handlerVPC;
639 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth))
640 if (!unwindCallFrame(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r))
643 // Now unwind the scope chain within the exception handler's call frame.
645 ScopeChain sc(scopeChain);
646 int scopeDelta = depth(sc) - scopeDepth;
647 ASSERT(scopeDelta >= 0);
650 setScopeChain(exec, scopeChain, sc.node());
655 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, RegisterFileStack* registerFileStack, JSValue** exception)
657 if (m_reentryDepth >= MaxReentryDepth) {
658 *exception = createStackOverflowError(exec);
662 RegisterFile* registerFile = registerFileStack->pushGlobalRegisterFile();
663 ASSERT(registerFile->numGlobalSlots());
664 CodeBlock* codeBlock = &programNode->code(scopeChain, !registerFileStack->inImplicitCall());
665 registerFile->addGlobalSlots(codeBlock->numVars);
667 registerFile->uncheckedGrow(codeBlock->numTemporaries);
668 Register* r = (*registerFile->basePointer());
670 r[ProgramCodeThisRegister].u.jsValue = thisObj;
672 if (codeBlock->needsFullScopeChain)
673 scopeChain = scopeChain->copy();
675 #if JAVASCRIPT_PROFILING
676 Profiler** profiler = Profiler::enabledProfilerReference();
678 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
681 ExecState newExec(exec, this, registerFile, scopeChain, -1);
684 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
687 registerFileStack->popGlobalRegisterFile();
689 #if JAVASCRIPT_PROFILING
691 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
697 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, FunctionImp* function, JSObject* thisObj, const List& args, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
699 if (m_reentryDepth >= MaxReentryDepth) {
700 *exception = createStackOverflowError(exec);
704 RegisterFile* registerFile = registerFileStack->current();
706 int argv = CallFrameHeaderSize;
707 int argc = args.size() + 1; // implicit "this" parameter
709 size_t oldSize = registerFile->size();
710 if (!registerFile->grow(oldSize + CallFrameHeaderSize + argc)) {
711 *exception = createStackOverflowError(exec);
715 Register** registerBase = registerFile->basePointer();
716 int registerOffset = oldSize;
717 int callFrameOffset = registerOffset;
718 Register* callFrame = (*registerBase) + callFrameOffset;
720 // put args in place, including "this"
721 Register* dst = callFrame + CallFrameHeaderSize;
722 (*dst).u.jsValue = thisObj;
724 List::const_iterator end = args.end();
725 for (List::const_iterator it = args.begin(); it != end; ++it)
726 (*++dst).u.jsValue = *it;
728 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
729 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, argv, argc, 0, function);
731 CodeBlock* newCodeBlock = &functionBodyNode->code(scopeChain);
732 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, *exception);
734 registerFile->shrink(oldSize);
738 scopeChain = scopeChainForCall(functionBodyNode, newCodeBlock, scopeChain, registerBase, r);
740 ExecState newExec(exec, this, registerFile, scopeChain, callFrameOffset);
742 #if JAVASCRIPT_PROFILING
743 Profiler** profiler = Profiler::enabledProfilerReference();
745 (*profiler)->willExecute(exec, function);
749 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, newCodeBlock, exception);
752 #if JAVASCRIPT_PROFILING
754 (*profiler)->didExecute(exec, function);
756 registerFile->shrink(oldSize);
760 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFile* registerFile, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
762 if (m_reentryDepth >= MaxReentryDepth) {
763 *exception = createStackOverflowError(exec);
767 EvalCodeBlock* codeBlock = &evalNode->code(scopeChain);
769 JSVariableObject* variableObject;
770 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
772 if (node->object->isVariableObject()) {
773 variableObject = static_cast<JSVariableObject*>(node->object);
778 for (Vector<Identifier>::const_iterator iter = codeBlock->declaredVariableNames.begin(); iter != codeBlock->declaredVariableNames.end(); ++iter) {
779 Identifier ident = *iter;
781 if (!variableObject->hasProperty(exec, ident))
782 variableObject->put(exec, ident, jsUndefined());
785 ASSERT(codeBlock->functions.size() == codeBlock->declaredFunctionNames.size());
786 for (size_t i = 0; i < codeBlock->functions.size(); ++i)
787 variableObject->put(exec, codeBlock->declaredFunctionNames[i], codeBlock->functions[i]->makeFunction(exec, scopeChain));
789 size_t oldSize = registerFile->size();
790 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numTemporaries + CallFrameHeaderSize;
791 if (!registerFile->grow(newSize)) {
792 *exception = createStackOverflowError(exec);
796 Register* callFrame = *registerFile->basePointer() + registerOffset;
798 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
799 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, 0, 0, 0, 0);
801 Register* r = callFrame + CallFrameHeaderSize + codeBlock->numVars;
802 r[ProgramCodeThisRegister].u.jsValue = thisObj;
804 if (codeBlock->needsFullScopeChain)
805 scopeChain = scopeChain->copy();
807 #if JAVASCRIPT_PROFILING
808 Profiler** profiler = Profiler::enabledProfilerReference();
810 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
813 ExecState newExec(exec, this, registerFile, scopeChain, -1);
816 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
819 registerFile->shrink(oldSize);
821 #if JAVASCRIPT_PROFILING
823 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
829 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
831 RegisterFile* registerFile = registerFileStack->current();
832 if (registerFile->safeForReentry())
833 return Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
834 registerFile = registerFileStack->pushFunctionRegisterFile();
835 JSValue* result = Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
836 registerFileStack->popFunctionRegisterFile();
840 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
842 scopeChain = newScopeChain;
843 exec->m_scopeChain = newScopeChain;
846 NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register** registerBase, Register* r)
848 int debugHookID = (++vPC)->u.operand;
849 int firstLine = (++vPC)->u.operand;
850 int lastLine = (++vPC)->u.operand;
852 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
856 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, 0, registerBase, r - *registerBase);
858 switch((DebugHookID)debugHookID) {
859 case DidEnterCallFrame: {
860 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
863 case WillLeaveCallFrame: {
864 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
867 case WillExecuteStatement: {
868 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
874 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
876 // One-time initialization of our address tables. We have to put this code
877 // here because our labels are only in scope inside this function.
878 if (flag == InitializeAndReturn) {
879 #if HAVE(COMPUTED_GOTO)
880 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
881 FOR_EACH_OPCODE_ID(ADD_OPCODE);
884 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
885 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
887 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
888 op_throw_end_indirect = &&op_throw_end;
889 op_call_indirect = &&op_call;
890 #endif // HAVE(COMPUTED_GOTO)
894 JSValue* exceptionValue = 0;
895 Instruction* handlerVPC = 0;
897 Register** registerBase = registerFile->basePointer();
898 Instruction* vPC = codeBlock->instructions.begin();
899 JSValue** k = codeBlock->jsValues.data();
900 #if JAVASCRIPT_PROFILING
901 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
903 #if HAVE(COMPUTED_GOTO)
904 // Yet another hack around GCC's various foibles, in this case fetching the
905 // profiler reference results in a regression. Removing this indirection
906 // results in a 0.8% regression.
907 goto *(&&profilerFetchHack);
913 registerFile->setSafeForReentry(false);
914 #define VM_CHECK_EXCEPTION() \
916 if (UNLIKELY(exec->hadException())) { \
917 exceptionValue = exec->exception(); \
922 #if HAVE(COMPUTED_GOTO)
923 #define NEXT_OPCODE goto *vPC->u.opcode
924 #define BEGIN_OPCODE(opcode) opcode:
927 #define NEXT_OPCODE continue
928 #define BEGIN_OPCODE(opcode) case opcode:
929 while(1) // iterator loop begins
930 switch (vPC->u.opcode)
933 BEGIN_OPCODE(op_load) {
934 /* load dst(r) src(k)
936 Copies constant src to register dst.
938 int dst = (++vPC)->u.operand;
939 int src = (++vPC)->u.operand;
940 r[dst].u.jsValue = k[src];
945 BEGIN_OPCODE(op_new_object) {
948 Constructs a new empty Object instance using the original
949 constructor, and puts the result in register dst.
951 int dst = (++vPC)->u.operand;
952 r[dst].u.jsValue = scopeChain->globalObject()->objectConstructor()->construct(exec, exec->emptyList());
957 BEGIN_OPCODE(op_new_array) {
960 Constructs a new empty Array instance using the original
961 constructor, and puts the result in register dst.
963 int dst = (++vPC)->u.operand;
964 r[dst].u.jsValue = scopeChain->globalObject()->arrayConstructor()->construct(exec, exec->emptyList());
969 BEGIN_OPCODE(op_new_regexp) {
970 /* new_regexp dst(r) regExp(re)
972 Constructs a new RegExp instance using the original
973 constructor from regexp regExp, and puts the result in
976 int dst = (++vPC)->u.operand;
977 int regExp = (++vPC)->u.operand;
978 r[dst].u.jsValue = new RegExpImp(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
983 BEGIN_OPCODE(op_mov) {
986 Copies register src to register dst.
988 int dst = (++vPC)->u.operand;
989 int src = (++vPC)->u.operand;
995 BEGIN_OPCODE(op_eq) {
996 /* eq dst(r) src1(r) src2(r)
998 Checks whether register src1 and register src2 are equal,
999 as with the ECMAScript '==' operator, and puts the result
1000 as a boolean in register dst.
1002 int dst = (++vPC)->u.operand;
1003 int src1 = (++vPC)->u.operand;
1004 int src2 = (++vPC)->u.operand;
1005 JSValue* result = jsBoolean(equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1006 VM_CHECK_EXCEPTION();
1007 r[dst].u.jsValue = result;
1012 BEGIN_OPCODE(op_neq) {
1013 /* neq dst(r) src1(r) src2(r)
1015 Checks whether register src1 and register src2 are not
1016 equal, as with the ECMAScript '!=' operator, and puts the
1017 result as a boolean in register dst.
1019 int dst = (++vPC)->u.operand;
1020 int src1 = (++vPC)->u.operand;
1021 int src2 = (++vPC)->u.operand;
1022 JSValue* result = jsBoolean(!equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1023 VM_CHECK_EXCEPTION();
1024 r[dst].u.jsValue = result;
1029 BEGIN_OPCODE(op_stricteq) {
1030 /* stricteq dst(r) src1(r) src2(r)
1032 Checks whether register src1 and register src2 are strictly
1033 equal, as with the ECMAScript '===' operator, and puts the
1034 result as a boolean in register dst.
1036 int dst = (++vPC)->u.operand;
1037 int src1 = (++vPC)->u.operand;
1038 int src2 = (++vPC)->u.operand;
1039 r[dst].u.jsValue = jsBoolean(strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
1044 BEGIN_OPCODE(op_nstricteq) {
1045 /* nstricteq dst(r) src1(r) src2(r)
1047 Checks whether register src1 and register src2 are not
1048 strictly equal, as with the ECMAScript '!==' operator, and
1049 puts the result as a boolean in register dst.
1051 int dst = (++vPC)->u.operand;
1052 int src1 = (++vPC)->u.operand;
1053 int src2 = (++vPC)->u.operand;
1054 r[dst].u.jsValue = jsBoolean(!strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
1059 BEGIN_OPCODE(op_less) {
1060 /* less dst(r) src1(r) src2(r)
1062 Checks whether register src1 is less than register src2, as
1063 with the ECMAScript '<' operator, and puts the result as
1064 a boolean in register dst.
1066 int dst = (++vPC)->u.operand;
1067 int src1 = (++vPC)->u.operand;
1068 int src2 = (++vPC)->u.operand;
1069 JSValue* result = jsBoolean(jsLess(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1070 VM_CHECK_EXCEPTION();
1071 r[dst].u.jsValue = result;
1076 BEGIN_OPCODE(op_lesseq) {
1077 /* lesseq dst(r) src1(r) src2(r)
1079 Checks whether register src1 is less than or equal to
1080 register src2, as with the ECMAScript '<=' operator, and
1081 puts the result as a boolean in register dst.
1083 int dst = (++vPC)->u.operand;
1084 int src1 = (++vPC)->u.operand;
1085 int src2 = (++vPC)->u.operand;
1086 JSValue* result = jsBoolean(jsLessEq(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1087 VM_CHECK_EXCEPTION();
1088 r[dst].u.jsValue = result;
1093 BEGIN_OPCODE(op_pre_inc) {
1094 /* pre_inc srcDst(r)
1096 Converts register srcDst to number, adds one, and puts the result
1097 back in register srcDst.
1099 int srcDst = (++vPC)->u.operand;
1100 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) + 1);
1101 VM_CHECK_EXCEPTION();
1102 r[srcDst].u.jsValue = result;
1107 BEGIN_OPCODE(op_pre_dec) {
1108 /* pre_dec srcDst(r)
1110 Converts register srcDst to number, subtracts one, and puts the result
1111 back in register srcDst.
1113 int srcDst = (++vPC)->u.operand;
1114 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) - 1);
1115 VM_CHECK_EXCEPTION();
1116 r[srcDst].u.jsValue = result;
1121 BEGIN_OPCODE(op_post_inc) {
1122 /* post_inc dst(r) srcDst(r)
1124 Converts register srcDst to number. The number itself is
1125 written to register dst, and the number plus one is written
1126 back to register srcDst.
1128 int dst = (++vPC)->u.operand;
1129 int srcDst = (++vPC)->u.operand;
1130 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1131 VM_CHECK_EXCEPTION();
1133 r[dst].u.jsValue = number;
1134 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() + 1);
1139 BEGIN_OPCODE(op_post_dec) {
1140 /* post_dec dst(r) srcDst(r)
1142 Converts register srcDst to number. The number itself is
1143 written to register dst, and the number minus one is written
1144 back to register srcDst.
1146 int dst = (++vPC)->u.operand;
1147 int srcDst = (++vPC)->u.operand;
1148 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1149 VM_CHECK_EXCEPTION();
1151 r[dst].u.jsValue = number;
1152 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() - 1);
1157 BEGIN_OPCODE(op_to_jsnumber) {
1158 /* to_jsnumber dst(r) src(r)
1160 Converts register src to number, and puts the result
1163 int dst = (++vPC)->u.operand;
1164 int src = (++vPC)->u.operand;
1165 JSValue* result = r[src].u.jsValue->toJSNumber(exec);
1166 VM_CHECK_EXCEPTION();
1168 r[dst].u.jsValue = result;
1173 BEGIN_OPCODE(op_negate) {
1174 /* negate dst(r) src(r)
1176 Converts register src to number, negates it, and puts the
1177 result in register dst.
1179 int dst = (++vPC)->u.operand;
1180 int src = (++vPC)->u.operand;
1181 JSValue* result = jsNumber(-r[src].u.jsValue->toNumber(exec));
1182 VM_CHECK_EXCEPTION();
1183 r[dst].u.jsValue = result;
1188 BEGIN_OPCODE(op_add) {
1189 /* add dst(r) src1(r) src2(r)
1191 Adds register src1 and register src2, and puts the result
1192 in register dst. (JS add may be string concatenation or
1193 numeric add, depending on the types of the operands.)
1195 int dst = (++vPC)->u.operand;
1196 int src1 = (++vPC)->u.operand;
1197 int src2 = (++vPC)->u.operand;
1198 JSValue* result = jsAdd(exec, r[src1].u.jsValue, r[src2].u.jsValue);
1199 VM_CHECK_EXCEPTION();
1200 r[dst].u.jsValue = result;
1204 BEGIN_OPCODE(op_mul) {
1205 /* mul dst(r) src1(r) src2(r)
1207 Multiplies register src1 and register src2 (converted to
1208 numbers), and puts the product in register dst.
1210 int dst = (++vPC)->u.operand;
1211 int src1 = (++vPC)->u.operand;
1212 int src2 = (++vPC)->u.operand;
1213 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) * r[src2].u.jsValue->toNumber(exec));
1214 VM_CHECK_EXCEPTION();
1215 r[dst].u.jsValue = result;
1220 BEGIN_OPCODE(op_div) {
1221 /* div dst(r) dividend(r) divisor(r)
1223 Divides register dividend (converted to number) by the
1224 register divisor (converted to number), and puts the
1225 quotient in register dst.
1227 int dst = (++vPC)->u.operand;
1228 int dividend = (++vPC)->u.operand;
1229 int divisor = (++vPC)->u.operand;
1230 JSValue* result = jsNumber(r[dividend].u.jsValue->toNumber(exec) / r[divisor].u.jsValue->toNumber(exec));
1231 VM_CHECK_EXCEPTION();
1232 r[dst].u.jsValue = result;
1236 BEGIN_OPCODE(op_mod) {
1237 /* mod dst(r) dividend(r) divisor(r)
1239 Divides register dividend (converted to number) by
1240 register divisor (converted to number), and puts the
1241 remainder in register dst.
1243 int dst = (++vPC)->u.operand;
1244 int dividend = (++vPC)->u.operand;
1245 int divisor = (++vPC)->u.operand;
1246 double d = r[dividend].u.jsValue->toNumber(exec);
1247 JSValue* result = jsNumber(fmod(d, r[divisor].u.jsValue->toNumber(exec)));
1248 VM_CHECK_EXCEPTION();
1249 r[dst].u.jsValue = result;
1253 BEGIN_OPCODE(op_sub) {
1254 /* sub dst(r) src1(r) src2(r)
1256 Subtracts register src2 (converted to number) from register
1257 src1 (converted to number), and puts the difference in
1260 int dst = (++vPC)->u.operand;
1261 int src1 = (++vPC)->u.operand;
1262 int src2 = (++vPC)->u.operand;
1263 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) - r[src2].u.jsValue->toNumber(exec));
1264 VM_CHECK_EXCEPTION();
1265 r[dst].u.jsValue = result;
1269 BEGIN_OPCODE(op_lshift) {
1270 /* lshift dst(r) val(r) shift(r)
1272 Performs left shift of register val (converted to int32) by
1273 register shift (converted to uint32), and puts the result
1276 int dst = (++vPC)->u.operand;
1277 int val = (++vPC)->u.operand;
1278 int shift = (++vPC)->u.operand;
1279 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) << (r[shift].u.jsValue->toUInt32(exec)));
1280 VM_CHECK_EXCEPTION();
1281 r[dst].u.jsValue = result;
1286 BEGIN_OPCODE(op_rshift) {
1287 /* rshift dst(r) val(r) shift(r)
1289 Performs arithmetic right shift of register val (converted
1290 to int32) by register shift (converted to
1291 uint32), and puts the result in register dst.
1293 int dst = (++vPC)->u.operand;
1294 int val = (++vPC)->u.operand;
1295 int shift = (++vPC)->u.operand;
1296 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1297 VM_CHECK_EXCEPTION();
1298 r[dst].u.jsValue = result;
1303 BEGIN_OPCODE(op_urshift) {
1304 /* rshift dst(r) val(r) shift(r)
1306 Performs logical right shift of register val (converted
1307 to uint32) by register shift (converted to
1308 uint32), and puts the result in register dst.
1310 int dst = (++vPC)->u.operand;
1311 int val = (++vPC)->u.operand;
1312 int shift = (++vPC)->u.operand;
1313 JSValue* result = jsNumber((r[val].u.jsValue->toUInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1314 VM_CHECK_EXCEPTION();
1315 r[dst].u.jsValue = result;
1320 BEGIN_OPCODE(op_bitand) {
1321 /* bitand dst(r) src1(r) src2(r)
1323 Computes bitwise AND of register src1 (converted to int32)
1324 and register src2 (converted to int32), and puts the result
1327 int dst = (++vPC)->u.operand;
1328 int src1 = (++vPC)->u.operand;
1329 int src2 = (++vPC)->u.operand;
1330 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) & (r[src2].u.jsValue->toInt32(exec)));
1331 VM_CHECK_EXCEPTION();
1332 r[dst].u.jsValue = result;
1337 BEGIN_OPCODE(op_bitxor) {
1338 /* bitxor dst(r) src1(r) src2(r)
1340 Computes bitwise XOR of register src1 (converted to int32)
1341 and register src2 (converted to int32), and puts the result
1344 int dst = (++vPC)->u.operand;
1345 int src1 = (++vPC)->u.operand;
1346 int src2 = (++vPC)->u.operand;
1347 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) ^ (r[src2].u.jsValue->toInt32(exec)));
1348 VM_CHECK_EXCEPTION();
1349 r[dst].u.jsValue = result;
1354 BEGIN_OPCODE(op_bitor) {
1355 /* bitor dst(r) src1(r) src2(r)
1357 Computes bitwise OR of register src1 (converted to int32)
1358 and register src2 (converted to int32), and puts the
1359 result in register dst.
1361 int dst = (++vPC)->u.operand;
1362 int src1 = (++vPC)->u.operand;
1363 int src2 = (++vPC)->u.operand;
1364 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) | (r[src2].u.jsValue->toInt32(exec)));
1365 VM_CHECK_EXCEPTION();
1366 r[dst].u.jsValue = result;
1371 BEGIN_OPCODE(op_bitnot) {
1372 /* bitnot dst(r) src(r)
1374 Computes bitwise NOT of register src1 (converted to int32),
1375 and puts the result in register dst.
1377 int dst = (++vPC)->u.operand;
1378 int src = (++vPC)->u.operand;
1379 JSValue* result = jsNumber(~r[src].u.jsValue->toInt32(exec));
1380 VM_CHECK_EXCEPTION();
1381 r[dst].u.jsValue = result;
1386 BEGIN_OPCODE(op_not) {
1387 /* not dst(r) src1(r) src2(r)
1389 Computes logical NOT of register src1 (converted to
1390 boolean), and puts the result in register dst.
1392 int dst = (++vPC)->u.operand;
1393 int src = (++vPC)->u.operand;
1394 JSValue* result = jsBoolean(!r[src].u.jsValue->toBoolean(exec));
1395 VM_CHECK_EXCEPTION();
1396 r[dst].u.jsValue = result;
1401 BEGIN_OPCODE(op_instanceof) {
1402 /* instanceof dst(r) value(r) constructor(r)
1404 Tests whether register value is an instance of register
1405 constructor, and puts the boolean result in register dst.
1407 Raises an exception if register constructor is not an
1410 int dst = (++vPC)->u.operand;
1411 int value = (++vPC)->u.operand;
1412 int base = (++vPC)->u.operand;
1414 JSValue* baseVal = r[base].u.jsValue;
1416 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1419 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1420 r[dst].u.jsValue = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].u.jsValue) : false);
1425 BEGIN_OPCODE(op_typeof) {
1426 /* typeof dst(r) src(r)
1428 Determines the type string for src according to ECMAScript
1429 rules, and puts the result in register dst.
1431 int dst = (++vPC)->u.operand;
1432 int src = (++vPC)->u.operand;
1433 r[dst].u.jsValue = jsTypeStringForValue(r[src].u.jsValue);
1438 BEGIN_OPCODE(op_in) {
1439 /* in dst(r) property(r) base(r)
1441 Tests whether register base has a property named register
1442 property, and puts the boolean result in register dst.
1444 Raises an exception if register constructor is not an
1447 int dst = (++vPC)->u.operand;
1448 int property = (++vPC)->u.operand;
1449 int base = (++vPC)->u.operand;
1451 JSValue* baseVal = r[base].u.jsValue;
1452 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1455 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1457 JSValue* propName = r[property].u.jsValue;
1460 if (propName->getUInt32(i))
1461 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, i));
1463 Identifier property(propName->toString(exec));
1464 VM_CHECK_EXCEPTION();
1465 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, property));
1471 BEGIN_OPCODE(op_resolve) {
1472 /* resolve dst(r) property(id)
1474 Looks up the property named by identifier property in the
1475 scope chain, and writes the resulting value to register
1476 dst. If the property is not found, raises an exception.
1478 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1484 BEGIN_OPCODE(op_resolve_skip) {
1485 /* resolve_skip dst(r) property(id) skip(n)
1487 Looks up the property named by identifier property in the
1488 scope chain skipping the top 'skip' levels, and writes the resulting
1489 value to register dst. If the property is not found, raises an exception.
1491 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1498 BEGIN_OPCODE(op_get_scoped_var) {
1499 /* get_scoped_var dst(r) index(n) skip(n)
1501 Loads the contents of the index-th local from the scope skip nodes from
1502 the top of the scope chain, and places it in register dst
1504 int dst = (++vPC)->u.operand;
1505 int index = (++vPC)->u.operand;
1506 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
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 r[dst].u.jsValue = scope->valueAt(index);
1522 BEGIN_OPCODE(op_put_scoped_var) {
1523 /* put_scoped_var index(n) skip(n) value(r)
1526 int index = (++vPC)->u.operand;
1527 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1528 int value = (++vPC)->u.operand;
1530 ScopeChainIterator iter = scopeChain->begin();
1531 ScopeChainIterator end = scopeChain->end();
1532 ASSERT(iter != end);
1535 ASSERT(iter != end);
1538 ASSERT((*iter)->isVariableObject());
1539 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1540 scope->valueAt(index) = r[value].u.jsValue;
1544 BEGIN_OPCODE(op_resolve_base) {
1545 /* resolve_base dst(r) property(id)
1547 Searches the scope chain for an object containing
1548 identifier property, and if one is found, writes it to
1549 register dst. If none is found, the outermost scope (which
1550 will be the global object) is stored in register dst.
1552 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1557 BEGIN_OPCODE(op_resolve_with_base) {
1558 /* resolve_with_base baseDst(r) propDst(r) property(id)
1560 Searches the scope chain for an object containing
1561 identifier property, and if one is found, writes it to
1562 register srcDst, and the retrieved property value to register
1563 propDst. If the property is not found, raises an exception.
1565 This is more efficient than doing resolve_base followed by
1566 resolve, or resolve_base followed by get_by_id, as it
1567 avoids duplicate hash lookups.
1569 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1575 BEGIN_OPCODE(op_resolve_func) {
1576 /* resolve_func baseDst(r) funcDst(r) property(id)
1578 Searches the scope chain for an object containing
1579 identifier property, and if one is found, writes the
1580 appropriate object to use as "this" when calling its
1581 properties to register baseDst; and the retrieved property
1582 value to register propDst. If the property is not found,
1583 raises an exception.
1585 This differs from resolve_with_base, because the
1586 global this value will be substituted for activations or
1587 the global object, which is the right behavior for function
1588 calls but not for other property lookup.
1590 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1596 BEGIN_OPCODE(op_get_by_id) {
1597 /* get_by_id dst(r) base(r) property(id)
1599 Converts register base to Object, gets the property
1600 named by identifier property from the object, and puts the
1601 result in register dst.
1603 int dst = (++vPC)->u.operand;
1604 int base = (++vPC)->u.operand;
1605 int property = (++vPC)->u.operand;
1607 int registerOffset = r - (*registerBase);
1609 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1611 Identifier& ident = codeBlock->identifiers[property];
1612 JSValue *result = baseObj->get(exec, ident);
1613 ASSERT(registerOffset == (r - (*registerBase)));
1614 VM_CHECK_EXCEPTION();
1615 r[dst].u.jsValue = result;
1619 BEGIN_OPCODE(op_put_by_id) {
1620 /* put_by_id base(r) property(id) value(r)
1622 Sets register value on register base as the property named
1623 by identifier property. Base is converted to object first.
1625 Unlike many opcodes, this one does not write any output to
1628 int base = (++vPC)->u.operand;
1629 int property = (++vPC)->u.operand;
1630 int value = (++vPC)->u.operand;
1632 int registerOffset = r - (*registerBase);
1635 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1637 Identifier& ident = codeBlock->identifiers[property];
1638 baseObj->put(exec, ident, r[value].u.jsValue);
1639 ASSERT(registerOffset == (r - (*registerBase)));
1641 VM_CHECK_EXCEPTION();
1645 BEGIN_OPCODE(op_del_by_id) {
1646 /* del_by_id dst(r) base(r) property(id)
1648 Converts register base to Object, deletes the property
1649 named by identifier property from the object, and writes a
1650 boolean indicating success (if true) or failure (if false)
1653 int dst = (++vPC)->u.operand;
1654 int base = (++vPC)->u.operand;
1655 int property = (++vPC)->u.operand;
1657 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1659 Identifier& ident = codeBlock->identifiers[property];
1660 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1661 VM_CHECK_EXCEPTION();
1662 r[dst].u.jsValue = result;
1666 BEGIN_OPCODE(op_get_by_val) {
1667 /* get_by_val dst(r) base(r) property(r)
1669 Converts register base to Object, gets the property named
1670 by register property from the object, and puts the result
1671 in register dst. property is nominally converted to string
1672 but numbers are treated more efficiently.
1674 int dst = (++vPC)->u.operand;
1675 int base = (++vPC)->u.operand;
1676 int property = (++vPC)->u.operand;
1678 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1680 JSValue* subscript = r[property].u.jsValue;
1683 if (subscript->getUInt32(i))
1684 result = baseObj->get(exec, i);
1686 Identifier property;
1687 if (subscript->isObject()) {
1688 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1689 property = Identifier(subscript->toString(exec));
1691 property = Identifier(subscript->toString(exec));
1693 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a getter after an exception is thrown
1694 result = baseObj->get(exec, property);
1697 VM_CHECK_EXCEPTION();
1698 r[dst].u.jsValue = result;
1702 BEGIN_OPCODE(op_put_by_val) {
1703 /* put_by_val base(r) property(r) value(r)
1705 Sets register value on register base as the property named
1706 by register property. Base is converted to object
1707 first. register property is nominally converted to string
1708 but numbers are treated more efficiently.
1710 Unlike many opcodes, this one does not write any output to
1713 int base = (++vPC)->u.operand;
1714 int property = (++vPC)->u.operand;
1715 int value = (++vPC)->u.operand;
1717 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1719 JSValue* subscript = r[property].u.jsValue;
1722 if (subscript->getUInt32(i))
1723 baseObj->put(exec, i, r[value].u.jsValue);
1725 Identifier property;
1726 if (subscript->isObject()) {
1727 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1728 property = Identifier(subscript->toString(exec));
1730 property = Identifier(subscript->toString(exec));
1732 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a setter after an exception is thrown
1733 baseObj->put(exec, property, r[value].u.jsValue);
1736 VM_CHECK_EXCEPTION();
1740 BEGIN_OPCODE(op_del_by_val) {
1741 /* del_by_val dst(r) base(r) property(r)
1743 Converts register base to Object, deletes the property
1744 named by register property from the object, and writes a
1745 boolean indicating success (if true) or failure (if false)
1748 int dst = (++vPC)->u.operand;
1749 int base = (++vPC)->u.operand;
1750 int property = (++vPC)->u.operand;
1752 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1754 JSValue* subscript = r[property].u.jsValue;
1757 if (subscript->getUInt32(i))
1758 result = jsBoolean(baseObj->deleteProperty(exec, i));
1760 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1761 Identifier property(subscript->toString(exec));
1762 VM_CHECK_EXCEPTION();
1763 result = jsBoolean(baseObj->deleteProperty(exec, property));
1766 VM_CHECK_EXCEPTION();
1767 r[dst].u.jsValue = result;
1771 BEGIN_OPCODE(op_put_by_index) {
1772 /* put_by_index base(r) property(n) value(r)
1774 Sets register value on register base as the property named
1775 by the immediate number property. Base is converted to
1776 object first. register property is nominally converted to
1777 string but numbers are treated more efficiently.
1779 Unlike many opcodes, this one does not write any output to
1782 This opcode is mainly used to initialize array literals.
1784 int base = (++vPC)->u.operand;
1785 unsigned property = (++vPC)->u.operand;
1786 int value = (++vPC)->u.operand;
1788 r[base].u.jsObject->put(exec, property, r[value].u.jsValue);
1793 BEGIN_OPCODE(op_jmp) {
1794 /* jmp target(offset)
1796 Jumps unconditionally to offset target from the current
1799 int target = (++vPC)->u.operand;
1804 BEGIN_OPCODE(op_jtrue) {
1805 /* jtrue cond(r) target(offset)
1807 Jumps to offset target from the current instruction, if and
1808 only if register cond converts to boolean as true.
1810 int cond = (++vPC)->u.operand;
1811 int target = (++vPC)->u.operand;
1812 if (r[cond].u.jsValue->toBoolean(exec)) {
1820 BEGIN_OPCODE(op_jfalse) {
1821 /* jfalse cond(r) target(offset)
1823 Jumps to offset target from the current instruction, if and
1824 only if register cond converts to boolean as false.
1826 int cond = (++vPC)->u.operand;
1827 int target = (++vPC)->u.operand;
1828 if (!r[cond].u.jsValue->toBoolean(exec)) {
1836 BEGIN_OPCODE(op_new_func) {
1837 /* new_func dst(r) func(f)
1839 Constructs a new Function instance from function func and
1840 the current scope chain using the original Function
1841 constructor, using the rules for function declarations, and
1842 puts the result in register dst.
1844 int dst = (++vPC)->u.operand;
1845 int func = (++vPC)->u.operand;
1847 r[dst].u.jsValue = codeBlock->functions[func]->makeFunction(exec, scopeChain);
1852 BEGIN_OPCODE(op_new_func_exp) {
1853 /* new_func_exp dst(r) func(f)
1855 Constructs a new Function instance from function func and
1856 the current scope chain using the original Function
1857 constructor, using the rules for function expressions, and
1858 puts the result in register dst.
1860 int dst = (++vPC)->u.operand;
1861 int func = (++vPC)->u.operand;
1863 r[dst].u.jsValue = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
1868 BEGIN_OPCODE(op_call_eval) {
1869 int dst = (++vPC)->u.operand;
1870 int func = (++vPC)->u.operand;
1871 int base = (++vPC)->u.operand;
1872 int argv = (++vPC)->u.operand;
1873 int argc = (++vPC)->u.operand;
1875 JSValue* funcVal = r[func].u.jsValue;
1876 JSValue* baseVal = r[base].u.jsValue;
1878 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
1879 int registerOffset = r - (*registerBase);
1881 JSObject* thisObject = r[codeBlock->thisRegister].u.jsObject;
1883 registerFile->setSafeForReentry(true);
1885 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, argv, argc, exceptionValue);
1887 registerFile->setSafeForReentry(false);
1888 r = (*registerBase) + registerOffset;
1893 r[dst].u.jsValue = result;
1899 // We didn't find the blessed version of eval, so reset vPC and process
1900 // this instruction as a normal function call, supplying the proper 'this'
1903 r[base].u.jsValue = baseVal->toObject(exec)->toThisObject(exec);
1905 #if HAVE(COMPUTED_GOTO)
1906 // Hack around gcc performance quirk by performing an indirect goto
1907 // in order to set the vPC -- attempting to do so directly results in a
1908 // significant regression.
1909 goto *op_call_indirect; // indirect goto -> op_call
1911 // fall through to op_call
1913 BEGIN_OPCODE(op_call) {
1914 int dst = (++vPC)->u.operand;
1915 int func = (++vPC)->u.operand;
1916 int base = (++vPC)->u.operand;
1917 int argv = (++vPC)->u.operand;
1918 int argc = (++vPC)->u.operand;
1920 JSValue* v = r[func].u.jsValue;
1923 CallType callType = v->getCallData(callData);
1925 if (callType == CallTypeJS) {
1926 #if JAVASCRIPT_PROFILING
1927 if (*enabledProfilerReference)
1928 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
1930 int registerOffset = r - (*registerBase);
1931 Register* callFrame = r + argv - CallFrameHeaderSize;
1932 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
1934 r[argv].u.jsValue = base == missingThisObjectMarker() ? exec->globalThisValue() : r[base].u.jsValue; // "this" value
1935 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, dst, argv, argc, 0, v);
1937 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
1938 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
1940 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
1941 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
1942 if (UNLIKELY(exceptionValue != 0))
1945 codeBlock = newCodeBlock;
1946 exec->m_callFrameOffset = callFrameOffset;
1947 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
1948 k = codeBlock->jsValues.data();
1949 vPC = codeBlock->instructions.begin();
1954 if (callType == CallTypeNative) {
1955 #if JAVASCRIPT_PROFILING
1956 if (*enabledProfilerReference)
1957 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
1959 int registerOffset = r - (*registerBase);
1961 r[argv].u.jsValue = base == missingThisObjectMarker() ? exec->globalThisValue() : (r[base].u.jsValue)->toObject(exec); // "this" value
1962 JSObject* thisObj = static_cast<JSObject*>(r[argv].u.jsValue);
1964 List args(&r[argv + 1].u.jsValue, argc - 1);
1966 registerFile->setSafeForReentry(true);
1967 JSValue* returnValue = static_cast<JSObject*>(v)->callAsFunction(exec, thisObj, args);
1968 registerFile->setSafeForReentry(false);
1970 r = (*registerBase) + registerOffset;
1971 r[dst].u.jsValue = returnValue;
1973 #if JAVASCRIPT_PROFILING
1974 if (*enabledProfilerReference)
1975 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
1977 VM_CHECK_EXCEPTION();
1983 ASSERT(callType == CallTypeNone);
1985 exceptionValue = createNotAFunctionError(exec, v, 0);
1988 BEGIN_OPCODE(op_ret) {
1989 int r1 = (++vPC)->u.operand;
1991 CodeBlock* oldCodeBlock = codeBlock;
1993 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
1994 JSValue* returnValue = r[r1].u.jsValue;
1996 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
1997 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
1998 ASSERT(activation->isActivationObject());
1999 activation->copyRegisters();
2002 if (codeBlock->needsFullScopeChain)
2003 scopeChain->deref();
2005 if (callFrame[CalledAsConstructor].u.i && !returnValue->isObject()) {
2006 JSValue* thisObject = callFrame[CallFrameHeaderSize].u.jsValue;
2007 returnValue = thisObject;
2010 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
2014 k = codeBlock->jsValues.data();
2015 vPC = callFrame[ReturnVPC].u.vPC;
2016 setScopeChain(exec, scopeChain, callFrame[CallerScopeChain].u.scopeChain);
2017 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
2018 r = (*registerBase) + callerRegisterOffset;
2019 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
2020 int r0 = callFrame[ReturnValueRegister].u.i;
2021 r[r0].u.jsValue = returnValue;
2023 #if JAVASCRIPT_PROFILING
2024 if (*enabledProfilerReference)
2025 (*enabledProfilerReference)->didExecute(exec, callFrame[Callee].u.jsObject);
2029 BEGIN_OPCODE(op_construct) {
2030 int dst = (++vPC)->u.operand;
2031 int func = (++vPC)->u.operand;
2032 int argv = (++vPC)->u.operand;
2033 int argc = (++vPC)->u.operand;
2035 JSValue* funcVal = r[func].u.jsValue;
2037 ConstructData constructData;
2038 ConstructType constructType = funcVal->getConstructData(constructData);
2040 // Removing this line of code causes a measurable regression on squirrelfish.
2041 JSObject* constructor = static_cast<JSObject*>(funcVal);
2043 if (constructType == ConstructTypeJS) {
2044 #if JAVASCRIPT_PROFILING
2045 if (*enabledProfilerReference)
2046 (*enabledProfilerReference)->willExecute(exec, constructor);
2048 int registerOffset = r - (*registerBase);
2049 Register* callFrame = r + argv - CallFrameHeaderSize;
2050 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
2052 JSObject* prototype;
2053 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
2055 prototype = static_cast<JSObject*>(p);
2057 prototype = scopeChain->globalObject()->objectPrototype();
2058 JSObject* newObject = new JSObject(prototype);
2059 r[argv].u.jsValue = newObject; // "this" value
2061 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, dst, argv, argc, 1, constructor);
2063 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
2064 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
2066 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
2067 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
2071 codeBlock = newCodeBlock;
2072 exec->m_callFrameOffset = callFrameOffset;
2073 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
2074 k = codeBlock->jsValues.data();
2075 vPC = codeBlock->instructions.begin();
2080 if (constructType == ConstructTypeNative) {
2081 #if JAVASCRIPT_PROFILING
2082 if (*enabledProfilerReference)
2083 (*enabledProfilerReference)->willExecute(exec, constructor);
2085 int registerOffset = r - (*registerBase);
2087 List args(&r[argv + 1].u.jsValue, argc - 1);
2088 registerFile->setSafeForReentry(true);
2089 JSValue* returnValue = constructor->construct(exec, args);
2090 registerFile->setSafeForReentry(false);
2092 r = (*registerBase) + registerOffset;
2093 VM_CHECK_EXCEPTION();
2094 r[dst].u.jsValue = returnValue;
2096 #if JAVASCRIPT_PROFILING
2097 if (*enabledProfilerReference)
2098 (*enabledProfilerReference)->didExecute(exec, constructor);
2104 ASSERT(constructType == ConstructTypeNone);
2106 exceptionValue = createNotAConstructorError(exec, funcVal, 0);
2109 BEGIN_OPCODE(op_push_scope) {
2110 /* push_scope scope(r)
2112 Converts register scope to object, and pushes it onto the top
2113 of the current scope chain.
2115 int scope = (++vPC)->u.operand;
2116 JSValue* v = r[scope].u.jsValue;
2117 JSObject* o = v->toObject(exec);
2118 VM_CHECK_EXCEPTION();
2120 setScopeChain(exec, scopeChain, scopeChain->push(o));
2125 BEGIN_OPCODE(op_pop_scope) {
2128 Removes the top item from the current scope chain.
2130 setScopeChain(exec, scopeChain, scopeChain->pop());
2135 BEGIN_OPCODE(op_get_pnames) {
2136 /* get_pnames dst(r) base(r)
2138 Creates a property name list for register base and puts it
2139 in register dst. This is not a true JavaScript value, just
2140 a synthetic value used to keep the iteration state in a
2143 int dst = (++vPC)->u.operand;
2144 int base = (++vPC)->u.operand;
2146 r[dst].u.jsPropertyNameIterator = JSPropertyNameIterator::create(exec, r[base].u.jsValue);
2150 BEGIN_OPCODE(op_next_pname) {
2151 /* next_pname dst(r) iter(r) target(offset)
2153 Tries to copies the next name from property name list in
2154 register iter. If there are names left, then copies one to
2155 register dst, and jumps to offset target. If there are none
2156 left, invalidates the iterator and continues to the next
2159 int dst = (++vPC)->u.operand;
2160 int iter = (++vPC)->u.operand;
2161 int target = (++vPC)->u.operand;
2163 JSPropertyNameIterator* it = r[iter].u.jsPropertyNameIterator;
2164 if (JSValue* temp = it->next(exec)) {
2165 r[dst].u.jsValue = temp;
2174 BEGIN_OPCODE(op_jmp_scopes) {
2175 /* jmp_scopes count(n) target(offset)
2177 Removes the a number of items from the current scope chain
2178 specified by immediate number count, then jumps to offset
2181 int count = (++vPC)->u.operand;
2182 int target = (++vPC)->u.operand;
2184 ScopeChainNode* tmp = scopeChain;
2187 setScopeChain(exec, scopeChain, tmp);
2192 BEGIN_OPCODE(op_catch) {
2193 ASSERT(exceptionValue);
2194 ASSERT(!exec->hadException());
2195 int r0 = (++vPC)->u.operand;
2196 r[r0].u.jsValue = exceptionValue;
2201 BEGIN_OPCODE(op_throw) {
2202 int e = (++vPC)->u.operand;
2203 exceptionValue = r[e].u.jsValue;
2204 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2206 *exception = exceptionValue;
2210 #if HAVE(COMPUTED_GOTO)
2211 // Hack around gcc performance quirk by performing an indirect goto
2212 // in order to set the vPC -- attempting to do so directly results in a
2213 // significant regression.
2214 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2222 BEGIN_OPCODE(op_new_error) {
2223 /* new_error dst(r) type(n) message(k)
2225 Constructs a new Error instance using the original
2226 constructor, using immediate number n as the type and
2227 constant message as the message string. The result is
2228 written to register dst.
2230 int dst = (++vPC)->u.operand;
2231 int type = (++vPC)->u.operand;
2232 int message = (++vPC)->u.operand;
2234 r[dst].u.jsValue = Error::create(exec, (ErrorType)type, k[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2239 BEGIN_OPCODE(op_end) {
2240 if (codeBlock->needsFullScopeChain) {
2241 ASSERT(scopeChain->refCount > 1);
2242 scopeChain->deref();
2244 int r0 = (++vPC)->u.operand;
2245 return r[r0].u.jsValue;
2247 BEGIN_OPCODE(op_put_getter) {
2248 /* put_getter base(r) property(id) function(r)
2250 Sets register function on register base as the getter named
2251 by identifier property. Base and function are assumed to be
2252 objects as this op should only be used for getters defined
2253 in object literal form.
2255 Unlike many opcodes, this one does not write any output to
2258 int base = (++vPC)->u.operand;
2259 int property = (++vPC)->u.operand;
2260 int function = (++vPC)->u.operand;
2262 ASSERT(r[base].u.jsValue->isObject());
2263 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2264 Identifier& ident = codeBlock->identifiers[property];
2265 ASSERT(r[function].u.jsValue->isObject());
2266 baseObj->defineGetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2271 BEGIN_OPCODE(op_put_setter) {
2272 /* put_setter base(r) property(id) function(r)
2274 Sets register function on register base as the setter named
2275 by identifier property. Base and function are assumed to be
2276 objects as this op should only be used for setters defined
2277 in object literal form.
2279 Unlike many opcodes, this one does not write any output to
2282 int base = (++vPC)->u.operand;
2283 int property = (++vPC)->u.operand;
2284 int function = (++vPC)->u.operand;
2286 ASSERT(r[base].u.jsValue->isObject());
2287 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2288 Identifier& ident = codeBlock->identifiers[property];
2289 ASSERT(r[function].u.jsValue->isObject());
2290 baseObj->defineSetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2295 BEGIN_OPCODE(op_jsr) {
2296 /* jsr retAddrDst(r) target(offset)
2298 Places the address of the next instruction into the retAddrDst
2299 register and jumps to offset target from the current instruction.
2301 int retAddrDst = (++vPC)->u.operand;
2302 int target = (++vPC)->u.operand;
2303 r[retAddrDst].u.vPC = vPC + 1;
2308 BEGIN_OPCODE(op_sret) {
2309 /* sret retAddrSrc(r)
2311 Jumps to the address stored in the retAddrSrc register. This
2312 differs from op_jmp because the target address is stored in a
2313 register, not as an immediate.
2315 int retAddrSrc = (++vPC)->u.operand;
2316 vPC = r[retAddrSrc].u.vPC;
2319 BEGIN_OPCODE(op_debug) {
2320 /* debug debugHookID(n) firstLine(n) lastLine(n)
2322 Notifies the debugger of the current state of execution:
2323 didEnterCallFrame; willLeaveCallFrame; or willExecuteStatement.
2325 This opcode is only generated while the debugger is attached.
2328 int registerOffset = r - (*registerBase);
2329 registerFile->setSafeForReentry(true);
2330 debug(exec, vPC, codeBlock, scopeChain, registerBase, r);
2331 registerFile->setSafeForReentry(false);
2332 r = (*registerBase) + registerOffset;
2338 exec->clearException();
2339 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2341 *exception = exceptionValue;
2350 #undef VM_CHECK_EXCEPTION
2353 JSValue* Machine::retrieveArguments(ExecState* exec, FunctionImp* function) const
2355 Register** registerBase;
2356 int callFrameOffset;
2358 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2361 Register* callFrame = (*registerBase) + callFrameOffset;
2362 JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue);
2364 CodeBlock* codeBlock = &function->body->generatedCode();
2365 activation = new JSActivation(function->body, registerBase, callFrameOffset + CallFrameHeaderSize + codeBlock->numLocals);
2366 callFrame[OptionalCalleeActivation].u.jsValue = activation;
2369 return activation->get(exec, exec->propertyNames().arguments);
2372 JSValue* Machine::retrieveCaller(ExecState* exec, FunctionImp* function) const
2374 Register** registerBase;
2375 int callFrameOffset;
2377 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2380 int callerFrameOffset;
2381 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callerFrameOffset))
2384 Register* callerFrame = (*registerBase) + callerFrameOffset;
2385 ASSERT(callerFrame[Callee].u.jsValue);
2386 return callerFrame[Callee].u.jsValue;
2389 bool Machine::getCallFrame(ExecState* exec, FunctionImp* function, Register**& registerBase, int& callFrameOffset) const
2391 callFrameOffset = exec->m_callFrameOffset;
2394 while (callFrameOffset < 0) {
2395 exec = exec->m_prev;
2398 callFrameOffset = exec->m_callFrameOffset;
2401 registerBase = exec->m_registerFile->basePointer();
2402 Register* callFrame = (*registerBase) + callFrameOffset;
2403 if (callFrame[Callee].u.jsValue == function)
2406 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callFrameOffset))
2407 callFrameOffset = -1;
2411 void Machine::getFunctionAndArguments(Register** registerBase, Register* callFrame, FunctionImp*& function, Register*& argv, int& argc)
2413 function = static_cast<FunctionImp*>(callFrame[Callee].u.jsValue);
2414 ASSERT(function->inherits(&FunctionImp::info));
2416 argv = (*registerBase) + callFrame[CallerRegisterOffset].u.i + callFrame[ArgumentStartRegister].u.i + 1; // skip "this"
2417 argc = callFrame[ArgumentCount].u.i - 1; // skip "this"