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 "Arguments.h"
34 #include "BatchedTransitionOptimizer.h"
35 #include "CodeBlock.h"
36 #include "DebuggerCallFrame.h"
37 #include "ExceptionHelpers.h"
38 #include "ExecState.h"
39 #include "GlobalEvalFunction.h"
40 #include "JSActivation.h"
42 #include "JSFunction.h"
43 #include "JSNotAnObject.h"
44 #include "JSPropertyNameIterator.h"
45 #include "JSStaticScopeObject.h"
47 #include "ObjectPrototype.h"
50 #include "RegExpObject.h"
51 #include "RegExpPrototype.h"
53 #include "collector.h"
55 #include "operations.h"
56 #include "SamplingTool.h"
64 #include <mach/mach.h>
83 // Preferred number of milliseconds between each timeout check
84 static const int preferredScriptCheckTimeInterval = 1000;
86 #if HAVE(COMPUTED_GOTO)
87 static void* op_throw_end_indirect;
88 static void* op_call_indirect;
93 static ALWAYS_INLINE Instruction* vPCForPC(CodeBlock* codeBlock, void* pc)
95 if (pc >= codeBlock->instructions.begin() && pc < codeBlock->instructions.end())
96 return static_cast<Instruction*>(pc);
98 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(pc));
99 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(pc);
100 return codeBlock->instructions.begin() + vPCIndex;
105 static ALWAYS_INLINE Instruction* vPCForPC(CodeBlock*, void* pc)
107 return static_cast<Instruction*>(pc);
110 #endif // ENABLE(CTI)
112 // Returns the depth of the scope chain within a given call frame.
113 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
115 if (!codeBlock->needsFullScopeChain)
118 ScopeChainIterator iter = sc.begin();
119 ScopeChainIterator end = sc.end();
120 while (!(*iter)->isObject(&JSActivation::info)) {
129 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
130 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
131 static ALWAYS_INLINE bool fastIsNumber(JSValuePtr value, double& arg)
133 if (JSImmediate::isNumber(value))
134 arg = JSImmediate::getTruncatedInt32(value);
135 else if (LIKELY(!JSImmediate::isImmediate(value)) && LIKELY(Heap::isNumber(asCell(value))))
136 arg = asNumberCell(value)->value();
142 // FIXME: Why doesn't JSValuePtr::toInt32 have the Heap::isNumber optimization?
143 static bool fastToInt32(JSValuePtr value, int32_t& arg)
145 if (JSImmediate::isNumber(value))
146 arg = JSImmediate::getTruncatedInt32(value);
147 else if (LIKELY(!JSImmediate::isImmediate(value)) && LIKELY(Heap::isNumber(asCell(value))))
148 arg = asNumberCell(value)->toInt32();
154 static ALWAYS_INLINE bool fastToUInt32(JSValuePtr value, uint32_t& arg)
156 if (JSImmediate::isNumber(value)) {
157 if (JSImmediate::getTruncatedUInt32(value, arg))
160 arg = toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
162 } else if (!JSImmediate::isImmediate(value) && Heap::isNumber(asCell(value)))
163 arg = asNumberCell(value)->toUInt32();
169 static inline bool jsLess(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2)
171 if (JSImmediate::areBothImmediateNumbers(v1, v2))
172 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
176 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
179 Machine* machine = callFrame->machine();
180 if (machine->isJSString(v1) && machine->isJSString(v2))
181 return asString(v1)->value() < asString(v2)->value();
185 bool wasNotString1 = v1->getPrimitiveNumber(callFrame, n1, p1);
186 bool wasNotString2 = v2->getPrimitiveNumber(callFrame, n2, p2);
188 if (wasNotString1 | wasNotString2)
191 return asString(p1)->value() < asString(p2)->value();
194 static inline bool jsLessEq(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2)
196 if (JSImmediate::areBothImmediateNumbers(v1, v2))
197 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
201 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
204 Machine* machine = callFrame->machine();
205 if (machine->isJSString(v1) && machine->isJSString(v2))
206 return !(asString(v2)->value() < asString(v1)->value());
210 bool wasNotString1 = v1->getPrimitiveNumber(callFrame, n1, p1);
211 bool wasNotString2 = v2->getPrimitiveNumber(callFrame, n2, p2);
213 if (wasNotString1 | wasNotString2)
216 return !(asString(p2)->value() < asString(p1)->value());
219 static NEVER_INLINE JSValuePtr jsAddSlowCase(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2)
221 // exception for the Date exception in defaultValue()
222 JSValuePtr p1 = v1->toPrimitive(callFrame);
223 JSValuePtr p2 = v2->toPrimitive(callFrame);
225 if (p1->isString() || p2->isString()) {
226 RefPtr<UString::Rep> value = concatenate(p1->toString(callFrame).rep(), p2->toString(callFrame).rep());
228 return throwOutOfMemoryError(callFrame);
229 return jsString(callFrame, value.release());
232 return jsNumber(callFrame, p1->toNumber(callFrame) + p2->toNumber(callFrame));
235 // Fast-path choices here are based on frequency data from SunSpider:
236 // <times> Add case: <t1> <t2>
237 // ---------------------------
238 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
239 // 247412 Add case: 5 5
240 // 20900 Add case: 5 6
241 // 13962 Add case: 5 3
242 // 4000 Add case: 3 5
244 static ALWAYS_INLINE JSValuePtr jsAdd(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2)
249 bool rightIsNumber = fastIsNumber(v2, right);
250 if (rightIsNumber && fastIsNumber(v1, left))
251 return jsNumber(callFrame, left + right);
253 bool leftIsString = v1->isString();
254 if (leftIsString && v2->isString()) {
255 RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep());
257 return throwOutOfMemoryError(callFrame);
258 return jsString(callFrame, value.release());
261 if (rightIsNumber & leftIsString) {
262 RefPtr<UString::Rep> value = JSImmediate::isImmediate(v2) ?
263 concatenate(asString(v1)->value().rep(), JSImmediate::getTruncatedInt32(v2)) :
264 concatenate(asString(v1)->value().rep(), right);
267 return throwOutOfMemoryError(callFrame);
268 return jsString(callFrame, value.release());
271 // All other cases are pretty uncommon
272 return jsAddSlowCase(callFrame, v1, v2);
275 static JSValuePtr jsTypeStringForValue(CallFrame* callFrame, JSValuePtr v)
277 if (v->isUndefined())
278 return jsNontrivialString(callFrame, "undefined");
280 return jsNontrivialString(callFrame, "boolean");
282 return jsNontrivialString(callFrame, "number");
284 return jsNontrivialString(callFrame, "string");
286 // Return "undefined" for objects that should be treated
287 // as null when doing comparisons.
288 if (asObject(v)->structureID()->typeInfo().masqueradesAsUndefined())
289 return jsNontrivialString(callFrame, "undefined");
291 if (asObject(v)->getCallData(callData) != CallTypeNone)
292 return jsNontrivialString(callFrame, "function");
294 return jsNontrivialString(callFrame, "object");
297 static bool jsIsObjectType(JSValuePtr v)
299 if (JSImmediate::isImmediate(v))
302 JSType type = asCell(v)->structureID()->typeInfo().type();
303 if (type == NumberType || type == StringType)
305 if (type == ObjectType) {
306 if (asObject(v)->structureID()->typeInfo().masqueradesAsUndefined())
309 if (asObject(v)->getCallData(callData) != CallTypeNone)
315 static bool jsIsFunctionType(JSValuePtr v)
319 if (asObject(v)->getCallData(callData) != CallTypeNone)
325 NEVER_INLINE bool Machine::resolve(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue)
327 int dst = (vPC + 1)->u.operand;
328 int property = (vPC + 2)->u.operand;
330 ScopeChainNode* scopeChain = callFrame->scopeChain();
331 ScopeChainIterator iter = scopeChain->begin();
332 ScopeChainIterator end = scopeChain->end();
335 CodeBlock* codeBlock = callFrame->codeBlock();
336 Identifier& ident = codeBlock->identifiers[property];
339 PropertySlot slot(o);
340 if (o->getPropertySlot(callFrame, ident, slot)) {
341 JSValuePtr result = slot.getValue(callFrame, ident);
342 exceptionValue = callFrame->globalData().exception;
345 callFrame[dst] = result;
348 } while (++iter != end);
349 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
353 NEVER_INLINE bool Machine::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue)
355 CodeBlock* codeBlock = callFrame->codeBlock();
357 int dst = (vPC + 1)->u.operand;
358 int property = (vPC + 2)->u.operand;
359 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
361 ScopeChainNode* scopeChain = callFrame->scopeChain();
362 ScopeChainIterator iter = scopeChain->begin();
363 ScopeChainIterator end = scopeChain->end();
369 Identifier& ident = codeBlock->identifiers[property];
372 PropertySlot slot(o);
373 if (o->getPropertySlot(callFrame, ident, slot)) {
374 JSValuePtr result = slot.getValue(callFrame, ident);
375 exceptionValue = callFrame->globalData().exception;
378 callFrame[dst] = result;
381 } while (++iter != end);
382 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
386 NEVER_INLINE bool Machine::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue)
388 int dst = (vPC + 1)->u.operand;
389 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
390 ASSERT(globalObject->isGlobalObject());
391 int property = (vPC + 3)->u.operand;
392 StructureID* structureID = (vPC + 4)->u.structureID;
393 int offset = (vPC + 5)->u.operand;
395 if (structureID == globalObject->structureID()) {
396 callFrame[dst] = globalObject->getDirectOffset(offset);
400 CodeBlock* codeBlock = callFrame->codeBlock();
401 Identifier& ident = codeBlock->identifiers[property];
402 PropertySlot slot(globalObject);
403 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
404 JSValuePtr result = slot.getValue(callFrame, ident);
405 if (slot.isCacheable()) {
406 if (vPC[4].u.structureID)
407 vPC[4].u.structureID->deref();
408 globalObject->structureID()->ref();
409 vPC[4] = globalObject->structureID();
410 vPC[5] = slot.cachedOffset();
411 callFrame[dst] = result;
415 exceptionValue = callFrame->globalData().exception;
418 callFrame[dst] = result;
422 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
426 static ALWAYS_INLINE JSValuePtr inlineResolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain)
428 ScopeChainIterator iter = scopeChain->begin();
429 ScopeChainIterator next = iter;
431 ScopeChainIterator end = scopeChain->end();
438 if (next == end || base->getPropertySlot(callFrame, property, slot))
445 ASSERT_NOT_REACHED();
449 NEVER_INLINE void Machine::resolveBase(CallFrame* callFrame, Instruction* vPC)
451 int dst = (vPC + 1)->u.operand;
452 int property = (vPC + 2)->u.operand;
453 callFrame[dst] = inlineResolveBase(callFrame, callFrame->codeBlock()->identifiers[property], callFrame->scopeChain());
456 NEVER_INLINE bool Machine::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue)
458 int baseDst = (vPC + 1)->u.operand;
459 int propDst = (vPC + 2)->u.operand;
460 int property = (vPC + 3)->u.operand;
462 ScopeChainNode* scopeChain = callFrame->scopeChain();
463 ScopeChainIterator iter = scopeChain->begin();
464 ScopeChainIterator end = scopeChain->end();
466 // FIXME: add scopeDepthIsZero optimization
470 CodeBlock* codeBlock = callFrame->codeBlock();
471 Identifier& ident = codeBlock->identifiers[property];
475 PropertySlot slot(base);
476 if (base->getPropertySlot(callFrame, ident, slot)) {
477 JSValuePtr result = slot.getValue(callFrame, ident);
478 exceptionValue = callFrame->globalData().exception;
481 callFrame[propDst] = result;
482 callFrame[baseDst] = base;
486 } while (iter != end);
488 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
492 NEVER_INLINE bool Machine::resolveBaseAndFunc(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue)
494 int baseDst = (vPC + 1)->u.operand;
495 int funcDst = (vPC + 2)->u.operand;
496 int property = (vPC + 3)->u.operand;
498 ScopeChainNode* scopeChain = callFrame->scopeChain();
499 ScopeChainIterator iter = scopeChain->begin();
500 ScopeChainIterator end = scopeChain->end();
502 // FIXME: add scopeDepthIsZero optimization
506 CodeBlock* codeBlock = callFrame->codeBlock();
507 Identifier& ident = codeBlock->identifiers[property];
511 PropertySlot slot(base);
512 if (base->getPropertySlot(callFrame, ident, slot)) {
513 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
514 // However, section 10.2.3 says that in the case where the value provided
515 // by the caller is null, the global object should be used. It also says
516 // that the section does not apply to internal functions, but for simplicity
517 // of implementation we use the global object anyway here. This guarantees
518 // that in host objects you always get a valid object for this.
519 // We also handle wrapper substitution for the global object at the same time.
520 JSObject* thisObj = base->toThisObject(callFrame);
521 JSValuePtr result = slot.getValue(callFrame, ident);
522 exceptionValue = callFrame->globalData().exception;
526 callFrame[baseDst] = thisObj;
527 callFrame[funcDst] = result;
531 } while (iter != end);
533 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
537 ALWAYS_INLINE CallFrame* Machine::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
539 Register* r = callFrame->registers();
540 Register* newEnd = r + registerOffset + newCodeBlock->numCalleeRegisters;
542 if (LIKELY(argc == newCodeBlock->numParameters)) { // correct number of arguments
543 if (UNLIKELY(!registerFile->grow(newEnd)))
546 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
547 size_t omittedArgCount = newCodeBlock->numParameters - argc;
548 registerOffset += omittedArgCount;
549 newEnd += omittedArgCount;
550 if (!registerFile->grow(newEnd))
554 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
555 for (size_t i = 0; i < omittedArgCount; ++i)
556 argv[i] = jsUndefined();
557 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
558 size_t numParameters = newCodeBlock->numParameters;
559 registerOffset += numParameters;
560 newEnd += numParameters;
562 if (!registerFile->grow(newEnd))
566 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
567 for (size_t i = 0; i < numParameters; ++i)
568 argv[i + argc] = argv[i];
571 return CallFrame::create(r);
574 static NEVER_INLINE bool isNotObject(CallFrame* callFrame, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValuePtr value, JSValuePtr& exceptionData)
576 if (value->isObject())
578 exceptionData = createInvalidParamError(callFrame, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
582 NEVER_INLINE JSValuePtr Machine::callEval(CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, int argv, int argc, JSValuePtr& exceptionValue)
585 return jsUndefined();
587 JSValuePtr program = callFrame[argv + 1].jsValue(callFrame);
589 if (!program->isString())
592 UString programSource = asString(program)->value();
594 CodeBlock* codeBlock = callFrame->codeBlock();
595 RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache.get(callFrame, programSource, scopeChain, exceptionValue);
597 JSValuePtr result = jsUndefined();
599 result = callFrame->globalData().machine->execute(evalNode.get(), callFrame, thisObj, callFrame->registers() - registerFile->start() + argv + 1 + RegisterFile::CallFrameHeaderSize, scopeChain, &exceptionValue);
607 , m_ctiArrayLengthTrampoline(0)
608 , m_ctiStringLengthTrampoline(0)
609 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
613 , m_timeAtLastCheckTimeout(0)
615 , m_timeoutCheckCount(0)
616 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
619 privateExecute(InitializeAndReturn, 0, 0, 0);
621 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
622 void* storage = fastMalloc(sizeof(CollectorBlock));
624 JSCell* jsArray = new (storage) JSArray(JSArray::createStructureID(jsNull()));
625 m_jsArrayVptr = jsArray->vptr();
628 JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
629 m_jsStringVptr = jsString->vptr();
632 JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructureID(jsNull()));
633 m_jsFunctionVptr = jsFunction->vptr();
634 jsFunction->~JSCell();
642 if (m_ctiArrayLengthTrampoline)
643 fastFree(m_ctiArrayLengthTrampoline);
644 if (m_ctiStringLengthTrampoline)
645 fastFree(m_ctiStringLengthTrampoline);
651 void Machine::dumpCallFrame(const RegisterFile* registerFile, CallFrame* callFrame)
653 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();
655 CodeBlock* codeBlock = callFrame->codeBlock();
656 codeBlock->dump(globalObject->globalExec());
658 dumpRegisters(registerFile, callFrame);
661 void Machine::dumpRegisters(const RegisterFile* registerFile, CallFrame* callFrame)
663 printf("Register frame: \n\n");
664 printf("----------------------------------------------------\n");
665 printf(" use | address | value \n");
666 printf("----------------------------------------------------\n");
668 CodeBlock* codeBlock = callFrame->codeBlock();
672 if (codeBlock->codeType == GlobalCode) {
673 it = registerFile->lastGlobal();
674 end = it + registerFile->numGlobals();
676 printf("[global var] | %10p | %10p \n", it, (*it).v());
679 printf("----------------------------------------------------\n");
682 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->numParameters;
683 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
684 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
687 printf("[param] | %10p | %10p \n", it, (*it).v());
691 printf("----------------------------------------------------\n");
693 printf("[CodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
694 printf("[ScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
695 printf("[CallerRegisters] | %10p | %10p \n", it, (*it).v()); ++it;
696 printf("[ReturnPC] | %10p | %10p \n", it, (*it).v()); ++it;
697 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
698 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
699 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
700 printf("[OptionalCalleeArguments] | %10p | %10p \n", it, (*it).v()); ++it;
701 printf("----------------------------------------------------\n");
703 int registerCount = 0;
705 end = it + codeBlock->numVars;
708 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
713 printf("----------------------------------------------------\n");
715 end = it + codeBlock->numConstants;
718 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
723 printf("----------------------------------------------------\n");
725 end = it + codeBlock->numCalleeRegisters - codeBlock->numConstants - codeBlock->numVars;
728 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
733 printf("----------------------------------------------------\n");
738 bool Machine::isOpcode(Opcode opcode)
740 #if HAVE(COMPUTED_GOTO)
741 return opcode != HashTraits<Opcode>::emptyValue()
742 && !HashTraits<Opcode>::isDeletedValue(opcode)
743 && m_opcodeIDTable.contains(opcode);
745 return opcode >= 0 && opcode <= op_end;
749 NEVER_INLINE bool Machine::unwindCallFrame(CallFrame*& callFrame, JSValuePtr exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock)
751 CodeBlock* oldCodeBlock = codeBlock;
752 ScopeChainNode* scopeChain = callFrame->scopeChain();
754 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
755 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
756 if (callFrame->callee())
757 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->lastLine());
759 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->lastLine());
762 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
763 if (callFrame->callee())
764 profiler->didExecute(callFrame, callFrame->callee());
766 profiler->didExecute(callFrame, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
769 // If this call frame created an activation or an 'arguments' object, tear it off.
770 if (oldCodeBlock->codeType == FunctionCode && oldCodeBlock->needsFullScopeChain) {
771 while (!scopeChain->object->isObject(&JSActivation::info))
772 scopeChain = scopeChain->pop();
773 static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments());
774 } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) {
775 if (!arguments->isTornOff())
776 arguments->copyRegisters();
779 if (oldCodeBlock->needsFullScopeChain)
782 void* returnPC = callFrame->returnPC();
783 callFrame = callFrame->callerFrame();
784 if (callFrame->hasHostCallFrameFlag())
787 codeBlock = callFrame->codeBlock();
788 vPC = vPCForPC(codeBlock, returnPC);
792 NEVER_INLINE Instruction* Machine::throwException(CallFrame*& callFrame, JSValuePtr& exceptionValue, const Instruction* vPC, bool explicitThrow)
794 // Set up the exception object
796 CodeBlock* codeBlock = callFrame->codeBlock();
797 if (exceptionValue->isObject()) {
798 JSObject* exception = asObject(exceptionValue);
799 if (exception->isNotAnObjectErrorStub()) {
800 exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
801 exceptionValue = exception;
803 if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) &&
804 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) &&
805 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) &&
806 !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) &&
807 !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) &&
808 !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) {
813 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
814 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete);
816 // We only hit this path for error messages and throw statements, which don't have a specific failure position
817 // So we just give the full range of the error/throw statement.
818 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete);
819 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete);
821 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
822 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerNode->sourceID()), ReadOnly | DontDelete);
823 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
826 if (exception->isWatchdogException()) {
827 while (unwindCallFrame(callFrame, exceptionValue, vPC, codeBlock)) {
828 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
835 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
836 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
837 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceID(), codeBlock->lineNumberForVPC(vPC));
840 // If we throw in the middle of a call instruction, we need to notify
841 // the profiler manually that the call instruction has returned, since
842 // we'll never reach the relevant op_profile_did_call.
843 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
844 if (isCallOpcode(vPC[0].u.opcode))
845 profiler->didExecute(callFrame, callFrame[vPC[2].u.operand].jsValue(callFrame));
846 else if (vPC[8].u.opcode == getOpcode(op_construct))
847 profiler->didExecute(callFrame, callFrame[vPC[10].u.operand].jsValue(callFrame));
850 // Calculate an exception handler vPC, unwinding call frames as necessary.
853 Instruction* handlerVPC;
855 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
856 if (!unwindCallFrame(callFrame, exceptionValue, vPC, codeBlock))
860 // Now unwind the scope chain within the exception handler's call frame.
862 ScopeChain sc(callFrame->scopeChain());
863 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
864 ASSERT(scopeDelta >= 0);
867 callFrame->setScopeChain(sc.node());
872 class DynamicGlobalObjectScope : Noncopyable {
874 DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject)
875 : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject)
876 , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot)
878 m_dynamicGlobalObjectSlot = dynamicGlobalObject;
881 ~DynamicGlobalObjectScope()
883 m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
887 JSGlobalObject*& m_dynamicGlobalObjectSlot;
888 JSGlobalObject* m_savedDynamicGlobalObject;
891 JSValuePtr Machine::execute(ProgramNode* programNode, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValuePtr* exception)
893 ASSERT(!scopeChain->globalData->exception);
895 if (m_reentryDepth >= MaxReentryDepth) {
896 *exception = createStackOverflowError(callFrame);
900 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
902 Register* oldEnd = m_registerFile.end();
903 Register* newEnd = oldEnd + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->numCalleeRegisters;
904 if (!m_registerFile.grow(newEnd)) {
905 *exception = createStackOverflowError(callFrame);
909 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject());
911 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
912 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
913 globalObject->copyGlobalsTo(m_registerFile);
915 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize);
916 newCallFrame[codeBlock->thisRegister] = thisObj;
917 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0);
919 if (codeBlock->needsFullScopeChain)
922 Profiler** profiler = Profiler::enabledProfilerReference();
924 (*profiler)->willExecute(newCallFrame, programNode->sourceURL(), programNode->lineNo());
928 if (!codeBlock->ctiCode)
929 CTI::compile(this, newCallFrame, codeBlock);
930 JSValuePtr result = CTI::execute(codeBlock->ctiCode, &m_registerFile, newCallFrame, scopeChain->globalData, exception);
932 JSValuePtr result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
936 MACHINE_SAMPLING_privateExecuteReturned();
939 (*profiler)->didExecute(callFrame, programNode->sourceURL(), programNode->lineNo());
941 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
942 lastGlobalObject->copyGlobalsTo(m_registerFile);
944 m_registerFile.shrink(oldEnd);
949 JSValuePtr Machine::execute(FunctionBodyNode* functionBodyNode, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValuePtr* exception)
951 ASSERT(!scopeChain->globalData->exception);
953 if (m_reentryDepth >= MaxReentryDepth) {
954 *exception = createStackOverflowError(callFrame);
958 Register* oldEnd = m_registerFile.end();
959 int argc = 1 + args.size(); // implicit "this" parameter
961 if (!m_registerFile.grow(oldEnd + argc)) {
962 *exception = createStackOverflowError(callFrame);
966 DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject());
968 CallFrame* newCallFrame = CallFrame::create(oldEnd);
970 newCallFrame[0] = thisObj;
971 ArgList::const_iterator end = args.end();
972 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
973 newCallFrame[++dst] = *it;
975 CodeBlock* codeBlock = &functionBodyNode->byteCode(scopeChain);
976 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
977 if (UNLIKELY(!newCallFrame)) {
978 *exception = createStackOverflowError(callFrame);
979 m_registerFile.shrink(oldEnd);
982 // a 0 codeBlock indicates a built-in caller
983 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
985 Profiler** profiler = Profiler::enabledProfilerReference();
987 (*profiler)->willExecute(newCallFrame, function);
991 if (!codeBlock->ctiCode)
992 CTI::compile(this, newCallFrame, codeBlock);
993 JSValuePtr result = CTI::execute(codeBlock->ctiCode, &m_registerFile, newCallFrame, scopeChain->globalData, exception);
995 JSValuePtr result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
1000 (*profiler)->didExecute(newCallFrame, function);
1002 MACHINE_SAMPLING_privateExecuteReturned();
1004 m_registerFile.shrink(oldEnd);
1008 JSValuePtr Machine::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValuePtr* exception)
1010 return execute(evalNode, callFrame, thisObj, m_registerFile.size() + evalNode->byteCode(scopeChain).numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
1013 JSValuePtr Machine::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValuePtr* exception)
1015 ASSERT(!scopeChain->globalData->exception);
1017 if (m_reentryDepth >= MaxReentryDepth) {
1018 *exception = createStackOverflowError(callFrame);
1022 DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject());
1024 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
1026 JSVariableObject* variableObject;
1027 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
1029 if (node->object->isVariableObject()) {
1030 variableObject = static_cast<JSVariableObject*>(node->object);
1035 { // Scope for BatchedTransitionOptimizer
1037 BatchedTransitionOptimizer optimizer(variableObject);
1039 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
1040 Node::VarStack::const_iterator varStackEnd = varStack.end();
1041 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
1042 const Identifier& ident = (*it).first;
1043 if (!variableObject->hasProperty(callFrame, ident)) {
1044 PutPropertySlot slot;
1045 variableObject->put(callFrame, ident, jsUndefined(), slot);
1049 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
1050 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
1051 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
1052 PutPropertySlot slot;
1053 variableObject->put(callFrame, (*it)->m_ident, (*it)->makeFunction(callFrame, scopeChain), slot);
1058 Register* oldEnd = m_registerFile.end();
1059 Register* newEnd = m_registerFile.start() + registerOffset + codeBlock->numCalleeRegisters;
1060 if (!m_registerFile.grow(newEnd)) {
1061 *exception = createStackOverflowError(callFrame);
1065 CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + registerOffset);
1067 // a 0 codeBlock indicates a built-in caller
1068 newCallFrame[codeBlock->thisRegister] = thisObj;
1069 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0);
1071 if (codeBlock->needsFullScopeChain)
1074 Profiler** profiler = Profiler::enabledProfilerReference();
1076 (*profiler)->willExecute(newCallFrame, evalNode->sourceURL(), evalNode->lineNo());
1080 if (!codeBlock->ctiCode)
1081 CTI::compile(this, newCallFrame, codeBlock);
1082 JSValuePtr result = CTI::execute(codeBlock->ctiCode, &m_registerFile, newCallFrame, scopeChain->globalData, exception);
1084 JSValuePtr result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
1088 MACHINE_SAMPLING_privateExecuteReturned();
1091 (*profiler)->didExecute(callFrame, evalNode->sourceURL(), evalNode->lineNo());
1093 m_registerFile.shrink(oldEnd);
1097 NEVER_INLINE void Machine::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
1099 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
1103 switch (debugHookID) {
1104 case DidEnterCallFrame:
1105 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerNode->sourceID(), firstLine);
1107 case WillLeaveCallFrame:
1108 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerNode->sourceID(), lastLine);
1110 case WillExecuteStatement:
1111 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerNode->sourceID(), firstLine);
1113 case WillExecuteProgram:
1114 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode->sourceID(), firstLine);
1116 case DidExecuteProgram:
1117 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode->sourceID(), lastLine);
1119 case DidReachBreakpoint:
1120 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerNode->sourceID(), lastLine);
1125 void Machine::resetTimeoutCheck()
1127 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1128 m_timeAtLastCheckTimeout = 0;
1129 m_timeExecuting = 0;
1132 // Returns the time the current thread has spent executing, in milliseconds.
1133 static inline unsigned getCPUTime()
1135 #if PLATFORM(DARWIN)
1136 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1137 thread_basic_info_data_t info;
1139 // Get thread information
1140 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1142 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1143 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1146 #elif HAVE(SYS_TIME_H)
1147 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1149 gettimeofday(&tv, 0);
1150 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1152 QDateTime t = QDateTime::currentDateTime();
1153 return t.toTime_t() * 1000 + t.time().msec();
1154 #elif PLATFORM(WIN_OS)
1157 unsigned long long fileTimeAsLong;
1158 } userTime, kernelTime;
1160 // GetThreadTimes won't accept NULL arguments so we pass these even though
1161 // they're not used.
1162 FILETIME creationTime, exitTime;
1164 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1166 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1168 #error Platform does not have getCurrentTime function
1172 // We have to return a JSValue here, gcc seems to produce worse code if
1173 // we attempt to return a bool
1174 ALWAYS_INLINE JSValuePtr Machine::checkTimeout(JSGlobalObject* globalObject)
1176 unsigned currentTime = getCPUTime();
1178 if (!m_timeAtLastCheckTimeout) {
1179 // Suspicious amount of looping in a script -- start timing it
1180 m_timeAtLastCheckTimeout = currentTime;
1184 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1189 m_timeExecuting += timeDiff;
1190 m_timeAtLastCheckTimeout = currentTime;
1192 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1193 // preferredScriptCheckTimeInterval
1194 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1195 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1196 // preferred script check time interval.
1197 if (m_ticksUntilNextTimeoutCheck == 0)
1198 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1200 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1201 if (globalObject->shouldInterruptScript())
1202 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1204 resetTimeoutCheck();
1210 NEVER_INLINE ScopeChainNode* Machine::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
1212 int dst = (++vPC)->u.operand;
1213 CodeBlock* codeBlock = callFrame->codeBlock();
1214 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1215 JSValuePtr value = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1216 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
1217 callFrame[dst] = scope;
1219 return callFrame->scopeChain()->push(scope);
1222 static StructureIDChain* cachePrototypeChain(CallFrame* callFrame, StructureID* structureID)
1224 JSValuePtr prototype = structureID->prototypeForLookup(callFrame);
1225 if (JSImmediate::isImmediate(prototype))
1227 RefPtr<StructureIDChain> chain = StructureIDChain::create(asObject(prototype)->structureID());
1228 structureID->setCachedPrototypeChain(chain.release());
1229 return structureID->cachedPrototypeChain();
1232 NEVER_INLINE void Machine::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValuePtr baseValue, const PutPropertySlot& slot)
1234 // Recursive invocation may already have specialized this instruction.
1235 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1238 if (JSImmediate::isImmediate(baseValue))
1241 // Uncacheable: give up.
1242 if (!slot.isCacheable()) {
1243 vPC[0] = getOpcode(op_put_by_id_generic);
1247 JSCell* baseCell = asCell(baseValue);
1248 StructureID* structureID = baseCell->structureID();
1250 if (structureID->isDictionary()) {
1251 vPC[0] = getOpcode(op_put_by_id_generic);
1255 // Cache miss: record StructureID to compare against next time.
1256 StructureID* lastStructureID = vPC[4].u.structureID;
1257 if (structureID != lastStructureID) {
1258 // First miss: record StructureID to compare against next time.
1259 if (!lastStructureID) {
1260 vPC[4] = structureID;
1264 // Second miss: give up.
1265 vPC[0] = getOpcode(op_put_by_id_generic);
1269 // Cache hit: Specialize instruction and ref StructureIDs.
1271 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1272 if (baseCell != slot.base()) {
1273 vPC[0] = getOpcode(op_put_by_id_generic);
1277 // StructureID transition, cache transition info
1278 if (slot.type() == PutPropertySlot::NewProperty) {
1279 vPC[0] = getOpcode(op_put_by_id_transition);
1280 vPC[4] = structureID->previousID();
1281 vPC[5] = structureID;
1282 StructureIDChain* chain = structureID->cachedPrototypeChain();
1284 chain = cachePrototypeChain(callFrame, structureID);
1286 // This happens if someone has manually inserted null into the prototype chain
1287 vPC[0] = getOpcode(op_put_by_id_generic);
1292 vPC[7] = slot.cachedOffset();
1293 codeBlock->refStructureIDs(vPC);
1297 vPC[0] = getOpcode(op_put_by_id_replace);
1298 vPC[5] = slot.cachedOffset();
1299 codeBlock->refStructureIDs(vPC);
1302 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1304 codeBlock->derefStructureIDs(vPC);
1305 vPC[0] = getOpcode(op_put_by_id);
1309 NEVER_INLINE void Machine::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValuePtr baseValue, const Identifier& propertyName, const PropertySlot& slot)
1311 // Recursive invocation may already have specialized this instruction.
1312 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1315 // FIXME: Cache property access for immediates.
1316 if (JSImmediate::isImmediate(baseValue)) {
1317 vPC[0] = getOpcode(op_get_by_id_generic);
1321 if (isJSArray(baseValue) && propertyName == callFrame->propertyNames().length) {
1322 vPC[0] = getOpcode(op_get_array_length);
1326 if (isJSString(baseValue) && propertyName == callFrame->propertyNames().length) {
1327 vPC[0] = getOpcode(op_get_string_length);
1331 // Uncacheable: give up.
1332 if (!slot.isCacheable()) {
1333 vPC[0] = getOpcode(op_get_by_id_generic);
1337 StructureID* structureID = asCell(baseValue)->structureID();
1339 if (structureID->isDictionary()) {
1340 vPC[0] = getOpcode(op_get_by_id_generic);
1345 StructureID* lastStructureID = vPC[4].u.structureID;
1346 if (structureID != lastStructureID) {
1347 // First miss: record StructureID to compare against next time.
1348 if (!lastStructureID) {
1349 vPC[4] = structureID;
1353 // Second miss: give up.
1354 vPC[0] = getOpcode(op_get_by_id_generic);
1358 // Cache hit: Specialize instruction and ref StructureIDs.
1360 if (slot.slotBase() == baseValue) {
1361 vPC[0] = getOpcode(op_get_by_id_self);
1362 vPC[5] = slot.cachedOffset();
1364 codeBlock->refStructureIDs(vPC);
1368 if (slot.slotBase() == structureID->prototypeForLookup(callFrame)) {
1369 ASSERT(slot.slotBase()->isObject());
1371 JSObject* baseObject = asObject(slot.slotBase());
1373 // Heavy access to a prototype is a good indication that it's not being
1374 // used as a dictionary.
1375 if (baseObject->structureID()->isDictionary()) {
1376 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1377 baseObject->setStructureID(transition.release());
1378 asCell(baseValue)->structureID()->setCachedPrototypeChain(0);
1381 vPC[0] = getOpcode(op_get_by_id_proto);
1382 vPC[5] = baseObject->structureID();
1383 vPC[6] = slot.cachedOffset();
1385 codeBlock->refStructureIDs(vPC);
1390 JSObject* o = asObject(baseValue);
1391 while (slot.slotBase() != o) {
1392 JSValuePtr v = o->structureID()->prototypeForLookup(callFrame);
1394 // If we didn't find base in baseValue's prototype chain, then baseValue
1395 // must be a proxy for another object.
1397 vPC[0] = getOpcode(op_get_by_id_generic);
1403 // Heavy access to a prototype is a good indication that it's not being
1404 // used as a dictionary.
1405 if (o->structureID()->isDictionary()) {
1406 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1407 o->setStructureID(transition.release());
1408 asObject(baseValue)->structureID()->setCachedPrototypeChain(0);
1414 StructureIDChain* chain = structureID->cachedPrototypeChain();
1416 chain = cachePrototypeChain(callFrame, structureID);
1419 vPC[0] = getOpcode(op_get_by_id_chain);
1420 vPC[4] = structureID;
1423 vPC[7] = slot.cachedOffset();
1424 codeBlock->refStructureIDs(vPC);
1427 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1429 codeBlock->derefStructureIDs(vPC);
1430 vPC[0] = getOpcode(op_get_by_id);
1434 JSValuePtr Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValuePtr* exception)
1436 // One-time initialization of our address tables. We have to put this code
1437 // here because our labels are only in scope inside this function.
1438 if (flag == InitializeAndReturn) {
1439 #if HAVE(COMPUTED_GOTO)
1440 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1441 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1444 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1445 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1446 #undef ADD_OPCODE_ID
1447 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1448 op_throw_end_indirect = &&op_throw_end;
1449 op_call_indirect = &&op_call;
1450 #endif // HAVE(COMPUTED_GOTO)
1455 // Currently with CTI enabled we never interpret functions
1456 ASSERT_NOT_REACHED();
1459 JSGlobalData* globalData = &callFrame->globalData();
1460 JSValuePtr exceptionValue = noValue();
1461 Instruction* handlerVPC = 0;
1463 Instruction* vPC = callFrame->codeBlock()->instructions.begin();
1464 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1465 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1467 #define VM_CHECK_EXCEPTION() \
1469 if (UNLIKELY(globalData->exception != noValue())) { \
1470 exceptionValue = globalData->exception; \
1475 #if DUMP_OPCODE_STATS
1476 OpcodeStats::resetLastInstruction();
1479 #define CHECK_FOR_TIMEOUT() \
1480 if (!--tickCount) { \
1481 if ((exceptionValue = checkTimeout(callFrame->dynamicGlobalObject()))) \
1483 tickCount = m_ticksUntilNextTimeoutCheck; \
1486 #if HAVE(COMPUTED_GOTO)
1487 #define NEXT_OPCODE MACHINE_SAMPLING_sample(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
1488 #if DUMP_OPCODE_STATS
1489 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1491 #define BEGIN_OPCODE(opcode) opcode:
1495 #define NEXT_OPCODE MACHINE_SAMPLING_sample(callFrame->codeBlock(), vPC); goto interpreterLoopStart
1496 #if DUMP_OPCODE_STATS
1497 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1499 #define BEGIN_OPCODE(opcode) case opcode:
1501 while (1) { // iterator loop begins
1502 interpreterLoopStart:;
1503 switch (vPC->u.opcode)
1506 BEGIN_OPCODE(op_new_object) {
1507 /* new_object dst(r)
1509 Constructs a new empty Object instance using the original
1510 constructor, and puts the result in register dst.
1512 int dst = (++vPC)->u.operand;
1513 callFrame[dst] = constructEmptyObject(callFrame);
1518 BEGIN_OPCODE(op_new_array) {
1519 /* new_array dst(r) firstArg(r) argCount(n)
1521 Constructs a new Array instance using the original
1522 constructor, and puts the result in register dst.
1523 The array will contain argCount elements with values
1524 taken from registers starting at register firstArg.
1526 int dst = (++vPC)->u.operand;
1527 int firstArg = (++vPC)->u.operand;
1528 int argCount = (++vPC)->u.operand;
1529 ArgList args(callFrame->registers() + firstArg, argCount);
1530 callFrame[dst] = constructArray(callFrame, args);
1535 BEGIN_OPCODE(op_new_regexp) {
1536 /* new_regexp dst(r) regExp(re)
1538 Constructs a new RegExp instance using the original
1539 constructor from regexp regExp, and puts the result in
1542 int dst = (++vPC)->u.operand;
1543 int regExp = (++vPC)->u.operand;
1544 callFrame[dst] = new (globalData) RegExpObject(callFrame->scopeChain()->globalObject()->regExpStructure(), callFrame->codeBlock()->regexps[regExp]);
1549 BEGIN_OPCODE(op_mov) {
1550 /* mov dst(r) src(r)
1552 Copies register src to register dst.
1554 int dst = (++vPC)->u.operand;
1555 int src = (++vPC)->u.operand;
1556 callFrame[dst] = callFrame[src];
1561 BEGIN_OPCODE(op_eq) {
1562 /* eq dst(r) src1(r) src2(r)
1564 Checks whether register src1 and register src2 are equal,
1565 as with the ECMAScript '==' operator, and puts the result
1566 as a boolean in register dst.
1568 int dst = (++vPC)->u.operand;
1569 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1570 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1571 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1572 callFrame[dst] = jsBoolean(src1 == src2);
1574 JSValuePtr result = jsBoolean(equalSlowCase(callFrame, src1, src2));
1575 VM_CHECK_EXCEPTION();
1576 callFrame[dst] = result;
1582 BEGIN_OPCODE(op_eq_null) {
1583 /* eq_null dst(r) src(r)
1585 Checks whether register src is null, as with the ECMAScript '!='
1586 operator, and puts the result as a boolean in register dst.
1588 int dst = (++vPC)->u.operand;
1589 JSValuePtr src = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1591 if (src->isUndefinedOrNull()) {
1592 callFrame[dst] = jsBoolean(true);
1597 callFrame[dst] = jsBoolean(!JSImmediate::isImmediate(src) && src->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
1601 BEGIN_OPCODE(op_neq) {
1602 /* neq dst(r) src1(r) src2(r)
1604 Checks whether register src1 and register src2 are not
1605 equal, as with the ECMAScript '!=' operator, and puts the
1606 result as a boolean in register dst.
1608 int dst = (++vPC)->u.operand;
1609 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1610 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1611 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1612 callFrame[dst] = jsBoolean(src1 != src2);
1614 JSValuePtr result = jsBoolean(!equalSlowCase(callFrame, src1, src2));
1615 VM_CHECK_EXCEPTION();
1616 callFrame[dst] = result;
1622 BEGIN_OPCODE(op_neq_null) {
1623 /* neq_null dst(r) src(r)
1625 Checks whether register src is not null, as with the ECMAScript '!='
1626 operator, and puts the result as a boolean in register dst.
1628 int dst = (++vPC)->u.operand;
1629 JSValuePtr src = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1631 if (src->isUndefinedOrNull()) {
1632 callFrame[dst] = jsBoolean(false);
1637 callFrame[dst] = jsBoolean(JSImmediate::isImmediate(src) || !asCell(src)->structureID()->typeInfo().masqueradesAsUndefined());
1641 BEGIN_OPCODE(op_stricteq) {
1642 /* stricteq dst(r) src1(r) src2(r)
1644 Checks whether register src1 and register src2 are strictly
1645 equal, as with the ECMAScript '===' operator, and puts the
1646 result as a boolean in register dst.
1648 int dst = (++vPC)->u.operand;
1649 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1650 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1651 if (JSImmediate::areBothImmediate(src1, src2))
1652 callFrame[dst] = jsBoolean(src1 == src2);
1653 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1654 callFrame[dst] = jsBoolean(false);
1656 callFrame[dst] = jsBoolean(strictEqualSlowCase(src1, src2));
1661 BEGIN_OPCODE(op_nstricteq) {
1662 /* nstricteq dst(r) src1(r) src2(r)
1664 Checks whether register src1 and register src2 are not
1665 strictly equal, as with the ECMAScript '!==' operator, and
1666 puts the result as a boolean in register dst.
1668 int dst = (++vPC)->u.operand;
1669 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1670 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1672 if (JSImmediate::areBothImmediate(src1, src2))
1673 callFrame[dst] = jsBoolean(src1 != src2);
1674 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1675 callFrame[dst] = jsBoolean(true);
1677 callFrame[dst] = jsBoolean(!strictEqualSlowCase(src1, src2));
1682 BEGIN_OPCODE(op_less) {
1683 /* less dst(r) src1(r) src2(r)
1685 Checks whether register src1 is less than register src2, as
1686 with the ECMAScript '<' operator, and puts the result as
1687 a boolean in register dst.
1689 int dst = (++vPC)->u.operand;
1690 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1691 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1692 JSValuePtr result = jsBoolean(jsLess(callFrame, src1, src2));
1693 VM_CHECK_EXCEPTION();
1694 callFrame[dst] = result;
1699 BEGIN_OPCODE(op_lesseq) {
1700 /* lesseq dst(r) src1(r) src2(r)
1702 Checks whether register src1 is less than or equal to
1703 register src2, as with the ECMAScript '<=' operator, and
1704 puts the result as a boolean in register dst.
1706 int dst = (++vPC)->u.operand;
1707 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1708 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1709 JSValuePtr result = jsBoolean(jsLessEq(callFrame, src1, src2));
1710 VM_CHECK_EXCEPTION();
1711 callFrame[dst] = result;
1716 BEGIN_OPCODE(op_pre_inc) {
1717 /* pre_inc srcDst(r)
1719 Converts register srcDst to number, adds one, and puts the result
1720 back in register srcDst.
1722 int srcDst = (++vPC)->u.operand;
1723 JSValuePtr v = callFrame[srcDst].jsValue(callFrame);
1724 if (JSImmediate::canDoFastAdditiveOperations(v))
1725 callFrame[srcDst] = JSImmediate::incImmediateNumber(v);
1727 JSValuePtr result = jsNumber(callFrame, v->toNumber(callFrame) + 1);
1728 VM_CHECK_EXCEPTION();
1729 callFrame[srcDst] = result;
1735 BEGIN_OPCODE(op_pre_dec) {
1736 /* pre_dec srcDst(r)
1738 Converts register srcDst to number, subtracts one, and puts the result
1739 back in register srcDst.
1741 int srcDst = (++vPC)->u.operand;
1742 JSValuePtr v = callFrame[srcDst].jsValue(callFrame);
1743 if (JSImmediate::canDoFastAdditiveOperations(v))
1744 callFrame[srcDst] = JSImmediate::decImmediateNumber(v);
1746 JSValuePtr result = jsNumber(callFrame, v->toNumber(callFrame) - 1);
1747 VM_CHECK_EXCEPTION();
1748 callFrame[srcDst] = result;
1754 BEGIN_OPCODE(op_post_inc) {
1755 /* post_inc dst(r) srcDst(r)
1757 Converts register srcDst to number. The number itself is
1758 written to register dst, and the number plus one is written
1759 back to register srcDst.
1761 int dst = (++vPC)->u.operand;
1762 int srcDst = (++vPC)->u.operand;
1763 JSValuePtr v = callFrame[srcDst].jsValue(callFrame);
1764 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1766 callFrame[srcDst] = JSImmediate::incImmediateNumber(v);
1768 JSValuePtr number = callFrame[srcDst].jsValue(callFrame)->toJSNumber(callFrame);
1769 VM_CHECK_EXCEPTION();
1770 callFrame[dst] = number;
1771 callFrame[srcDst] = jsNumber(callFrame, number->uncheckedGetNumber() + 1);
1777 BEGIN_OPCODE(op_post_dec) {
1778 /* post_dec dst(r) srcDst(r)
1780 Converts register srcDst to number. The number itself is
1781 written to register dst, and the number minus one is written
1782 back to register srcDst.
1784 int dst = (++vPC)->u.operand;
1785 int srcDst = (++vPC)->u.operand;
1786 JSValuePtr v = callFrame[srcDst].jsValue(callFrame);
1787 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1789 callFrame[srcDst] = JSImmediate::decImmediateNumber(v);
1791 JSValuePtr number = callFrame[srcDst].jsValue(callFrame)->toJSNumber(callFrame);
1792 VM_CHECK_EXCEPTION();
1793 callFrame[dst] = number;
1794 callFrame[srcDst] = jsNumber(callFrame, number->uncheckedGetNumber() - 1);
1800 BEGIN_OPCODE(op_to_jsnumber) {
1801 /* to_jsnumber dst(r) src(r)
1803 Converts register src to number, and puts the result
1806 int dst = (++vPC)->u.operand;
1807 int src = (++vPC)->u.operand;
1809 JSValuePtr srcVal = callFrame[src].jsValue(callFrame);
1811 if (LIKELY(srcVal->isNumber()))
1812 callFrame[dst] = callFrame[src];
1814 JSValuePtr result = srcVal->toJSNumber(callFrame);
1815 VM_CHECK_EXCEPTION();
1816 callFrame[dst] = result;
1822 BEGIN_OPCODE(op_negate) {
1823 /* negate dst(r) src(r)
1825 Converts register src to number, negates it, and puts the
1826 result in register dst.
1828 int dst = (++vPC)->u.operand;
1829 JSValuePtr src = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1831 if (fastIsNumber(src, v))
1832 callFrame[dst] = jsNumber(callFrame, -v);
1834 JSValuePtr result = jsNumber(callFrame, -src->toNumber(callFrame));
1835 VM_CHECK_EXCEPTION();
1836 callFrame[dst] = result;
1842 BEGIN_OPCODE(op_add) {
1843 /* add dst(r) src1(r) src2(r)
1845 Adds register src1 and register src2, and puts the result
1846 in register dst. (JS add may be string concatenation or
1847 numeric add, depending on the types of the operands.)
1849 int dst = (++vPC)->u.operand;
1850 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1851 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1852 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1853 callFrame[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1855 JSValuePtr result = jsAdd(callFrame, src1, src2);
1856 VM_CHECK_EXCEPTION();
1857 callFrame[dst] = result;
1862 BEGIN_OPCODE(op_mul) {
1863 /* mul dst(r) src1(r) src2(r)
1865 Multiplies register src1 and register src2 (converted to
1866 numbers), and puts the product in register dst.
1868 int dst = (++vPC)->u.operand;
1869 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1870 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1873 if (JSImmediate::areBothImmediateNumbers(src1, src2)) {
1874 int32_t left = JSImmediate::getTruncatedInt32(src1);
1875 int32_t right = JSImmediate::getTruncatedInt32(src2);
1876 if ((left | right) >> 15 == 0)
1877 callFrame[dst] = jsNumber(callFrame, left * right);
1879 callFrame[dst] = jsNumber(callFrame, static_cast<double>(left) * static_cast<double>(right));
1880 } else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1881 callFrame[dst] = jsNumber(callFrame, left * right);
1883 JSValuePtr result = jsNumber(callFrame, src1->toNumber(callFrame) * src2->toNumber(callFrame));
1884 VM_CHECK_EXCEPTION();
1885 callFrame[dst] = result;
1891 BEGIN_OPCODE(op_div) {
1892 /* div dst(r) dividend(r) divisor(r)
1894 Divides register dividend (converted to number) by the
1895 register divisor (converted to number), and puts the
1896 quotient in register dst.
1898 int dst = (++vPC)->u.operand;
1899 JSValuePtr dividend = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1900 JSValuePtr divisor = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1903 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1904 callFrame[dst] = jsNumber(callFrame, left / right);
1906 JSValuePtr result = jsNumber(callFrame, dividend->toNumber(callFrame) / divisor->toNumber(callFrame));
1907 VM_CHECK_EXCEPTION();
1908 callFrame[dst] = result;
1913 BEGIN_OPCODE(op_mod) {
1914 /* mod dst(r) dividend(r) divisor(r)
1916 Divides register dividend (converted to number) by
1917 register divisor (converted to number), and puts the
1918 remainder in register dst.
1920 int dst = (++vPC)->u.operand;
1921 int dividend = (++vPC)->u.operand;
1922 int divisor = (++vPC)->u.operand;
1924 JSValuePtr dividendValue = callFrame[dividend].jsValue(callFrame);
1925 JSValuePtr divisorValue = callFrame[divisor].jsValue(callFrame);
1927 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1928 callFrame[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1933 double d = dividendValue->toNumber(callFrame);
1934 JSValuePtr result = jsNumber(callFrame, fmod(d, divisorValue->toNumber(callFrame)));
1935 VM_CHECK_EXCEPTION();
1936 callFrame[dst] = result;
1940 BEGIN_OPCODE(op_sub) {
1941 /* sub dst(r) src1(r) src2(r)
1943 Subtracts register src2 (converted to number) from register
1944 src1 (converted to number), and puts the difference in
1947 int dst = (++vPC)->u.operand;
1948 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1949 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1952 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1953 callFrame[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1954 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1955 callFrame[dst] = jsNumber(callFrame, left - right);
1957 JSValuePtr result = jsNumber(callFrame, src1->toNumber(callFrame) - src2->toNumber(callFrame));
1958 VM_CHECK_EXCEPTION();
1959 callFrame[dst] = result;
1964 BEGIN_OPCODE(op_lshift) {
1965 /* lshift dst(r) val(r) shift(r)
1967 Performs left shift of register val (converted to int32) by
1968 register shift (converted to uint32), and puts the result
1971 int dst = (++vPC)->u.operand;
1972 JSValuePtr val = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1973 JSValuePtr shift = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1976 if (JSImmediate::areBothImmediateNumbers(val, shift))
1977 callFrame[dst] = jsNumber(callFrame, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1978 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1979 callFrame[dst] = jsNumber(callFrame, left << (right & 0x1f));
1981 JSValuePtr result = jsNumber(callFrame, (val->toInt32(callFrame)) << (shift->toUInt32(callFrame) & 0x1f));
1982 VM_CHECK_EXCEPTION();
1983 callFrame[dst] = result;
1989 BEGIN_OPCODE(op_rshift) {
1990 /* rshift dst(r) val(r) shift(r)
1992 Performs arithmetic right shift of register val (converted
1993 to int32) by register shift (converted to
1994 uint32), and puts the result in register dst.
1996 int dst = (++vPC)->u.operand;
1997 JSValuePtr val = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1998 JSValuePtr shift = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2001 if (JSImmediate::areBothImmediateNumbers(val, shift))
2002 callFrame[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
2003 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
2004 callFrame[dst] = jsNumber(callFrame, left >> (right & 0x1f));
2006 JSValuePtr result = jsNumber(callFrame, (val->toInt32(callFrame)) >> (shift->toUInt32(callFrame) & 0x1f));
2007 VM_CHECK_EXCEPTION();
2008 callFrame[dst] = result;
2014 BEGIN_OPCODE(op_urshift) {
2015 /* rshift dst(r) val(r) shift(r)
2017 Performs logical right shift of register val (converted
2018 to uint32) by register shift (converted to
2019 uint32), and puts the result in register dst.
2021 int dst = (++vPC)->u.operand;
2022 JSValuePtr val = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2023 JSValuePtr shift = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2024 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
2025 callFrame[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
2027 JSValuePtr result = jsNumber(callFrame, (val->toUInt32(callFrame)) >> (shift->toUInt32(callFrame) & 0x1f));
2028 VM_CHECK_EXCEPTION();
2029 callFrame[dst] = result;
2035 BEGIN_OPCODE(op_bitand) {
2036 /* bitand dst(r) src1(r) src2(r)
2038 Computes bitwise AND of register src1 (converted to int32)
2039 and register src2 (converted to int32), and puts the result
2042 int dst = (++vPC)->u.operand;
2043 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2044 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2047 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2048 callFrame[dst] = JSImmediate::andImmediateNumbers(src1, src2);
2049 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2050 callFrame[dst] = jsNumber(callFrame, left & right);
2052 JSValuePtr result = jsNumber(callFrame, src1->toInt32(callFrame) & src2->toInt32(callFrame));
2053 VM_CHECK_EXCEPTION();
2054 callFrame[dst] = result;
2060 BEGIN_OPCODE(op_bitxor) {
2061 /* bitxor dst(r) src1(r) src2(r)
2063 Computes bitwise XOR of register src1 (converted to int32)
2064 and register src2 (converted to int32), and puts the result
2067 int dst = (++vPC)->u.operand;
2068 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2069 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2072 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2073 callFrame[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
2074 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2075 callFrame[dst] = jsNumber(callFrame, left ^ right);
2077 JSValuePtr result = jsNumber(callFrame, src1->toInt32(callFrame) ^ src2->toInt32(callFrame));
2078 VM_CHECK_EXCEPTION();
2079 callFrame[dst] = result;
2085 BEGIN_OPCODE(op_bitor) {
2086 /* bitor dst(r) src1(r) src2(r)
2088 Computes bitwise OR of register src1 (converted to int32)
2089 and register src2 (converted to int32), and puts the
2090 result in register dst.
2092 int dst = (++vPC)->u.operand;
2093 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2094 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2097 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2098 callFrame[dst] = JSImmediate::orImmediateNumbers(src1, src2);
2099 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2100 callFrame[dst] = jsNumber(callFrame, left | right);
2102 JSValuePtr result = jsNumber(callFrame, src1->toInt32(callFrame) | src2->toInt32(callFrame));
2103 VM_CHECK_EXCEPTION();
2104 callFrame[dst] = result;
2110 BEGIN_OPCODE(op_bitnot) {
2111 /* bitnot dst(r) src(r)
2113 Computes bitwise NOT of register src1 (converted to int32),
2114 and puts the result in register dst.
2116 int dst = (++vPC)->u.operand;
2117 JSValuePtr src = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2119 if (fastToInt32(src, value))
2120 callFrame[dst] = jsNumber(callFrame, ~value);
2122 JSValuePtr result = jsNumber(callFrame, ~src->toInt32(callFrame));
2123 VM_CHECK_EXCEPTION();
2124 callFrame[dst] = result;
2129 BEGIN_OPCODE(op_not) {
2130 /* not dst(r) src(r)
2132 Computes logical NOT of register src (converted to
2133 boolean), and puts the result in register dst.
2135 int dst = (++vPC)->u.operand;
2136 int src = (++vPC)->u.operand;
2137 JSValuePtr result = jsBoolean(!callFrame[src].jsValue(callFrame)->toBoolean(callFrame));
2138 VM_CHECK_EXCEPTION();
2139 callFrame[dst] = result;
2144 BEGIN_OPCODE(op_instanceof) {
2145 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2147 Tests whether register value is an instance of register
2148 constructor, and puts the boolean result in register
2149 dst. Register constructorProto must contain the "prototype"
2150 property (not the actual prototype) of the object in
2151 register constructor. This lookup is separated so that
2152 polymorphic inline caching can apply.
2154 Raises an exception if register constructor is not an
2157 int dst = vPC[1].u.operand;
2158 int value = vPC[2].u.operand;
2159 int base = vPC[3].u.operand;
2160 int baseProto = vPC[4].u.operand;
2162 JSValuePtr baseVal = callFrame[base].jsValue(callFrame);
2164 if (isNotObject(callFrame, true, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
2167 JSObject* baseObj = asObject(baseVal);
2168 callFrame[dst] = jsBoolean(baseObj->structureID()->typeInfo().implementsHasInstance() ? baseObj->hasInstance(callFrame, callFrame[value].jsValue(callFrame), callFrame[baseProto].jsValue(callFrame)) : false);
2173 BEGIN_OPCODE(op_typeof) {
2174 /* typeof dst(r) src(r)
2176 Determines the type string for src according to ECMAScript
2177 rules, and puts the result in register dst.
2179 int dst = (++vPC)->u.operand;
2180 int src = (++vPC)->u.operand;
2181 callFrame[dst] = jsTypeStringForValue(callFrame, callFrame[src].jsValue(callFrame));
2186 BEGIN_OPCODE(op_is_undefined) {
2187 /* is_undefined dst(r) src(r)
2189 Determines whether the type string for src according to
2190 the ECMAScript rules is "undefined", and puts the result
2193 int dst = (++vPC)->u.operand;
2194 int src = (++vPC)->u.operand;
2195 JSValuePtr v = callFrame[src].jsValue(callFrame);
2196 callFrame[dst] = jsBoolean(JSImmediate::isImmediate(v) ? v->isUndefined() : v->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
2201 BEGIN_OPCODE(op_is_boolean) {
2202 /* is_boolean dst(r) src(r)
2204 Determines whether the type string for src according to
2205 the ECMAScript rules is "boolean", and puts the result
2208 int dst = (++vPC)->u.operand;
2209 int src = (++vPC)->u.operand;
2210 callFrame[dst] = jsBoolean(callFrame[src].jsValue(callFrame)->isBoolean());
2215 BEGIN_OPCODE(op_is_number) {
2216 /* is_number dst(r) src(r)
2218 Determines whether the type string for src according to
2219 the ECMAScript rules is "number", and puts the result
2222 int dst = (++vPC)->u.operand;
2223 int src = (++vPC)->u.operand;
2224 callFrame[dst] = jsBoolean(callFrame[src].jsValue(callFrame)->isNumber());
2229 BEGIN_OPCODE(op_is_string) {
2230 /* is_string dst(r) src(r)
2232 Determines whether the type string for src according to
2233 the ECMAScript rules is "string", and puts the result
2236 int dst = (++vPC)->u.operand;
2237 int src = (++vPC)->u.operand;
2238 callFrame[dst] = jsBoolean(callFrame[src].jsValue(callFrame)->isString());
2243 BEGIN_OPCODE(op_is_object) {
2244 /* is_object dst(r) src(r)
2246 Determines whether the type string for src according to
2247 the ECMAScript rules is "object", and puts the result
2250 int dst = (++vPC)->u.operand;
2251 int src = (++vPC)->u.operand;
2252 callFrame[dst] = jsBoolean(jsIsObjectType(callFrame[src].jsValue(callFrame)));
2257 BEGIN_OPCODE(op_is_function) {
2258 /* is_function dst(r) src(r)
2260 Determines whether the type string for src according to
2261 the ECMAScript rules is "function", and puts the result
2264 int dst = (++vPC)->u.operand;
2265 int src = (++vPC)->u.operand;
2266 callFrame[dst] = jsBoolean(jsIsFunctionType(callFrame[src].jsValue(callFrame)));
2271 BEGIN_OPCODE(op_in) {
2272 /* in dst(r) property(r) base(r)
2274 Tests whether register base has a property named register
2275 property, and puts the boolean result in register dst.
2277 Raises an exception if register constructor is not an
2280 int dst = (++vPC)->u.operand;
2281 int property = (++vPC)->u.operand;
2282 int base = (++vPC)->u.operand;
2284 JSValuePtr baseVal = callFrame[base].jsValue(callFrame);
2285 if (isNotObject(callFrame, false, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
2288 JSObject* baseObj = asObject(baseVal);
2290 JSValuePtr propName = callFrame[property].jsValue(callFrame);
2293 if (propName->getUInt32(i))
2294 callFrame[dst] = jsBoolean(baseObj->hasProperty(callFrame, i));
2296 Identifier property(callFrame, propName->toString(callFrame));
2297 VM_CHECK_EXCEPTION();
2298 callFrame[dst] = jsBoolean(baseObj->hasProperty(callFrame, property));
2304 BEGIN_OPCODE(op_resolve) {
2305 /* resolve dst(r) property(id)
2307 Looks up the property named by identifier property in the
2308 scope chain, and writes the resulting value to register
2309 dst. If the property is not found, raises an exception.
2311 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
2317 BEGIN_OPCODE(op_resolve_skip) {
2318 /* resolve_skip dst(r) property(id) skip(n)
2320 Looks up the property named by identifier property in the
2321 scope chain skipping the top 'skip' levels, and writes the resulting
2322 value to register dst. If the property is not found, raises an exception.
2324 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
2331 BEGIN_OPCODE(op_resolve_global) {
2332 /* resolve_skip dst(r) globalObject(c) property(id) structureID(sID) offset(n)
2334 Performs a dynamic property lookup for the given property, on the provided
2335 global object. If structureID matches the StructureID of the global then perform
2336 a fast lookup using the case offset, otherwise fall back to a full resolve and
2337 cache the new structureID and offset
2339 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
2346 BEGIN_OPCODE(op_get_global_var) {
2347 /* get_global_var dst(r) globalObject(c) index(n)
2349 Gets the global var at global slot index and places it in register dst.
2351 int dst = (++vPC)->u.operand;
2352 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2353 ASSERT(scope->isGlobalObject());
2354 int index = (++vPC)->u.operand;
2356 callFrame[dst] = scope->registerAt(index);
2360 BEGIN_OPCODE(op_put_global_var) {
2361 /* put_global_var globalObject(c) index(n) value(r)
2363 Puts value into global slot index.
2365 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2366 ASSERT(scope->isGlobalObject());
2367 int index = (++vPC)->u.operand;
2368 int value = (++vPC)->u.operand;
2370 scope->registerAt(index) = callFrame[value].jsValue(callFrame);
2374 BEGIN_OPCODE(op_get_scoped_var) {
2375 /* get_scoped_var dst(r) index(n) skip(n)
2377 Loads the contents of the index-th local from the scope skip nodes from
2378 the top of the scope chain, and places it in register dst
2380 int dst = (++vPC)->u.operand;
2381 int index = (++vPC)->u.operand;
2382 int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain;
2384 ScopeChainNode* scopeChain = callFrame->scopeChain();
2385 ScopeChainIterator iter = scopeChain->begin();
2386 ScopeChainIterator end = scopeChain->end();
2387 ASSERT(iter != end);
2390 ASSERT(iter != end);
2393 ASSERT((*iter)->isVariableObject());
2394 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2395 callFrame[dst] = scope->registerAt(index);
2399 BEGIN_OPCODE(op_put_scoped_var) {
2400 /* put_scoped_var index(n) skip(n) value(r)
2403 int index = (++vPC)->u.operand;
2404 int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain;
2405 int value = (++vPC)->u.operand;
2407 ScopeChainNode* scopeChain = callFrame->scopeChain();
2408 ScopeChainIterator iter = scopeChain->begin();
2409 ScopeChainIterator end = scopeChain->end();
2410 ASSERT(iter != end);
2413 ASSERT(iter != end);
2416 ASSERT((*iter)->isVariableObject());
2417 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2418 scope->registerAt(index) = callFrame[value].jsValue(callFrame);
2422 BEGIN_OPCODE(op_resolve_base) {
2423 /* resolve_base dst(r) property(id)
2425 Searches the scope chain for an object containing
2426 identifier property, and if one is found, writes it to
2427 register dst. If none is found, the outermost scope (which
2428 will be the global object) is stored in register dst.
2430 resolveBase(callFrame, vPC);
2435 BEGIN_OPCODE(op_resolve_with_base) {
2436 /* resolve_with_base baseDst(r) propDst(r) property(id)
2438 Searches the scope chain for an object containing
2439 identifier property, and if one is found, writes it to
2440 register srcDst, and the retrieved property value to register
2441 propDst. If the property is not found, raises an exception.
2443 This is more efficient than doing resolve_base followed by
2444 resolve, or resolve_base followed by get_by_id, as it
2445 avoids duplicate hash lookups.
2447 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
2453 BEGIN_OPCODE(op_resolve_func) {
2454 /* resolve_func baseDst(r) funcDst(r) property(id)
2456 Searches the scope chain for an object containing
2457 identifier property, and if one is found, writes the
2458 appropriate object to use as "this" when calling its
2459 properties to register baseDst; and the retrieved property
2460 value to register propDst. If the property is not found,
2461 raises an exception.
2463 This differs from resolve_with_base, because the
2464 global this value will be substituted for activations or
2465 the global object, which is the right behavior for function
2466 calls but not for other property lookup.
2468 if (UNLIKELY(!resolveBaseAndFunc(callFrame, vPC, exceptionValue)))
2474 BEGIN_OPCODE(op_get_by_id) {
2475 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2477 Generic property access: Gets the property named by identifier
2478 property from the value base, and puts the result in register dst.
2480 int dst = vPC[1].u.operand;
2481 int base = vPC[2].u.operand;
2482 int property = vPC[3].u.operand;
2484 CodeBlock* codeBlock = callFrame->codeBlock();
2485 Identifier& ident = codeBlock->identifiers[property];
2486 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2487 PropertySlot slot(baseValue);
2488 JSValuePtr result = baseValue->get(callFrame, ident, slot);
2489 VM_CHECK_EXCEPTION();
2491 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
2493 callFrame[dst] = result;
2497 BEGIN_OPCODE(op_get_by_id_self) {
2498 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2500 Cached property access: Attempts to get a cached property from the
2501 value base. If the cache misses, op_get_by_id_self reverts to
2504 int base = vPC[2].u.operand;
2505 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2507 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2508 JSCell* baseCell = asCell(baseValue);
2509 StructureID* structureID = vPC[4].u.structureID;
2511 if (LIKELY(baseCell->structureID() == structureID)) {
2512 ASSERT(baseCell->isObject());
2513 JSObject* baseObject = asObject(baseCell);
2514 int dst = vPC[1].u.operand;
2515 int offset = vPC[5].u.operand;
2517 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2518 callFrame[dst] = baseObject->getDirectOffset(offset);
2525 uncacheGetByID(callFrame->codeBlock(), vPC);
2528 BEGIN_OPCODE(op_get_by_id_proto) {
2529 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2531 Cached property access: Attempts to get a cached property from the
2532 value base's prototype. If the cache misses, op_get_by_id_proto
2533 reverts to op_get_by_id.
2535 int base = vPC[2].u.operand;
2536 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2538 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2539 JSCell* baseCell = asCell(baseValue);
2540 StructureID* structureID = vPC[4].u.structureID;
2542 if (LIKELY(baseCell->structureID() == structureID)) {
2543 ASSERT(structureID->prototypeForLookup(callFrame)->isObject());
2544 JSObject* protoObject = asObject(structureID->prototypeForLookup(callFrame));
2545 StructureID* protoStructureID = vPC[5].u.structureID;
2547 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2548 int dst = vPC[1].u.operand;
2549 int offset = vPC[6].u.operand;
2551 ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2552 callFrame[dst] = protoObject->getDirectOffset(offset);
2560 uncacheGetByID(callFrame->codeBlock(), vPC);
2563 BEGIN_OPCODE(op_get_by_id_chain) {
2564 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2566 Cached property access: Attempts to get a cached property from the
2567 value base's prototype chain. If the cache misses, op_get_by_id_chain
2568 reverts to op_get_by_id.
2570 int base = vPC[2].u.operand;
2571 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2573 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2574 JSCell* baseCell = asCell(baseValue);
2575 StructureID* structureID = vPC[4].u.structureID;
2577 if (LIKELY(baseCell->structureID() == structureID)) {
2578 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2579 size_t count = vPC[6].u.operand;
2580 RefPtr<StructureID>* end = it + count;
2582 JSObject* baseObject = asObject(baseCell);
2584 baseObject = asObject(baseObject->structureID()->prototypeForLookup(callFrame));
2585 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2589 int dst = vPC[1].u.operand;
2590 int offset = vPC[7].u.operand;
2592 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2593 callFrame[dst] = baseObject->getDirectOffset(offset);
2602 uncacheGetByID(callFrame->codeBlock(), vPC);
2605 BEGIN_OPCODE(op_get_by_id_generic) {
2606 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2608 Generic property access: Gets the property named by identifier
2609 property from the value base, and puts the result in register dst.
2611 int dst = vPC[1].u.operand;
2612 int base = vPC[2].u.operand;
2613 int property = vPC[3].u.operand;
2615 Identifier& ident = callFrame->codeBlock()->identifiers[property];
2616 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2617 PropertySlot slot(baseValue);
2618 JSValuePtr result = baseValue->get(callFrame, ident, slot);
2619 VM_CHECK_EXCEPTION();
2621 callFrame[dst] = result;
2625 BEGIN_OPCODE(op_get_array_length) {
2626 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2628 Cached property access: Gets the length of the array in register base,
2629 and puts the result in register dst. If register base does not hold
2630 an array, op_get_array_length reverts to op_get_by_id.
2633 int base = vPC[2].u.operand;
2634 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2635 if (LIKELY(isJSArray(baseValue))) {
2636 int dst = vPC[1].u.operand;
2637 callFrame[dst] = jsNumber(callFrame, asArray(baseValue)->length());
2642 uncacheGetByID(callFrame->codeBlock(), vPC);
2645 BEGIN_OPCODE(op_get_string_length) {
2646 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2648 Cached property access: Gets the length of the string in register base,
2649 and puts the result in register dst. If register base does not hold
2650 a string, op_get_string_length reverts to op_get_by_id.
2653 int base = vPC[2].u.operand;
2654 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2655 if (LIKELY(isJSString(baseValue))) {
2656 int dst = vPC[1].u.operand;
2657 callFrame[dst] = jsNumber(callFrame, asString(baseValue)->value().size());
2662 uncacheGetByID(callFrame->codeBlock(), vPC);
2665 BEGIN_OPCODE(op_put_by_id) {
2666 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2668 Generic property access: Sets the property named by identifier
2669 property, belonging to register base, to register value.
2671 Unlike many opcodes, this one does not write any output to
2675 int base = vPC[1].u.operand;
2676 int property = vPC[2].u.operand;
2677 int value = vPC[3].u.operand;
2679 CodeBlock* codeBlock = callFrame->codeBlock();
2680 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2681 Identifier& ident = codeBlock->identifiers[property];
2682 PutPropertySlot slot;
2683 baseValue->put(callFrame, ident, callFrame[value].jsValue(callFrame), slot);
2684 VM_CHECK_EXCEPTION();
2686 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
2691 BEGIN_OPCODE(op_put_by_id_transition) {
2692 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2694 Cached property access: Attempts to set a new property with a cached transition
2695 property named by identifier property, belonging to register base,
2696 to register value. If the cache misses, op_put_by_id_transition
2697 reverts to op_put_by_id_generic.
2699 Unlike many opcodes, this one does not write any output to
2702 int base = vPC[1].u.operand;
2703 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2705 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2706 JSCell* baseCell = asCell(baseValue);
2707 StructureID* oldStructureID = vPC[4].u.structureID;
2708 StructureID* newStructureID = vPC[5].u.structureID;
2710 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2711 ASSERT(baseCell->isObject());
2712 JSObject* baseObject = asObject(baseCell);
2714 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2716 JSValuePtr proto = baseObject->structureID()->prototypeForLookup(callFrame);
2717 while (!proto->isNull()) {
2718 if (UNLIKELY(asObject(proto)->structureID() != (*it).get())) {
2719 uncachePutByID(callFrame->codeBlock(), vPC);
2723 proto = asObject(proto)->structureID()->prototypeForLookup(callFrame);
2726 baseObject->transitionTo(newStructureID);
2728 int value = vPC[3].u.operand;
2729 unsigned offset = vPC[7].u.operand;
2730 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifiers[vPC[2].u.operand])) == offset);
2731 baseObject->putDirectOffset(offset, callFrame[value].jsValue(callFrame));
2738 uncachePutByID(callFrame->codeBlock(), vPC);
2741 BEGIN_OPCODE(op_put_by_id_replace) {
2742 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2744 Cached property access: Attempts to set a pre-existing, cached
2745 property named by identifier property, belonging to register base,
2746 to register value. If the cache misses, op_put_by_id_replace
2747 reverts to op_put_by_id.
2749 Unlike many opcodes, this one does not write any output to
2752 int base = vPC[1].u.operand;
2753 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2755 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2756 JSCell* baseCell = asCell(baseValue);
2757 StructureID* structureID = vPC[4].u.structureID;
2759 if (LIKELY(baseCell->structureID() == structureID)) {
2760 ASSERT(baseCell->isObject());
2761 JSObject* baseObject = asObject(baseCell);
2762 int value = vPC[3].u.operand;
2763 unsigned offset = vPC[5].u.operand;
2765 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifiers[vPC[2].u.operand])) == offset);
2766 baseObject->putDirectOffset(offset, callFrame[value].jsValue(callFrame));
2773 uncachePutByID(callFrame->codeBlock(), vPC);
2776 BEGIN_OPCODE(op_put_by_id_generic) {
2777 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2779 Generic property access: Sets the property named by identifier
2780 property, belonging to register base, to register value.
2782 Unlike many opcodes, this one does not write any output to
2785 int base = vPC[1].u.operand;
2786 int property = vPC[2].u.operand;
2787 int value = vPC[3].u.operand;
2789 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2790 Identifier& ident = callFrame->codeBlock()->identifiers[property];
2791 PutPropertySlot slot;
2792 baseValue->put(callFrame, ident, callFrame[value].jsValue(callFrame), slot);
2793 VM_CHECK_EXCEPTION();
2798 BEGIN_OPCODE(op_del_by_id) {
2799 /* del_by_id dst(r) base(r) property(id)
2801 Converts register base to Object, deletes the property
2802 named by identifier property from the object, and writes a
2803 boolean indicating success (if true) or failure (if false)
2806 int dst = (++vPC)->u.operand;
2807 int base = (++vPC)->u.operand;
2808 int property = (++vPC)->u.operand;
2810 JSObject* baseObj = callFrame[base].jsValue(callFrame)->toObject(callFrame);
2811 Identifier& ident = callFrame->codeBlock()->identifiers[property];
2812 JSValuePtr result = jsBoolean(baseObj->deleteProperty(callFrame, ident));
2813 VM_CHECK_EXCEPTION();
2814 callFrame[dst] = result;
2818 BEGIN_OPCODE(op_get_by_val) {
2819 /* get_by_val dst(r) base(r) property(r)
2821 Converts register base to Object, gets the property named
2822 by register property from the object, and puts the result
2823 in register dst. property is nominally converted to string
2824 but numbers are treated more efficiently.
2826 int dst = (++vPC)->u.operand;
2827 int base = (++vPC)->u.operand;
2828 int property = (++vPC)->u.operand;
2830 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2831 JSValuePtr subscript = callFrame[property].jsValue(callFrame);
2836 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2837 if (LIKELY(isUInt32)) {
2838 if (isJSArray(baseValue)) {
2839 JSArray* jsArray = asArray(baseValue);
2840 if (jsArray->canGetIndex(i))
2841 result = jsArray->getIndex(i);
2843 result = jsArray->JSArray::get(callFrame, i);
2844 } else if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
2845 result = asString(baseValue)->getIndex(&callFrame->globalData(), i);
2847 result = baseValue->get(callFrame, i);
2849 Identifier property(callFrame, subscript->toString(callFrame));
2850 result = baseValue->get(callFrame, property);
2853 VM_CHECK_EXCEPTION();
2854 callFrame[dst] = result;
2858 BEGIN_OPCODE(op_put_by_val) {
2859 /* put_by_val base(r) property(r) value(r)
2861 Sets register value on register base as the property named
2862 by register property. Base is converted to object
2863 first. register property is nominally converted to string
2864 but numbers are treated more efficiently.
2866 Unlike many opcodes, this one does not write any output to
2869 int base = (++vPC)->u.operand;
2870 int property = (++vPC)->u.operand;
2871 int value = (++vPC)->u.operand;
2873 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);
2874 JSValuePtr subscript = callFrame[property].jsValue(callFrame);
2878 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2879 if (LIKELY(isUInt32)) {
2880 if (isJSArray(baseValue)) {
2881 JSArray* jsArray = asArray(baseValue);
2882 if (jsArray->canSetIndex(i))
2883 jsArray->setIndex(i, callFrame[value].jsValue(callFrame));
2885 jsArray->JSArray::put(callFrame, i, callFrame[value].jsValue(callFrame));
2887 baseValue->put(callFrame, i, callFrame[value].jsValue(callFrame));
2889 Identifier property(callFrame, subscript->toString(callFrame));
2890 if (!globalData->exception) { // Don't put to an object if toString threw an exception.
2891 PutPropertySlot slot;
2892 baseValue->put(callFrame, property, callFrame[value].jsValue(callFrame), slot);
2896 VM_CHECK_EXCEPTION();
2900 BEGIN_OPCODE(op_del_by_val) {
2901 /* del_by_val dst(r) base(r) property(r)
2903 Converts register base to Object, deletes the property
2904 named by register property from the object, and writes a
2905 boolean indicating success (if true) or failure (if false)
2908 int dst = (++vPC)->u.operand;
2909 int base = (++vPC)->u.operand;
2910 int property = (++vPC)->u.operand;
2912 JSObject* baseObj = callFrame[base].jsValue(callFrame)->toObject(callFrame); // may throw
2914 JSValuePtr subscript = callFrame[property].jsValue(callFrame);
2917 if (subscript->getUInt32(i))
2918 result = jsBoolean(baseObj->deleteProperty(callFrame, i));
2920 VM_CHECK_EXCEPTION();
2921 Identifier property(callFrame, subscript->toString(callFrame));
2922 VM_CHECK_EXCEPTION();
2923 result = jsBoolean(baseObj->deleteProperty(callFrame, property));
2926 VM_CHECK_EXCEPTION();
2927 callFrame[dst] = result;
2931 BEGIN_OPCODE(op_put_by_index) {
2932 /* put_by_index base(r) property(n) value(r)
2934 Sets register value on register base as the property named
2935 by the immediate number property. Base is converted to
2938 Unlike many opcodes, this one does not write any output to
2941 This opcode is mainly used to initialize array literals.
2943 int base = (++vPC)->u.operand;
2944 unsigned property = (++vPC)->u.operand;
2945 int value = (++vPC)->u.operand;
2947 callFrame[base].jsValue(callFrame)->put(callFrame, property, callFrame[value].jsValue(callFrame));
2952 BEGIN_OPCODE(op_loop) {
2953 /* loop target(offset)
2955 Jumps unconditionally to offset target from the current
2958 Additionally this loop instruction may terminate JS execution is
2959 the JS timeout is reached.
2961 #if DUMP_OPCODE_STATS
2962 OpcodeStats::resetLastInstruction();
2964 int target = (++vPC)->u.operand;
2965 CHECK_FOR_TIMEOUT();
2969 BEGIN_OPCODE(op_jmp) {
2970 /* jmp target(offset)
2972 Jumps unconditionally to offset target from the current
2975 #if DUMP_OPCODE_STATS
2976 OpcodeStats::resetLastInstruction();
2978 int target = (++vPC)->u.operand;
2983 BEGIN_OPCODE(op_loop_if_true) {
2984 /* loop_if_true cond(r) target(offset)
2986 Jumps to offset target from the current instruction, if and
2987 only if register cond converts to boolean as true.
2989 Additionally this loop instruction may terminate JS execution is
2990 the JS timeout is reached.
2992 int cond = (++vPC)->u.operand;
2993 int target = (++vPC)->u.operand;
2994 if (callFrame[cond].jsValue(callFrame)->toBoolean(callFrame)) {
2996 CHECK_FOR_TIMEOUT();
3003 BEGIN_OPCODE(op_jtrue) {
3004 /* jtrue cond(r) target(offset)
3006 Jumps to offset target from the current instruction, if and
3007 only if register cond converts to boolean as true.
3009 int cond = (++vPC)->u.operand;
3010 int target = (++vPC)->u.operand;
3011 if (callFrame[cond].jsValue(callFrame)->toBoolean(callFrame)) {
3019 BEGIN_OPCODE(op_jfalse) {
3020 /* jfalse cond(r) target(offset)
3022 Jumps to offset target from the current instruction, if and
3023 only if register cond converts to boolean as false.
3025 int cond = (++vPC)->u.operand;
3026 int target = (++vPC)->u.operand;
3027 if (!callFrame[cond].jsValue(callFrame)->toBoolean(callFrame)) {
3035 BEGIN_OPCODE(op_jeq_null) {
3036 /* jeq_null src(r) target(offset)
3038 Jumps to offset target from the current instruction, if and
3039 only if register src is null.
3041 int src = (++vPC)->u.operand;
3042 int target = (++vPC)->u.operand;
3043 JSValuePtr srcValue = callFrame[src].jsValue(callFrame);
3045 if (srcValue->isUndefinedOrNull() || (!JSImmediate::isImmediate(srcValue) && srcValue->asCell()->structureID()->typeInfo().masqueradesAsUndefined())) {
3053 BEGIN_OPCODE(op_jneq_null) {
3054 /* jneq_null src(r) target(offset)
3056 Jumps to offset target from the current instruction, if and
3057 only if register src is not null.
3059 int src = (++vPC)->u.operand;
3060 int target = (++vPC)->u.operand;
3061 JSValuePtr srcValue = callFrame[src].jsValue(callFrame);
3063 if (!srcValue->isUndefinedOrNull() || (!JSImmediate::isImmediate(srcValue) && !srcValue->asCell()->structureID()->typeInfo().masqueradesAsUndefined())) {
3071 BEGIN_OPCODE(op_loop_if_less) {
3072 /* loop_if_less src1(r) src2(r) target(offset)
3074 Checks whether register src1 is less than register src2, as
3075 with the ECMAScript '<' operator, and then jumps to offset
3076 target from the current instruction, if and only if the
3077 result of the comparison is true.
3079 Additionally this loop instruction may terminate JS execution is
3080 the JS timeout is reached.
3082 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3083 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3084 int target = (++vPC)->u.operand;
3086 bool result = jsLess(callFrame, src1, src2);
3087 VM_CHECK_EXCEPTION();
3091 CHECK_FOR_TIMEOUT();
3098 BEGIN_OPCODE(op_loop_if_lesseq) {
3099 /* loop_if_lesseq src1(r) src2(r) target(offset)
3101 Checks whether register src1 is less than or equal to register
3102 src2, as with the ECMAScript '<=' operator, and then jumps to
3103 offset target from the current instruction, if and only if the
3104 result of the comparison is true.
3106 Additionally this loop instruction may terminate JS execution is
3107 the JS timeout is reached.
3109 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3110 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3111 int target = (++vPC)->u.operand;
3113 bool result = jsLessEq(callFrame, src1, src2);
3114 VM_CHECK_EXCEPTION();
3118 CHECK_FOR_TIMEOUT();
3125 BEGIN_OPCODE(op_jnless) {
3126 /* jnless src1(r) src2(r) target(offset)
3128 Checks whether register src1 is less than register src2, as
3129 with the ECMAScript '<' operator, and then jumps to offset
3130 target from the current instruction, if and only if the
3131 result of the comparison is false.
3133 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3134 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3135 int target = (++vPC)->u.operand;
3137 bool result = jsLess(callFrame, src1, src2);
3138 VM_CHECK_EXCEPTION();
3148 BEGIN_OPCODE(op_switch_imm) {
3149 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3151 Performs a range checked switch on the scrutinee value, using
3152 the tableIndex-th immediate switch jump table. If the scrutinee value
3153 is an immediate number in the range covered by the referenced jump
3154 table, and the value at jumpTable[scrutinee value] is non-zero, then
3155 that value is used as the jump offset, otherwise defaultOffset is used.
3157 int tableIndex = (++vPC)->u.operand;
3158 int defaultOffset = (++vPC)->u.operand;
3159 JSValuePtr scrutinee = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3160 if (!JSImmediate::isNumber(scrutinee))
3161 vPC += defaultOffset;
3163 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3164 vPC += callFrame->codeBlock()->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
3168 BEGIN_OPCODE(op_switch_char) {
3169 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3171 Performs a range checked switch on the scrutinee value, using
3172 the tableIndex-th character switch jump table. If the scrutinee value
3173 is a single character string in the range covered by the referenced jump
3174 table, and the value at jumpTable[scrutinee value] is non-zero, then
3175 that value is used as the jump offset, otherwise defaultOffset is used.
3177 int tableIndex = (++vPC)->u.operand;
3178 int defaultOffset = (++vPC)->u.operand;
3179 JSValuePtr scrutinee = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3180 if (!scrutinee->isString())
3181 vPC += defaultOffset;
3183 UString::Rep* value = asString(scrutinee)->value().rep();
3184 if (value->size() != 1)
3185 vPC += defaultOffset;
3187 vPC += callFrame->codeBlock()->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
3191 BEGIN_OPCODE(op_switch_string) {
3192 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3194 Performs a sparse hashmap based switch on the value in the scrutinee
3195 register, using the tableIndex-th string switch jump table. If the
3196 scrutinee value is a string that exists as a key in the referenced
3197 jump table, then the value associated with the string is used as the
3198 jump offset, otherwise defaultOffset is used.
3200 int tableIndex = (++vPC)->u.operand;
3201 int defaultOffset = (++vPC)->u.operand;
3202 JSValuePtr scrutinee = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3203 if (!scrutinee->isString())
3204 vPC += defaultOffset;
3206 vPC += callFrame->codeBlock()->stringSwitchJumpTables[tableIndex].offsetForValue(asString(scrutinee)->value().rep(), defaultOffset);
3209 BEGIN_OPCODE(op_new_func) {
3210 /* new_func dst(r) func(f)
3212 Constructs a new Function instance from function func and
3213 the current scope chain using the original Function
3214 constructor, using the rules for function declarations, and
3215 puts the result in register dst.
3217 int dst = (++vPC)->u.operand;
3218 int func = (++vPC)->u.operand;
3220 callFrame[dst] = callFrame->codeBlock()->functions[func]->makeFunction(callFrame, callFrame->scopeChain());
3225 BEGIN_OPCODE(op_new_func_exp) {
3226 /* new_func_exp dst(r) func(f)
3228 Constructs a new Function instance from function func and
3229 the current scope chain using the original Function
3230 constructor, using the rules for function expressions, and
3231 puts the result in register dst.
3233 int dst = (++vPC)->u.operand;
3234 int func = (++vPC)->u.operand;
3236 callFrame[dst] = callFrame->codeBlock()->functionExpressions[func]->makeFunction(callFrame, callFrame->scopeChain());
3241 BEGIN_OPCODE(op_call_eval) {
3242 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3244 Call a function named "eval" with no explicit "this" value
3245 (which may therefore be the eval operator). If register
3246 thisVal is the global object, and register func contains
3247 that global object's original global eval function, then
3248 perform the eval operator in local scope (interpreting
3249 the argument registers as for the "call"
3250 opcode). Otherwise, act exactly as the "call" opcode would.
3253 int dst = vPC[1].u.operand;
3254 int func = vPC[2].u.operand;
3255 int thisVal = vPC[3].u.operand;
3256 int firstArg = vPC[4].u.operand;
3257 int argCount = vPC[5].u.operand;
3259 JSValuePtr funcVal = callFrame[func].jsValue(callFrame);
3260 JSValuePtr baseVal = callFrame[thisVal].jsValue(callFrame);
3262 ScopeChainNode* scopeChain = callFrame->scopeChain();
3263 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
3264 JSObject* thisObject = asObject(callFrame[callFrame->codeBlock()->thisRegister].jsValue(callFrame));
3265 JSValuePtr result = callEval(callFrame, thisObject, scopeChain, registerFile, firstArg, argCount, exceptionValue);
3269 callFrame[dst] = result;
3275 // We didn't find the blessed version of eval, so reset vPC and process
3276 // this instruction as a normal function call, supplying the proper 'this'
3278 callFrame[thisVal] = baseVal->toThisObject(callFrame);
3280 #if HAVE(COMPUTED_GOTO)
3281 // Hack around gcc performance quirk by performing an indirect goto
3282 // in order to set the vPC -- attempting to do so directly results in a
3283 // significant regression.
3284 goto *op_call_indirect; // indirect goto -> op_call
3286 // fall through to op_call
3288 BEGIN_OPCODE(op_call) {
3289 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n) registerOffset(n)
3291 Perform a function call. Specifically, call register func
3292 with a "this" value of register thisVal, and put the result
3295 The arguments start at register firstArg and go up to
3296 argCount, but the "this" value is considered an implicit
3297 first argument, so the argCount should be one greater than
3298 the number of explicit arguments passed, and the register
3299 after firstArg should contain the actual first
3300 argument. This opcode will copy from the thisVal register
3301 to the firstArg register, unless the register index of
3302 thisVal is the special missing this object marker, which is
3303 2^31-1; in that case, the global object will be used as the
3306 If func is a native code function, then this opcode calls
3307 it and returns the value immediately.
3309 But if it is a JS function, then the current scope chain
3310 and code block is set to the function's, and we slide the
3311 register window so that the arguments would form the first
3312 few local registers of the called function's register
3313 window. In addition, a call frame header is written
3314 immediately before the arguments; see the call frame
3315 documentation for an explanation of how many registers a
3316 call frame takes and what they contain. That many registers
3317 before the firstArg register will be overwritten by the
3318 call. In addition, any registers higher than firstArg +
3319 argCount may be overwritten. Once this setup is complete,
3320 execution continues from the called function's first
3321 argument, and does not return until a "ret" opcode is
3325 int dst = vPC[1].u.operand;
3326 int func = vPC[2].u.operand;
3327 int thisVal = vPC[3].u.operand;
3328 int firstArg = vPC[4].u.operand;
3329 int argCount = vPC[5].u.operand;
3330 int registerOffset = vPC[6].u.operand;
3332 JSValuePtr v = callFrame[func].jsValue(callFrame);
3335 CallType callType = v->getCallData(callData);
3337 if (callType == CallTypeJS) {
3338 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3339 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3340 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3342 callFrame[firstArg] = thisVal == missingThisObjectMarker() ? callFrame->globalThisValue() : callFrame[thisVal].jsValue(callFrame);
3344 CallFrame* previousCallFrame = callFrame;
3346 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3347 if (UNLIKELY(!callFrame)) {
3348 callFrame = previousCallFrame;
3349 exceptionValue = createStackOverflowError(callFrame);
3353 callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3354 vPC = newCodeBlock->instructions.begin();
3356 #if DUMP_OPCODE_STATS
3357 OpcodeStats::resetLastInstruction();
3363 if (callType == CallTypeHost) {
3364 JSValuePtr thisValue = thisVal == missingThisObjectMarker() ? callFrame->globalThisValue() : callFrame[thisVal].jsValue(callFrame);
3365 ArgList args(callFrame->registers() + firstArg + 1, argCount - 1);
3367 ScopeChainNode* scopeChain = callFrame->scopeChain();
3368 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3369 newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
3371 MACHINE_SAMPLING_callingHostFunction();
3373 JSValuePtr returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
3374 VM_CHECK_EXCEPTION();
3376 callFrame[dst] = returnValue;
3382 ASSERT(callType == CallTypeNone);
3384 exceptionValue = createNotAFunctionError(callFrame, v, vPC, callFrame->codeBlock());
3387 BEGIN_OPCODE(op_tear_off_activation) {
3388 /* tear_off_activation activation(r)
3390 Copy all locals and parameters to new memory allocated on
3391 the heap, and make the passed activation use this memory
3392 in the future when looking up entries in the symbol table.
3393 If there is an 'arguments' object, then it will also use
3394 this memory for storing the named parameters, but not any
3397 This opcode should only be used immediately before op_ret.
3400 int src = (++vPC)->u.operand;
3401 ASSERT(callFrame->codeBlock()->needsFullScopeChain);
3403 asActivation(callFrame[src].getJSValue())->copyRegisters(callFrame->optionalCalleeArguments());
3408 BEGIN_OPCODE(op_tear_off_arguments) {
3409 /* tear_off_arguments
3411 Copy all arguments to new memory allocated on the heap,
3412 and make the 'arguments' object use this memory in the
3413 future when looking up named parameters, but not any
3414 extra arguments. If an activation object exists for the
3415 current function context, then the tear_off_activation
3416 opcode should be used instead.
3418 This opcode should only be used immediately before op_ret.
3421 ASSERT(callFrame->codeBlock()->usesArguments && !callFrame->codeBlock()->needsFullScopeChain);
3423 callFrame->optionalCalleeArguments()->copyRegisters();
3428 BEGIN_OPCODE(op_ret) {
3431 Return register result as the return value of the current
3432 function call, writing it into the caller's expected return
3433 value register. In addition, unwind one call frame and
3434 restore the scope chain, code block instruction pointer and
3435 register base to those of the calling function.
3438 int result = (++vPC)->u.operand;
3440 if (callFrame->codeBlock()->needsFullScopeChain)
3441 callFrame->scopeChain()->deref();
3443 JSValuePtr returnValue = callFrame[result].jsValue(callFrame);
3445 vPC = callFrame->returnPC();
3446 int dst = callFrame->returnValueRegister();
3447 callFrame = callFrame->callerFrame();
3449 if (callFrame->hasHostCallFrameFlag())
3452 callFrame[dst] = returnValue;
3456 BEGIN_OPCODE(op_enter) {
3459 Initializes local variables to undefined and fills constant
3460 registers with their values. If the code block requires an
3461 activation, enter_with_activation should be used instead.
3463 This opcode should only be used at the beginning of a code
3468 CodeBlock* codeBlock = callFrame->codeBlock();
3470 for (size_t count = codeBlock->numVars; i < count; ++i)
3471 callFrame[i] = jsUndefined();
3473 for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
3474 callFrame[i] = codeBlock->constantRegisters[j];
3479 BEGIN_OPCODE(op_enter_with_activation) {
3480 /* enter_with_activation dst(r)
3482 Initializes local variables to undefined, fills constant
3483 registers with their values, creates an activation object,
3484 and places the new activation both in dst and at the top
3485 of the scope chain. If the code block does not require an
3486 activation, enter should be used instead.
3488 This opcode should only be used at the beginning of a code
3493 CodeBlock* codeBlock = callFrame->codeBlock();
3495 for (size_t count = codeBlock->numVars; i < count; ++i)
3496 callFrame[i] = jsUndefined();
3498 for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
3499 callFrame[i] = codeBlock->constantRegisters[j];
3501 int dst = (++vPC)->u.operand;
3502 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionBodyNode*>(codeBlock->ownerNode));
3503 callFrame[dst] = activation;
3504 callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation));
3509 BEGIN_OPCODE(op_convert_this) {
3510 /* convert_this this(r)
3512 Takes the value in the 'this' register, converts it to a
3513 value that is suitable for use as the 'this' value, and
3514 stores it in the 'this' register. This opcode is emitted
3515 to avoid doing the conversion in the caller unnecessarily.
3517 This opcode should only be used at the beginning of a code
3521 int thisRegister = (++vPC)->u.operand;
3522 JSValuePtr thisVal = callFrame[thisRegister].getJSValue();
3523 if (thisVal->needsThisConversion())
3524 callFrame[thisRegister] = thisVal->toThisObject(callFrame);
3529 BEGIN_OPCODE(op_create_arguments) {
3532 Creates the 'arguments' object and places it in both the
3533 'arguments' call frame slot and the local 'arguments'
3536 This opcode should only be used at the beginning of a code
3540 Arguments* arguments = new (globalData) Arguments(callFrame);
3541 callFrame->setCalleeArguments(arguments);
3542 callFrame[RegisterFile::ArgumentsRegister] = arguments;
3547 BEGIN_OPCODE(op_construct) {
3548 /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n) registerOffset(n)
3550 Invoke register "constr" as a constructor. For JS
3551 functions, the calling convention is exactly as for the
3552 "call" opcode, except that the "this" value is a newly
3553 created Object. For native constructors, a null "this"
3554 value is passed. In either case, the firstArg and argCount
3555 registers are interpreted as for the "call" opcode.
3557 Register constrProto must contain the prototype property of
3558 register constsr. This is to enable polymorphic inline
3559 caching of this lookup.
3562 int dst = vPC[1].u.operand;
3563 int constr = vPC[2].u.operand;
3564 int constrProto = vPC[3].u.operand;
3565 int firstArg = vPC[4].u.operand;
3566 int argCount = vPC[5].u.operand;
3567 int registerOffset = vPC[6].u.operand;
3569 JSValuePtr v = callFrame[constr].jsValue(callFrame);
3571 ConstructData constructData;
3572 ConstructType constructType = v->getConstructData(constructData);
3574 if (constructType == ConstructTypeJS) {
3575 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3576 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3577 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3579 StructureID* structure;
3580 JSValuePtr prototype = callFrame[constrProto].jsValue(callFrame);
3581 if (prototype->isObject())
3582 structure = asObject(prototype)->inheritorID();
3584 structure = callDataScopeChain->globalObject()->emptyObjectStructure();
3585 JSObject* newObject = new (globalData) JSObject(structure);
3587 callFrame[firstArg] = newObject; // "this" value
3589 CallFrame* previousCallFrame = callFrame;
3591 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3592 if (UNLIKELY(!callFrame)) {
3593 callFrame = previousCallFrame;
3594 exceptionValue = createStackOverflowError(callFrame);
3598 callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3599 vPC = newCodeBlock->instructions.begin();
3601 #if DUMP_OPCODE_STATS
3602 OpcodeStats::resetLastInstruction();
3608 if (constructType == ConstructTypeHost) {
3609 ArgList args(callFrame->registers() + firstArg + 1, argCount - 1);
3611 ScopeChainNode* scopeChain = callFrame->scopeChain();
3612 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3613 newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
3615 MACHINE_SAMPLING_callingHostFunction();
3617 JSValuePtr returnValue = constructData.native.function(newCallFrame, asObject(v), args);
3619 VM_CHECK_EXCEPTION();
3620 callFrame[dst] = returnValue;
3626 ASSERT(constructType == ConstructTypeNone);
3628 exceptionValue = createNotAConstructorError(callFrame, v, vPC, callFrame->codeBlock());
3631 BEGIN_OPCODE(op_construct_verify) {
3632 /* construct_verify dst(r) override(r)
3634 Verifies that register dst holds an object. If not, moves
3635 the object in register override to register dst.
3638 int dst = vPC[1].u.operand;;
3639 if (LIKELY(callFrame[dst].jsValue(callFrame)->isObject())) {
3644 int override = vPC[2].u.operand;
3645 callFrame[dst] = callFrame[override];
3650 BEGIN_OPCODE(op_push_scope) {
3651 /* push_scope scope(r)
3653 Converts register scope to object, and pushes it onto the top
3654 of the current scope chain.
3656 int scope = (++vPC)->u.operand;
3657 JSValuePtr v = callFrame[scope].jsValue(callFrame);
3658 JSObject* o = v->toObject(callFrame);
3659 VM_CHECK_EXCEPTION();
3661 callFrame->setScopeChain(callFrame->scopeChain()->push(o));
3666 BEGIN_OPCODE(op_pop_scope) {
3669 Removes the top item from the current scope chain.
3671 callFrame->setScopeChain(callFrame->scopeChain()->pop());
3676 BEGIN_OPCODE(op_get_pnames) {
3677 /* get_pnames dst(r) base(r)
3679 Creates a property name list for register base and puts it
3680 in register dst. This is not a true JavaScript value, just
3681 a synthetic value used to keep the iteration state in a
3684 int dst = (++vPC)->u.operand;
3685 int base = (++vPC)->u.operand;
3687 callFrame[dst] = JSPropertyNameIterator::create(callFrame, callFrame[base].jsValue(callFrame));
3691 BEGIN_OPCODE(op_next_pname) {
3692 /* next_pname dst(r) iter(r) target(offset)
3694 Tries to copies the next name from property name list in
3695 register iter. If there are names left, then copies one to
3696 register dst, and jumps to offset target. If there are none
3697 left, invalidates the iterator and continues to the next
3700 int dst = (++vPC)->u.operand;
3701 int iter = (++vPC)->u.operand;
3702 int target = (++vPC)->u.operand;
3704 JSPropertyNameIterator* it = callFrame[iter].propertyNameIterator();
3705 if (JSValuePtr temp = it->next(callFrame)) {
3706 CHECK_FOR_TIMEOUT();
3707 callFrame[dst] = temp;
3716 BEGIN_OPCODE(op_jmp_scopes) {
3717 /* jmp_scopes count(n) target(offset)
3719 Removes the a number of items from the current scope chain
3720 specified by immediate number count, then jumps to offset
3723 int count = (++vPC)->u.operand;
3724 int target = (++vPC)->u.operand;
3726 ScopeChainNode* tmp = callFrame->scopeChain();
3729 callFrame->setScopeChain(tmp);
3734 #if HAVE(COMPUTED_GOTO)
3736 goto *(&&skip_new_scope);
3738 BEGIN_OPCODE(op_push_new_scope) {
3739 /* new_scope dst(r) property(id) value(r)
3741 Constructs a new StaticScopeObject with property set to value. That scope
3742 object is then pushed onto the ScopeChain. The scope object is then stored
3745 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));
3750 #if HAVE(COMPUTED_GOTO)
3753 BEGIN_OPCODE(op_catch) {
3756 Retrieves the VMs current exception and puts it in register
3757 ex. This is only valid after an exception has been raised,
3758 and usually forms the beginning of an exception handler.
3760 ASSERT(exceptionValue);
3761 ASSERT(!globalData->exception);
3762 int ex = (++vPC)->u.operand;
3763 callFrame[ex] = exceptionValue;
3764 exceptionValue = noValue();
3769 BEGIN_OPCODE(op_throw) {
3772 Throws register ex as an exception. This involves three
3773 steps: first, it is set as the current exception in the
3774 VM's internal state, then the stack is unwound until an
3775 exception handler or a native code boundary is found, and
3776 then control resumes at the exception handler if any or
3777 else the script returns control to the nearest native caller.
3780 int ex = (++vPC)->u.operand;
3781 exceptionValue = callFrame[ex].jsValue(callFrame);
3783 handlerVPC = throwException(callFrame, exceptionValue, vPC, true);
3785 *exception = exceptionValue;
3789 #if HAVE(COMPUTED_GOTO)
3790 // Hack around gcc performance quirk by performing an indirect goto
3791 // in order to set the vPC -- attempting to do so directly results in a
3792 // significant regression.
3793 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
3801 BEGIN_OPCODE(op_unexpected_load) {
3802 /* unexpected_load load dst(r) src(k)
3804 Copies constant src to register dst.
3806 int dst = (++vPC)->u.operand;
3807 int src = (++vPC)->u.operand;
3808 callFrame[dst] = callFrame->codeBlock()->unexpectedConstants[src];
3813 BEGIN_OPCODE(op_new_error) {
3814 /* new_error dst(r) type(n) message(k)
3816 Constructs a new Error instance using the original
3817 constructor, using immediate number n as the type and
3818 constant message as the message string. The result is
3819 written to register dst.
3821 int dst = (++vPC)->u.operand;
3822 int type = (++vPC)->u.operand;
3823 int message = (++vPC)->u.operand;
3825 CodeBlock* codeBlock = callFrame->codeBlock();
3826 callFrame[dst] = Error::create(callFrame, (ErrorType)type, codeBlock->unexpectedConstants[message]->toString(callFrame), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->sourceURL());
3831 BEGIN_OPCODE(op_end) {
3834 Return register result as the value of a global or eval
3835 program. Return control to the calling native code.
3838 if (callFrame->codeBlock()->needsFullScopeChain) {
3839 ScopeChainNode* scopeChain = callFrame->scopeChain();
3840 ASSERT(scopeChain->refCount > 1);
3841 scopeChain->deref();
3843 int result = (++vPC)->u.operand;
3844 return callFrame[result].jsValue(callFrame);
3846 BEGIN_OPCODE(op_put_getter) {
3847 /* put_getter base(r) property(id) function(r)
3849 Sets register function on register base as the getter named
3850 by identifier property. Base and function are assumed to be
3851 objects as this op should only be used for getters defined
3852 in object literal form.
3854 Unlike many opcodes, this one does not write any output to
3857 int base = (++vPC)->u.operand;
3858 int property = (++vPC)->u.operand;
3859 int function = (++vPC)->u.operand;
3861 ASSERT(callFrame[base].jsValue(callFrame)->isObject());
3862 JSObject* baseObj = asObject(callFrame[base].jsValue(callFrame));
3863 Identifier& ident = callFrame->codeBlock()->identifiers[property];
3864 ASSERT(callFrame[function].jsValue(callFrame)->isObject());
3865 baseObj->defineGetter(callFrame, ident, asObject(callFrame[function].jsValue(callFrame)));
3870 BEGIN_OPCODE(op_put_setter) {
3871 /* put_setter base(r) property(id) function(r)
3873 Sets register function on register base as the setter named
3874 by identifier property. Base and function are assumed to be
3875 objects as this op should only be used for setters defined
3876 in object literal form.
3878 Unlike many opcodes, this one does not write any output to
3881 int base = (++vPC)->u.operand;
3882 int property = (++vPC)->u.operand;
3883 int function = (++vPC)->u.operand;
3885 ASSERT(callFrame[base].jsValue(callFrame)->isObject());
3886 JSObject* baseObj = asObject(callFrame[base].jsValue(callFrame));
3887 Identifier& ident = callFrame->codeBlock()->identifiers[property];
3888 ASSERT(callFrame[function].jsValue(callFrame)->isObject());
3889 baseObj->defineSetter(callFrame, ident, asObject(callFrame[function].jsValue(callFrame)));
3894 BEGIN_OPCODE(op_jsr) {
3895 /* jsr retAddrDst(r) target(offset)
3897 Places the address of the next instruction into the retAddrDst
3898 register and jumps to offset target from the current instruction.
3900 int retAddrDst = (++vPC)->u.operand;
3901 int target = (++vPC)->u.operand;
3902 callFrame[retAddrDst] = vPC + 1;
3907 BEGIN_OPCODE(op_sret) {
3908 /* sret retAddrSrc(r)
3910 Jumps to the address stored in the retAddrSrc register. This
3911 differs from op_jmp because the target address is stored in a
3912 register, not as an immediate.
3914 int retAddrSrc = (++vPC)->u.operand;
3915 vPC = callFrame[retAddrSrc].vPC();
3918 BEGIN_OPCODE(op_debug) {
3919 /* debug debugHookID(n) firstLine(n) lastLine(n)
3921 Notifies the debugger of the current state of execution. This opcode
3922 is only generated while the debugger is attached.
3924 int debugHookID = (++vPC)->u.operand;
3925 int firstLine = (++vPC)->u.operand;
3926 int lastLine = (++vPC)->u.operand;
3928 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3933 BEGIN_OPCODE(op_profile_will_call) {
3934 /* op_profile_will_call function(r)
3936 Notifies the profiler of the beginning of a function call. This opcode
3937 is only generated if developer tools are enabled.
3939 int function = vPC[1].u.operand;
3941 if (*enabledProfilerReference)
3942 (*enabledProfilerReference)->willExecute(callFrame, callFrame[function].jsValue(callFrame));
3947 BEGIN_OPCODE(op_profile_did_call) {
3948 /* op_profile_did_call function(r)
3950 Notifies the profiler of the end of a function call. This opcode
3951 is only generated if developer tools are enabled.
3953 int function = vPC[1].u.operand;
3955 if (*enabledProfilerReference)
3956 (*enabledProfilerReference)->didExecute(callFrame, callFrame[function].jsValue(callFrame));
3962 globalData->exception = noValue();
3964 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3965 // cannot fathom if we don't assign to the exceptionValue before branching)
3966 exceptionValue = createInterruptedExecutionException(globalData);
3968 handlerVPC = throwException(callFrame, exceptionValue, vPC, false);
3970 *exception = exceptionValue;
3977 #if !HAVE(COMPUTED_GOTO)
3978 } // iterator loop ends
3982 #undef VM_CHECK_EXCEPTION
3983 #undef CHECK_FOR_TIMEOUT
3986 JSValuePtr Machine::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
3988 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
3989 if (!functionCallFrame)
3992 CodeBlock* codeBlock = functionCallFrame->codeBlock();
3993 if (codeBlock->usesArguments) {
3994 ASSERT(codeBlock->codeType == FunctionCode);
3995 SymbolTable& symbolTable = static_cast<FunctionBodyNode*>(codeBlock->ownerNode)->symbolTable();
3996 int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();
3997 return functionCallFrame[argumentsIndex].jsValue(callFrame);
4000 Arguments* arguments = functionCallFrame->optionalCalleeArguments();
4002 arguments = new (functionCallFrame) Arguments(functionCallFrame);
4003 arguments->copyRegisters();
4004 callFrame->setCalleeArguments(arguments);
4010 JSValuePtr Machine::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const
4012 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
4013 if (!functionCallFrame)
4016 CallFrame* callerFrame = functionCallFrame->callerFrame();
4017 if (callerFrame->hasHostCallFrameFlag())
4020 JSValuePtr caller = callerFrame->callee();
4027 void Machine::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValuePtr& function) const
4029 function = noValue();