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"
60 #include <mach/mach.h>
79 // Preferred number of milliseconds between each timeout check
80 static const int preferredScriptCheckTimeInterval = 1000;
82 #if HAVE(COMPUTED_GOTO)
83 static void* op_throw_end_indirect;
84 static void* op_call_indirect;
89 ALWAYS_INLINE static Instruction* vPCForPC(CodeBlock* codeBlock, void* pc)
91 if (pc >= codeBlock->instructions.begin() && pc < codeBlock->instructions.end())
92 return static_cast<Instruction*>(pc);
94 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(pc));
95 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(pc);
96 return codeBlock->instructions.begin() + vPCIndex;
101 ALWAYS_INLINE static Instruction* vPCForPC(CodeBlock*, void* pc)
103 return static_cast<Instruction*>(pc);
106 #endif // #ENABLE(CTI)
108 // Returns the depth of the scope chain within a given call frame.
109 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
111 if (!codeBlock->needsFullScopeChain)
114 ScopeChainIterator iter = sc.begin();
115 ScopeChainIterator end = sc.end();
116 while (!(*iter)->isObject(&JSActivation::info)) {
125 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
126 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
127 static bool fastIsNumber(JSValue* value, double& arg)
129 if (JSImmediate::isNumber(value))
130 arg = JSImmediate::getTruncatedInt32(value);
131 else if (Heap::isNumber(static_cast<JSCell*>(value)))
132 arg = static_cast<JSNumberCell*>(value)->value();
138 // FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
139 static bool fastToInt32(JSValue* value, int32_t& arg)
141 if (JSImmediate::isNumber(value))
142 arg = JSImmediate::getTruncatedInt32(value);
143 else if (Heap::isNumber(static_cast<JSCell*>(value)))
144 arg = static_cast<JSNumberCell*>(value)->toInt32();
150 static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
152 if (JSImmediate::isNumber(value)) {
153 if (JSImmediate::getTruncatedUInt32(value, arg))
156 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
158 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
159 arg = static_cast<JSNumberCell*>(value)->toUInt32();
165 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
167 if (JSImmediate::areBothImmediateNumbers(v1, v2))
168 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
172 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
175 Machine* machine = exec->machine();
176 if (machine->isJSString(v1) && machine->isJSString(v2))
177 return static_cast<const JSString*>(v1)->value() < static_cast<const JSString*>(v2)->value();
181 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
182 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
184 if (wasNotString1 | wasNotString2)
187 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
190 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
192 if (JSImmediate::areBothImmediateNumbers(v1, v2))
193 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
197 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
200 Machine* machine = exec->machine();
201 if (machine->isJSString(v1) && machine->isJSString(v2))
202 return !(static_cast<const JSString*>(v2)->value() < static_cast<const JSString*>(v1)->value());
206 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
207 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
209 if (wasNotString1 | wasNotString2)
212 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
215 static NEVER_INLINE JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
217 // exception for the Date exception in defaultValue()
218 JSValue* p1 = v1->toPrimitive(exec);
219 JSValue* p2 = v2->toPrimitive(exec);
221 if (p1->isString() || p2->isString()) {
222 RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
224 return throwOutOfMemoryError(exec);
225 return jsString(exec, value.release());
228 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
231 // Fast-path choices here are based on frequency data from SunSpider:
232 // <times> Add case: <t1> <t2>
233 // ---------------------------
234 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
235 // 247412 Add case: 5 5
236 // 20900 Add case: 5 6
237 // 13962 Add case: 5 3
238 // 4000 Add case: 3 5
240 static ALWAYS_INLINE JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
245 bool rightIsNumber = fastIsNumber(v2, right);
246 if (rightIsNumber && fastIsNumber(v1, left))
247 return jsNumber(exec, left + right);
249 bool leftIsString = v1->isString();
250 if (leftIsString && v2->isString()) {
251 RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
253 return throwOutOfMemoryError(exec);
254 return jsString(exec, value.release());
257 if (rightIsNumber & leftIsString) {
258 RefPtr<UString::Rep> value = JSImmediate::isImmediate(v2) ?
259 concatenate(static_cast<JSString*>(v1)->value().rep(), JSImmediate::getTruncatedInt32(v2)) :
260 concatenate(static_cast<JSString*>(v1)->value().rep(), right);
263 return throwOutOfMemoryError(exec);
264 return jsString(exec, value.release());
267 // All other cases are pretty uncommon
268 return jsAddSlowCase(exec, v1, v2);
271 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
273 if (v->isUndefined())
274 return jsNontrivialString(exec, "undefined");
276 return jsNontrivialString(exec, "boolean");
278 return jsNontrivialString(exec, "number");
280 return jsNontrivialString(exec, "string");
282 // Return "undefined" for objects that should be treated
283 // as null when doing comparisons.
284 if (static_cast<JSObject*>(v)->structureID()->typeInfo().masqueradesAsUndefined())
285 return jsNontrivialString(exec, "undefined");
287 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
288 return jsNontrivialString(exec, "function");
290 return jsNontrivialString(exec, "object");
293 static bool jsIsObjectType(JSValue* v)
295 if (JSImmediate::isImmediate(v))
298 JSType type = static_cast<JSCell*>(v)->structureID()->typeInfo().type();
299 if (type == NumberType || type == StringType)
301 if (type == ObjectType) {
302 if (static_cast<JSObject*>(v)->structureID()->typeInfo().masqueradesAsUndefined())
305 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
311 static bool jsIsFunctionType(JSValue* v)
315 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
321 NEVER_INLINE bool Machine::resolve(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
323 int dst = (vPC + 1)->u.operand;
324 int property = (vPC + 2)->u.operand;
326 ScopeChainNode* scopeChain = this->scopeChain(r);
327 ScopeChainIterator iter = scopeChain->begin();
328 ScopeChainIterator end = scopeChain->end();
331 CodeBlock* codeBlock = this->codeBlock(r);
332 Identifier& ident = codeBlock->identifiers[property];
335 PropertySlot slot(o);
336 if (o->getPropertySlot(exec, ident, slot)) {
337 JSValue* result = slot.getValue(exec, ident);
338 exceptionValue = exec->exception();
344 } while (++iter != end);
345 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
349 NEVER_INLINE bool Machine::resolveSkip(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
351 CodeBlock* codeBlock = this->codeBlock(r);
353 int dst = (vPC + 1)->u.operand;
354 int property = (vPC + 2)->u.operand;
355 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
357 ScopeChainNode* scopeChain = this->scopeChain(r);
358 ScopeChainIterator iter = scopeChain->begin();
359 ScopeChainIterator end = scopeChain->end();
365 Identifier& ident = codeBlock->identifiers[property];
368 PropertySlot slot(o);
369 if (o->getPropertySlot(exec, ident, slot)) {
370 JSValue* result = slot.getValue(exec, ident);
371 exceptionValue = exec->exception();
377 } while (++iter != end);
378 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
382 NEVER_INLINE bool Machine::resolveGlobal(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
384 int dst = (vPC + 1)->u.operand;
385 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
386 ASSERT(globalObject->isGlobalObject());
387 int property = (vPC + 3)->u.operand;
388 StructureID* structureID = (vPC + 4)->u.structureID;
389 int offset = (vPC + 5)->u.operand;
391 if (structureID == globalObject->structureID()) {
392 r[dst] = globalObject->getDirectOffset(offset);
396 CodeBlock* codeBlock = this->codeBlock(r);
397 Identifier& ident = codeBlock->identifiers[property];
398 PropertySlot slot(globalObject);
399 if (globalObject->getPropertySlot(exec, ident, slot)) {
400 JSValue* result = slot.getValue(exec, ident);
401 if (slot.isCacheable()) {
402 if (vPC[4].u.structureID)
403 vPC[4].u.structureID->deref();
404 globalObject->structureID()->ref();
405 vPC[4] = globalObject->structureID();
406 vPC[5] = slot.cachedOffset();
411 exceptionValue = exec->exception();
418 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
422 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
424 ScopeChainIterator iter = scopeChain->begin();
425 ScopeChainIterator next = iter;
427 ScopeChainIterator end = scopeChain->end();
434 if (next == end || base->getPropertySlot(exec, property, slot))
441 ASSERT_NOT_REACHED();
445 NEVER_INLINE void Machine::resolveBase(ExecState* exec, Instruction* vPC, Register* r)
447 int dst = (vPC + 1)->u.operand;
448 int property = (vPC + 2)->u.operand;
449 CodeBlock* codeBlock = this->codeBlock(r);
450 ScopeChainNode* scopeChain = this->scopeChain(r);
451 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
454 NEVER_INLINE bool Machine::resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
456 int baseDst = (vPC + 1)->u.operand;
457 int propDst = (vPC + 2)->u.operand;
458 int property = (vPC + 3)->u.operand;
460 ScopeChainNode* scopeChain = this->scopeChain(r);
461 ScopeChainIterator iter = scopeChain->begin();
462 ScopeChainIterator end = scopeChain->end();
464 // FIXME: add scopeDepthIsZero optimization
468 CodeBlock* codeBlock = this->codeBlock(r);
469 Identifier& ident = codeBlock->identifiers[property];
473 PropertySlot slot(base);
474 if (base->getPropertySlot(exec, ident, slot)) {
475 JSValue* result = slot.getValue(exec, ident);
476 exceptionValue = exec->exception();
484 } while (iter != end);
486 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
490 NEVER_INLINE bool Machine::resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
492 int baseDst = (vPC + 1)->u.operand;
493 int funcDst = (vPC + 2)->u.operand;
494 int property = (vPC + 3)->u.operand;
496 ScopeChainNode* scopeChain = this->scopeChain(r);
497 ScopeChainIterator iter = scopeChain->begin();
498 ScopeChainIterator end = scopeChain->end();
500 // FIXME: add scopeDepthIsZero optimization
504 CodeBlock* codeBlock = this->codeBlock(r);
505 Identifier& ident = codeBlock->identifiers[property];
509 PropertySlot slot(base);
510 if (base->getPropertySlot(exec, ident, slot)) {
511 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
512 // However, section 10.2.3 says that in the case where the value provided
513 // by the caller is null, the global object should be used. It also says
514 // that the section does not apply to internal functions, but for simplicity
515 // of implementation we use the global object anyway here. This guarantees
516 // that in host objects you always get a valid object for this.
517 // We also handle wrapper substitution for the global object at the same time.
518 JSObject* thisObj = base->toThisObject(exec);
519 JSValue* result = slot.getValue(exec, ident);
520 exceptionValue = exec->exception();
524 r[baseDst] = thisObj;
529 } while (iter != end);
531 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
535 ALWAYS_INLINE Register* slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* r, size_t registerOffset, int argc)
537 Register* newEnd = r + registerOffset + newCodeBlock->numCalleeRegisters;
539 if (LIKELY(argc == newCodeBlock->numParameters)) { // correct number of arguments
540 if (UNLIKELY(!registerFile->grow(newEnd)))
543 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
544 size_t omittedArgCount = newCodeBlock->numParameters - argc;
545 registerOffset += omittedArgCount;
546 newEnd += omittedArgCount;
547 if (!registerFile->grow(newEnd))
551 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
552 for (size_t i = 0; i < omittedArgCount; ++i)
553 argv[i] = jsUndefined();
554 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
555 size_t numParameters = newCodeBlock->numParameters;
556 registerOffset += numParameters;
557 newEnd += numParameters;
559 if (!registerFile->grow(newEnd))
563 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
564 for (size_t i = 0; i < numParameters; ++i)
565 argv[i + argc] = argv[i];
571 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
573 if (value->isObject())
575 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
579 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
582 return jsUndefined();
584 JSValue* program = r[argv + 1].jsValue(exec);
586 if (!program->isString())
589 Profiler** profiler = Profiler::enabledProfilerReference();
591 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
593 UString programSource = static_cast<JSString*>(program)->value();
595 CodeBlock* codeBlock = this->codeBlock(r);
596 RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
600 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->start() + argv + 1 + RegisterFile::CallFrameHeaderSize, scopeChain, &exceptionValue);
603 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
611 , m_ctiArrayLengthTrampoline(0)
612 , m_ctiStringLengthTrampoline(0)
613 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
617 , m_timeAtLastCheckTimeout(0)
619 , m_timeoutCheckCount(0)
620 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
623 privateExecute(InitializeAndReturn, 0, 0, 0);
625 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
626 void* storage = fastMalloc(sizeof(CollectorBlock));
628 JSArray* jsArray = new (storage) JSArray(JSArray::createStructureID(jsNull()));
629 m_jsArrayVptr = jsArray->vptr();
630 static_cast<JSCell*>(jsArray)->~JSCell();
632 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
633 m_jsStringVptr = jsString->vptr();
634 static_cast<JSCell*>(jsString)->~JSCell();
636 JSFunction* jsFunction = new (storage) JSFunction(JSFunction::createStructureID(jsNull()));
637 m_jsFunctionVptr = jsFunction->vptr();
638 static_cast<JSCell*>(jsFunction)->~JSCell();
646 if (m_ctiArrayLengthTrampoline)
647 fastFree(m_ctiArrayLengthTrampoline);
648 if (m_ctiStringLengthTrampoline)
649 fastFree(m_ctiStringLengthTrampoline);
655 void Machine::dumpCallFrame(const RegisterFile* registerFile, const Register* r)
657 JSGlobalObject* globalObject = scopeChain(r)->globalObject();
659 CodeBlock* codeBlock = this->codeBlock(r);
660 codeBlock->dump(globalObject->globalExec());
662 dumpRegisters(registerFile, r);
665 void Machine::dumpRegisters(const RegisterFile* registerFile, const Register* r)
667 printf("Register frame: \n\n");
668 printf("----------------------------------------------------\n");
669 printf(" use | address | value \n");
670 printf("----------------------------------------------------\n");
672 CodeBlock* codeBlock = this->codeBlock(r);
676 if (codeBlock->codeType == GlobalCode) {
677 it = registerFile->lastGlobal();
678 end = it + registerFile->numGlobals();
680 printf("[global var] | %10p | %10p \n", it, (*it).v());
683 printf("----------------------------------------------------\n");
686 it = r - RegisterFile::CallFrameHeaderSize - codeBlock->numParameters;
687 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
688 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
691 printf("[param] | %10p | %10p \n", it, (*it).v());
695 printf("----------------------------------------------------\n");
697 printf("[CodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
698 printf("[ScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
699 printf("[CallerRegisters] | %10p | %10p \n", it, (*it).v()); ++it;
700 printf("[ReturnPC] | %10p | %10p \n", it, (*it).v()); ++it;
701 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
702 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
703 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
704 printf("[OptionalCalleeArguments] | %10p | %10p \n", it, (*it).v()); ++it;
705 printf("----------------------------------------------------\n");
707 int registerCount = 0;
709 end = it + codeBlock->numVars;
712 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
717 printf("----------------------------------------------------\n");
719 end = it + codeBlock->numConstants;
722 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
727 printf("----------------------------------------------------\n");
729 end = it + codeBlock->numCalleeRegisters - codeBlock->numConstants - codeBlock->numVars;
732 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
737 printf("----------------------------------------------------\n");
742 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
744 bool Machine::isOpcode(Opcode opcode)
746 #if HAVE(COMPUTED_GOTO)
747 return opcode != HashTraits<Opcode>::emptyValue()
748 && !HashTraits<Opcode>::isDeletedValue(opcode)
749 && m_opcodeIDTable.contains(opcode);
751 return opcode >= 0 && opcode <= op_end;
757 NEVER_INLINE bool Machine::unwindCallFrame(ExecState*& exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, Register*& r)
759 CodeBlock* oldCodeBlock = codeBlock;
760 ScopeChainNode* scopeChain = this->scopeChain(r);
762 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
763 DebuggerCallFrame debuggerCallFrame(exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
764 if (r[RegisterFile::Callee].jsValue(exec))
765 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->lastLine());
767 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->lastLine());
770 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
771 if (r[RegisterFile::Callee].jsValue(exec))
772 profiler->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
774 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
777 // If this call frame created an activation or an 'arguments' object, tear it off.
778 if (oldCodeBlock->codeType == FunctionCode && oldCodeBlock->needsFullScopeChain) {
779 while (!scopeChain->object->isObject(&JSActivation::info))
780 scopeChain = scopeChain->pop();
781 JSActivation* activation = static_cast<JSActivation*>(scopeChain->object);
782 ASSERT(activation->isObject(&JSActivation::info));
784 Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
785 ASSERT(!arguments || arguments->isObject(&Arguments::info));
787 activation->copyRegisters(arguments);
788 } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
789 ASSERT(arguments->isObject(&Arguments::info));
790 if (!arguments->isTornOff())
791 arguments->copyRegisters();
794 if (oldCodeBlock->needsFullScopeChain)
797 void* returnPC = r[RegisterFile::ReturnPC].v();
798 r = r[RegisterFile::CallerRegisters].r();
799 exec = CallFrame::create(r);
800 if (isHostCallFrame(r))
803 codeBlock = this->codeBlock(r);
804 vPC = vPCForPC(codeBlock, returnPC);
808 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, Register*& r, bool explicitThrow)
810 // Set up the exception object
812 CodeBlock* codeBlock = this->codeBlock(r);
813 if (exceptionValue->isObject()) {
814 JSObject* exception = static_cast<JSObject*>(exceptionValue);
815 if (exception->isNotAnObjectErrorStub()) {
816 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
817 exceptionValue = exception;
819 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
820 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
821 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
822 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
823 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
824 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
829 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
830 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
832 // We only hit this path for error messages and throw statements, which don't have a specific failure position
833 // So we just give the full range of the error/throw statement.
834 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
835 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
837 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
838 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceID()), ReadOnly | DontDelete);
839 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
842 if (exception->isWatchdogException()) {
843 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, r)) {
844 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
851 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
852 ScopeChainNode* scopeChain = this->scopeChain(r);
853 DebuggerCallFrame debuggerCallFrame(exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
854 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceID(), codeBlock->lineNumberForVPC(vPC));
857 // Calculate an exception handler vPC, unwinding call frames as necessary.
860 Instruction* handlerVPC;
862 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
863 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, r))
867 // Now unwind the scope chain within the exception handler's call frame.
869 ScopeChain sc(this->scopeChain(r));
870 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
871 ASSERT(scopeDelta >= 0);
874 r[RegisterFile::ScopeChain] = sc.node();
879 class DynamicGlobalObjectScope {
881 DynamicGlobalObjectScope(ExecState* exec, JSGlobalObject* dynamicGlobalObject)
883 , m_savedGlobalObject(exec->globalData().dynamicGlobalObject)
885 exec->globalData().dynamicGlobalObject = dynamicGlobalObject;
888 ~DynamicGlobalObjectScope()
890 m_exec->globalData().dynamicGlobalObject = m_savedGlobalObject;
895 JSGlobalObject* m_savedGlobalObject;
898 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
900 ASSERT(!exec->hadException());
902 if (m_reentryDepth >= MaxReentryDepth) {
903 *exception = createStackOverflowError(exec);
907 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
909 Register* oldEnd = m_registerFile.end();
910 Register* newEnd = oldEnd + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->numCalleeRegisters;
911 if (!m_registerFile.grow(newEnd)) {
912 *exception = createStackOverflowError(exec);
916 DynamicGlobalObjectScope globalObjectScope(exec, scopeChain->globalObject());
918 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
919 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
920 globalObject->copyGlobalsTo(m_registerFile);
922 Register* r = oldEnd + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize;
923 r[codeBlock->thisRegister] = thisObj;
924 initializeCallFrame(r, codeBlock, 0, scopeChain, makeHostCallFramePointer(0), 0, 0, 0);
926 if (codeBlock->needsFullScopeChain)
927 scopeChain = scopeChain->copy();
929 Profiler** profiler = Profiler::enabledProfilerReference();
931 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
935 if (!codeBlock->ctiCode)
936 CTI::compile(this, exec, codeBlock);
937 JSValue* result = CTI::execute(codeBlock->ctiCode, &m_registerFile, r, scopeChain->globalData, exception);
939 JSValue* result = privateExecute(Normal, &m_registerFile, r, exception);
943 MACHINE_SAMPLING_privateExecuteReturned();
946 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
948 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
949 lastGlobalObject->copyGlobalsTo(m_registerFile);
951 m_registerFile.shrink(oldEnd);
956 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
958 ASSERT(!exec->hadException());
960 if (m_reentryDepth >= MaxReentryDepth) {
961 *exception = createStackOverflowError(exec);
965 Register* oldEnd = m_registerFile.end();
966 int argc = 1 + args.size(); // implicit "this" parameter
968 if (!m_registerFile.grow(oldEnd + argc)) {
969 *exception = createStackOverflowError(exec);
973 DynamicGlobalObjectScope globalObjectScope(exec, exec->globalData().dynamicGlobalObject ? exec->globalData().dynamicGlobalObject : scopeChain->globalObject());
975 Register* argv = oldEnd;
979 ArgList::const_iterator end = args.end();
980 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
983 CodeBlock* codeBlock = &functionBodyNode->byteCode(scopeChain);
984 Register* r = slideRegisterWindowForCall(codeBlock, &m_registerFile, argv, argc + RegisterFile::CallFrameHeaderSize, argc);
986 *exception = createStackOverflowError(exec);
987 m_registerFile.shrink(oldEnd);
990 // a 0 codeBlock indicates a built-in caller
991 initializeCallFrame(r, codeBlock, 0, scopeChain, makeHostCallFramePointer(exec->registers()), 0, argc, function);
993 Profiler** profiler = Profiler::enabledProfilerReference();
995 (*profiler)->willExecute(exec, function);
999 if (!codeBlock->ctiCode)
1000 CTI::compile(this, exec, codeBlock);
1001 JSValue* result = CTI::execute(codeBlock->ctiCode, &m_registerFile, r, scopeChain->globalData, exception);
1003 JSValue* result = privateExecute(Normal, &m_registerFile, r, exception);
1007 MACHINE_SAMPLING_privateExecuteReturned();
1009 m_registerFile.shrink(oldEnd);
1013 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception)
1015 return execute(evalNode, exec, thisObj, m_registerFile.size() + evalNode->byteCode(scopeChain).numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
1018 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
1020 ASSERT(!exec->hadException());
1022 if (m_reentryDepth >= MaxReentryDepth) {
1023 *exception = createStackOverflowError(exec);
1027 DynamicGlobalObjectScope globalObjectScope(exec, exec->globalData().dynamicGlobalObject ? exec->globalData().dynamicGlobalObject : scopeChain->globalObject());
1029 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
1031 JSVariableObject* variableObject;
1032 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
1034 if (node->object->isVariableObject()) {
1035 variableObject = static_cast<JSVariableObject*>(node->object);
1040 { // Scope for BatchedTransitionOptimizer
1042 BatchedTransitionOptimizer optimizer(variableObject);
1044 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
1045 Node::VarStack::const_iterator varStackEnd = varStack.end();
1046 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
1047 const Identifier& ident = (*it).first;
1048 if (!variableObject->hasProperty(exec, ident)) {
1049 PutPropertySlot slot;
1050 variableObject->put(exec, ident, jsUndefined(), slot);
1054 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
1055 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
1056 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
1057 PutPropertySlot slot;
1058 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
1063 Register* oldEnd = m_registerFile.end();
1064 Register* newEnd = m_registerFile.start() + registerOffset + codeBlock->numCalleeRegisters;
1065 if (!m_registerFile.grow(newEnd)) {
1066 *exception = createStackOverflowError(exec);
1070 Register* r = m_registerFile.start() + registerOffset;
1072 // a 0 codeBlock indicates a built-in caller
1073 r[codeBlock->thisRegister] = thisObj;
1074 initializeCallFrame(r, codeBlock, 0, scopeChain, makeHostCallFramePointer(exec->registers()), 0, 0, 0);
1076 if (codeBlock->needsFullScopeChain)
1077 scopeChain = scopeChain->copy();
1079 Profiler** profiler = Profiler::enabledProfilerReference();
1081 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1085 if (!codeBlock->ctiCode)
1086 CTI::compile(this, exec, codeBlock);
1087 JSValue* result = CTI::execute(codeBlock->ctiCode, &m_registerFile, r, scopeChain->globalData, exception);
1089 JSValue* result = privateExecute(Normal, &m_registerFile, r, exception);
1093 MACHINE_SAMPLING_privateExecuteReturned();
1096 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1098 m_registerFile.shrink(oldEnd);
1102 NEVER_INLINE void Machine::debug(ExecState* exec, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
1104 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
1108 CodeBlock* codeBlock = this->codeBlock(r);
1109 ScopeChainNode* scopeChain = this->scopeChain(r);
1110 DebuggerCallFrame debuggerCallFrame(exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
1112 switch (debugHookID) {
1113 case DidEnterCallFrame:
1114 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceID(), firstLine);
1116 case WillLeaveCallFrame:
1117 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceID(), lastLine);
1119 case WillExecuteStatement:
1120 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceID(), firstLine);
1122 case WillExecuteProgram:
1123 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceID(), firstLine);
1125 case DidExecuteProgram:
1126 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceID(), lastLine);
1128 case DidReachBreakpoint:
1129 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceID(), lastLine);
1134 void Machine::resetTimeoutCheck()
1136 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1137 m_timeAtLastCheckTimeout = 0;
1138 m_timeExecuting = 0;
1141 // Returns the time the current thread has spent executing, in milliseconds.
1142 static inline unsigned getCPUTime()
1144 #if PLATFORM(DARWIN)
1145 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1146 thread_basic_info_data_t info;
1148 // Get thread information
1149 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1151 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1152 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1155 #elif HAVE(SYS_TIME_H)
1156 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1158 gettimeofday(&tv, 0);
1159 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1161 QDateTime t = QDateTime::currentDateTime();
1162 return t.toTime_t() * 1000 + t.time().msec();
1163 #elif PLATFORM(WIN_OS)
1166 unsigned long long fileTimeAsLong;
1167 } userTime, kernelTime;
1169 // GetThreadTimes won't accept NULL arguments so we pass these even though
1170 // they're not used.
1171 FILETIME creationTime, exitTime;
1173 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1175 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1177 #error Platform does not have getCurrentTime function
1181 // We have to return a JSValue here, gcc seems to produce worse code if
1182 // we attempt to return a bool
1183 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1185 unsigned currentTime = getCPUTime();
1187 if (!m_timeAtLastCheckTimeout) {
1188 // Suspicious amount of looping in a script -- start timing it
1189 m_timeAtLastCheckTimeout = currentTime;
1193 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1198 m_timeExecuting += timeDiff;
1199 m_timeAtLastCheckTimeout = currentTime;
1201 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1202 // preferredScriptCheckTimeInterval
1203 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1204 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1205 // preferred script check time interval.
1206 if (m_ticksUntilNextTimeoutCheck == 0)
1207 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1209 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1210 if (globalObject->shouldInterruptScript())
1211 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1213 resetTimeoutCheck();
1219 NEVER_INLINE ScopeChainNode* Machine::createExceptionScope(ExecState* exec, const Instruction* vPC, Register* r)
1221 int dst = (++vPC)->u.operand;
1222 CodeBlock* codeBlock = this->codeBlock(r);
1223 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1224 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1225 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1228 return scopeChain(r)->push(scope);
1231 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1233 JSValue* prototype = structureID->prototypeForLookup(exec);
1234 if (JSImmediate::isImmediate(prototype))
1236 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(prototype)->structureID());
1237 structureID->setCachedPrototypeChain(chain.release());
1238 return structureID->cachedPrototypeChain();
1241 NEVER_INLINE void Machine::tryCachePutByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1243 // Recursive invocation may already have specialized this instruction.
1244 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1247 if (JSImmediate::isImmediate(baseValue))
1250 // Uncacheable: give up.
1251 if (!slot.isCacheable()) {
1252 vPC[0] = getOpcode(op_put_by_id_generic);
1256 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1257 StructureID* structureID = baseCell->structureID();
1259 if (structureID->isDictionary()) {
1260 vPC[0] = getOpcode(op_put_by_id_generic);
1264 // Cache miss: record StructureID to compare against next time.
1265 StructureID* lastStructureID = vPC[4].u.structureID;
1266 if (structureID != lastStructureID) {
1267 // First miss: record StructureID to compare against next time.
1268 if (!lastStructureID) {
1269 vPC[4] = structureID;
1273 // Second miss: give up.
1274 vPC[0] = getOpcode(op_put_by_id_generic);
1278 // Cache hit: Specialize instruction and ref StructureIDs.
1280 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1281 if (baseCell != slot.base()) {
1282 vPC[0] = getOpcode(op_put_by_id_generic);
1286 // StructureID transition, cache transition info
1287 if (slot.type() == PutPropertySlot::NewProperty) {
1288 vPC[0] = getOpcode(op_put_by_id_transition);
1289 vPC[4] = structureID->previousID();
1290 vPC[5] = structureID;
1291 StructureIDChain* chain = structureID->cachedPrototypeChain();
1293 chain = cachePrototypeChain(exec, structureID);
1295 // This happens if someone has manually inserted null into the prototype chain
1296 vPC[0] = getOpcode(op_put_by_id_generic);
1301 vPC[7] = slot.cachedOffset();
1302 codeBlock->refStructureIDs(vPC);
1306 vPC[0] = getOpcode(op_put_by_id_replace);
1307 vPC[5] = slot.cachedOffset();
1308 codeBlock->refStructureIDs(vPC);
1311 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1313 codeBlock->derefStructureIDs(vPC);
1314 vPC[0] = getOpcode(op_put_by_id);
1318 NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1320 // Recursive invocation may already have specialized this instruction.
1321 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1324 // FIXME: Cache property access for immediates.
1325 if (JSImmediate::isImmediate(baseValue)) {
1326 vPC[0] = getOpcode(op_get_by_id_generic);
1330 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1331 vPC[0] = getOpcode(op_get_array_length);
1335 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1336 vPC[0] = getOpcode(op_get_string_length);
1340 // Uncacheable: give up.
1341 if (!slot.isCacheable()) {
1342 vPC[0] = getOpcode(op_get_by_id_generic);
1346 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1348 if (structureID->isDictionary()) {
1349 vPC[0] = getOpcode(op_get_by_id_generic);
1354 StructureID* lastStructureID = vPC[4].u.structureID;
1355 if (structureID != lastStructureID) {
1356 // First miss: record StructureID to compare against next time.
1357 if (!lastStructureID) {
1358 vPC[4] = structureID;
1362 // Second miss: give up.
1363 vPC[0] = getOpcode(op_get_by_id_generic);
1367 // Cache hit: Specialize instruction and ref StructureIDs.
1369 if (slot.slotBase() == baseValue) {
1370 vPC[0] = getOpcode(op_get_by_id_self);
1371 vPC[5] = slot.cachedOffset();
1373 codeBlock->refStructureIDs(vPC);
1377 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1378 ASSERT(slot.slotBase()->isObject());
1380 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1382 // Heavy access to a prototype is a good indication that it's not being
1383 // used as a dictionary.
1384 if (baseObject->structureID()->isDictionary()) {
1385 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1386 baseObject->setStructureID(transition.release());
1387 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1390 vPC[0] = getOpcode(op_get_by_id_proto);
1391 vPC[5] = baseObject->structureID();
1392 vPC[6] = slot.cachedOffset();
1394 codeBlock->refStructureIDs(vPC);
1399 JSObject* o = static_cast<JSObject*>(baseValue);
1400 while (slot.slotBase() != o) {
1401 JSValue* v = o->structureID()->prototypeForLookup(exec);
1403 // If we didn't find base in baseValue's prototype chain, then baseValue
1404 // must be a proxy for another object.
1406 vPC[0] = getOpcode(op_get_by_id_generic);
1410 o = static_cast<JSObject*>(v);
1412 // Heavy access to a prototype is a good indication that it's not being
1413 // used as a dictionary.
1414 if (o->structureID()->isDictionary()) {
1415 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1416 o->setStructureID(transition.release());
1417 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1423 StructureIDChain* chain = structureID->cachedPrototypeChain();
1425 chain = cachePrototypeChain(exec, structureID);
1428 vPC[0] = getOpcode(op_get_by_id_chain);
1429 vPC[4] = structureID;
1432 vPC[7] = slot.cachedOffset();
1433 codeBlock->refStructureIDs(vPC);
1436 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1438 codeBlock->derefStructureIDs(vPC);
1439 vPC[0] = getOpcode(op_get_by_id);
1443 JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, Register* r, JSValue** exception)
1445 // One-time initialization of our address tables. We have to put this code
1446 // here because our labels are only in scope inside this function.
1447 if (flag == InitializeAndReturn) {
1448 #if HAVE(COMPUTED_GOTO)
1449 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1450 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1453 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1454 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1455 #undef ADD_OPCODE_ID
1456 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1457 op_throw_end_indirect = &&op_throw_end;
1458 op_call_indirect = &&op_call;
1459 #endif // HAVE(COMPUTED_GOTO)
1464 // Currently with CTI enabled we never interpret functions
1465 ASSERT_NOT_REACHED();
1468 #define exec CallFrame::create(r)
1470 JSGlobalData* globalData = &exec->globalData();
1471 JSValue* exceptionValue = 0;
1472 Instruction* handlerVPC = 0;
1474 Instruction* vPC = this->codeBlock(r)->instructions.begin();
1475 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1476 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1478 #define VM_CHECK_EXCEPTION() \
1480 if (UNLIKELY(globalData->exception != 0)) { \
1481 exceptionValue = globalData->exception; \
1486 #if DUMP_OPCODE_STATS
1487 OpcodeStats::resetLastInstruction();
1490 #define CHECK_FOR_TIMEOUT() \
1491 if (!--tickCount) { \
1492 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1494 tickCount = m_ticksUntilNextTimeoutCheck; \
1497 #if HAVE(COMPUTED_GOTO)
1498 #define NEXT_OPCODE MACHINE_SAMPLING_sample(this->codeBlock(r), vPC); goto *vPC->u.opcode
1499 #if DUMP_OPCODE_STATS
1500 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1502 #define BEGIN_OPCODE(opcode) opcode:
1506 #define NEXT_OPCODE MACHINE_SAMPLING_sample(this->codeBlock(r), vPC); continue
1507 #if DUMP_OPCODE_STATS
1508 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1510 #define BEGIN_OPCODE(opcode) case opcode:
1512 while (1) // iterator loop begins
1513 switch (vPC->u.opcode)
1516 BEGIN_OPCODE(op_new_object) {
1517 /* new_object dst(r)
1519 Constructs a new empty Object instance using the original
1520 constructor, and puts the result in register dst.
1522 int dst = (++vPC)->u.operand;
1523 r[dst] = constructEmptyObject(exec);
1528 BEGIN_OPCODE(op_new_array) {
1529 /* new_array dst(r) firstArg(r) argCount(n)
1531 Constructs a new Array instance using the original
1532 constructor, and puts the result in register dst.
1533 The array will contain argCount elements with values
1534 taken from registers starting at register firstArg.
1536 int dst = (++vPC)->u.operand;
1537 int firstArg = (++vPC)->u.operand;
1538 int argCount = (++vPC)->u.operand;
1539 ArgList args(r + firstArg, argCount);
1540 r[dst] = constructArray(exec, args);
1545 BEGIN_OPCODE(op_new_regexp) {
1546 /* new_regexp dst(r) regExp(re)
1548 Constructs a new RegExp instance using the original
1549 constructor from regexp regExp, and puts the result in
1552 int dst = (++vPC)->u.operand;
1553 int regExp = (++vPC)->u.operand;
1554 r[dst] = new (globalData) RegExpObject(scopeChain(r)->globalObject()->regExpStructure(), codeBlock(r)->regexps[regExp]);
1559 BEGIN_OPCODE(op_mov) {
1560 /* mov dst(r) src(r)
1562 Copies register src to register dst.
1564 int dst = (++vPC)->u.operand;
1565 int src = (++vPC)->u.operand;
1571 BEGIN_OPCODE(op_eq) {
1572 /* eq dst(r) src1(r) src2(r)
1574 Checks whether register src1 and register src2 are equal,
1575 as with the ECMAScript '==' operator, and puts the result
1576 as a boolean in register dst.
1578 int dst = (++vPC)->u.operand;
1579 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1580 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1581 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1582 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1584 JSValue* result = jsBoolean(equalSlowCase(exec, src1, src2));
1585 VM_CHECK_EXCEPTION();
1592 BEGIN_OPCODE(op_eq_null) {
1593 /* neq dst(r) src(r)
1595 Checks whether register src is null, as with the ECMAScript '!='
1596 operator, and puts the result as a boolean in register dst.
1598 int dst = (++vPC)->u.operand;
1599 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1601 if (src->isUndefinedOrNull()) {
1602 r[dst] = jsBoolean(true);
1607 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && src->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
1611 BEGIN_OPCODE(op_neq) {
1612 /* neq dst(r) src1(r) src2(r)
1614 Checks whether register src1 and register src2 are not
1615 equal, as with the ECMAScript '!=' operator, and puts the
1616 result as a boolean in register dst.
1618 int dst = (++vPC)->u.operand;
1619 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1620 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1621 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1622 r[dst] = jsBoolean(src1 != src2);
1624 JSValue* result = jsBoolean(!equalSlowCase(exec, src1, src2));
1625 VM_CHECK_EXCEPTION();
1632 BEGIN_OPCODE(op_neq_null) {
1633 /* neq dst(r) src(r)
1635 Checks whether register src is not null, as with the ECMAScript '!='
1636 operator, and puts the result as a boolean in register dst.
1638 int dst = (++vPC)->u.operand;
1639 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1641 if (src->isUndefinedOrNull()) {
1642 r[dst] = jsBoolean(false);
1647 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
1651 BEGIN_OPCODE(op_stricteq) {
1652 /* stricteq dst(r) src1(r) src2(r)
1654 Checks whether register src1 and register src2 are strictly
1655 equal, as with the ECMAScript '===' operator, and puts the
1656 result as a boolean in register dst.
1658 int dst = (++vPC)->u.operand;
1659 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1660 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1661 if (JSImmediate::areBothImmediate(src1, src2))
1662 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1663 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1664 r[dst] = jsBoolean(false);
1666 r[dst] = jsBoolean(strictEqualSlowCase(src1, src2));
1671 BEGIN_OPCODE(op_nstricteq) {
1672 /* nstricteq dst(r) src1(r) src2(r)
1674 Checks whether register src1 and register src2 are not
1675 strictly equal, as with the ECMAScript '!==' operator, and
1676 puts the result as a boolean in register dst.
1678 int dst = (++vPC)->u.operand;
1679 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1680 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1682 if (JSImmediate::areBothImmediate(src1, src2))
1683 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1684 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1685 r[dst] = jsBoolean(true);
1687 r[dst] = jsBoolean(!strictEqualSlowCase(src1, src2));
1692 BEGIN_OPCODE(op_less) {
1693 /* less dst(r) src1(r) src2(r)
1695 Checks whether register src1 is less than register src2, as
1696 with the ECMAScript '<' operator, and puts the result as
1697 a boolean in register dst.
1699 int dst = (++vPC)->u.operand;
1700 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1701 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1702 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1703 VM_CHECK_EXCEPTION();
1709 BEGIN_OPCODE(op_lesseq) {
1710 /* lesseq dst(r) src1(r) src2(r)
1712 Checks whether register src1 is less than or equal to
1713 register src2, as with the ECMAScript '<=' operator, and
1714 puts the result as a boolean in register dst.
1716 int dst = (++vPC)->u.operand;
1717 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1718 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1719 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1720 VM_CHECK_EXCEPTION();
1726 BEGIN_OPCODE(op_pre_inc) {
1727 /* pre_inc srcDst(r)
1729 Converts register srcDst to number, adds one, and puts the result
1730 back in register srcDst.
1732 int srcDst = (++vPC)->u.operand;
1733 JSValue* v = r[srcDst].jsValue(exec);
1734 if (JSImmediate::canDoFastAdditiveOperations(v))
1735 r[srcDst] = JSImmediate::incImmediateNumber(v);
1737 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1738 VM_CHECK_EXCEPTION();
1745 BEGIN_OPCODE(op_pre_dec) {
1746 /* pre_dec srcDst(r)
1748 Converts register srcDst to number, subtracts one, and puts the result
1749 back in register srcDst.
1751 int srcDst = (++vPC)->u.operand;
1752 JSValue* v = r[srcDst].jsValue(exec);
1753 if (JSImmediate::canDoFastAdditiveOperations(v))
1754 r[srcDst] = JSImmediate::decImmediateNumber(v);
1756 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1757 VM_CHECK_EXCEPTION();
1764 BEGIN_OPCODE(op_post_inc) {
1765 /* post_inc dst(r) srcDst(r)
1767 Converts register srcDst to number. The number itself is
1768 written to register dst, and the number plus one is written
1769 back to register srcDst.
1771 int dst = (++vPC)->u.operand;
1772 int srcDst = (++vPC)->u.operand;
1773 JSValue* v = r[srcDst].jsValue(exec);
1774 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1776 r[srcDst] = JSImmediate::incImmediateNumber(v);
1778 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1779 VM_CHECK_EXCEPTION();
1781 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1787 BEGIN_OPCODE(op_post_dec) {
1788 /* post_dec dst(r) srcDst(r)
1790 Converts register srcDst to number. The number itself is
1791 written to register dst, and the number minus one is written
1792 back to register srcDst.
1794 int dst = (++vPC)->u.operand;
1795 int srcDst = (++vPC)->u.operand;
1796 JSValue* v = r[srcDst].jsValue(exec);
1797 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1799 r[srcDst] = JSImmediate::decImmediateNumber(v);
1801 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1802 VM_CHECK_EXCEPTION();
1804 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1810 BEGIN_OPCODE(op_to_jsnumber) {
1811 /* to_jsnumber dst(r) src(r)
1813 Converts register src to number, and puts the result
1816 int dst = (++vPC)->u.operand;
1817 int src = (++vPC)->u.operand;
1819 JSValue* srcVal = r[src].jsValue(exec);
1821 if (LIKELY(JSImmediate::isNumber(srcVal) || static_cast<JSCell*>(srcVal)->structureID()->typeInfo().type() == NumberType)) {
1824 JSValue* result = srcVal->toJSNumber(exec);
1825 VM_CHECK_EXCEPTION();
1832 BEGIN_OPCODE(op_negate) {
1833 /* negate dst(r) src(r)
1835 Converts register src to number, negates it, and puts the
1836 result in register dst.
1838 int dst = (++vPC)->u.operand;
1839 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1841 if (fastIsNumber(src, v))
1842 r[dst] = jsNumber(exec, -v);
1844 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1845 VM_CHECK_EXCEPTION();
1852 BEGIN_OPCODE(op_add) {
1853 /* add dst(r) src1(r) src2(r)
1855 Adds register src1 and register src2, and puts the result
1856 in register dst. (JS add may be string concatenation or
1857 numeric add, depending on the types of the operands.)
1859 int dst = (++vPC)->u.operand;
1860 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1861 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1862 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1863 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1865 JSValue* result = jsAdd(exec, src1, src2);
1866 VM_CHECK_EXCEPTION();
1872 BEGIN_OPCODE(op_mul) {
1873 /* mul dst(r) src1(r) src2(r)
1875 Multiplies register src1 and register src2 (converted to
1876 numbers), and puts the product in register dst.
1878 int dst = (++vPC)->u.operand;
1879 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1880 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1883 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1884 r[dst] = jsNumber(exec, left * right);
1886 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1887 VM_CHECK_EXCEPTION();
1894 BEGIN_OPCODE(op_div) {
1895 /* div dst(r) dividend(r) divisor(r)
1897 Divides register dividend (converted to number) by the
1898 register divisor (converted to number), and puts the
1899 quotient in register dst.
1901 int dst = (++vPC)->u.operand;
1902 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1903 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1906 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1907 r[dst] = jsNumber(exec, left / right);
1909 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1910 VM_CHECK_EXCEPTION();
1916 BEGIN_OPCODE(op_mod) {
1917 /* mod dst(r) dividend(r) divisor(r)
1919 Divides register dividend (converted to number) by
1920 register divisor (converted to number), and puts the
1921 remainder in register dst.
1923 int dst = (++vPC)->u.operand;
1924 int dividend = (++vPC)->u.operand;
1925 int divisor = (++vPC)->u.operand;
1927 JSValue* dividendValue = r[dividend].jsValue(exec);
1928 JSValue* divisorValue = r[divisor].jsValue(exec);
1930 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1931 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1936 double d = dividendValue->toNumber(exec);
1937 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1938 VM_CHECK_EXCEPTION();
1943 BEGIN_OPCODE(op_sub) {
1944 /* sub dst(r) src1(r) src2(r)
1946 Subtracts register src2 (converted to number) from register
1947 src1 (converted to number), and puts the difference in
1950 int dst = (++vPC)->u.operand;
1951 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1952 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1955 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1956 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1957 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1958 r[dst] = jsNumber(exec, left - right);
1960 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1961 VM_CHECK_EXCEPTION();
1967 BEGIN_OPCODE(op_lshift) {
1968 /* lshift dst(r) val(r) shift(r)
1970 Performs left shift of register val (converted to int32) by
1971 register shift (converted to uint32), and puts the result
1974 int dst = (++vPC)->u.operand;
1975 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1976 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1979 if (JSImmediate::areBothImmediateNumbers(val, shift))
1980 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1981 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1982 r[dst] = jsNumber(exec, left << (right & 0x1f));
1984 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1985 VM_CHECK_EXCEPTION();
1992 BEGIN_OPCODE(op_rshift) {
1993 /* rshift dst(r) val(r) shift(r)
1995 Performs arithmetic right shift of register val (converted
1996 to int32) by register shift (converted to
1997 uint32), and puts the result in register dst.
1999 int dst = (++vPC)->u.operand;
2000 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
2001 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
2004 if (JSImmediate::areBothImmediateNumbers(val, shift))
2005 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
2006 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
2007 r[dst] = jsNumber(exec, left >> (right & 0x1f));
2009 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
2010 VM_CHECK_EXCEPTION();
2017 BEGIN_OPCODE(op_urshift) {
2018 /* rshift dst(r) val(r) shift(r)
2020 Performs logical right shift of register val (converted
2021 to uint32) by register shift (converted to
2022 uint32), and puts the result in register dst.
2024 int dst = (++vPC)->u.operand;
2025 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
2026 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
2027 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
2028 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
2030 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
2031 VM_CHECK_EXCEPTION();
2038 BEGIN_OPCODE(op_bitand) {
2039 /* bitand dst(r) src1(r) src2(r)
2041 Computes bitwise AND of register src1 (converted to int32)
2042 and register src2 (converted to int32), and puts the result
2045 int dst = (++vPC)->u.operand;
2046 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2047 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2050 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2051 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
2052 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2053 r[dst] = jsNumber(exec, left & right);
2055 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
2056 VM_CHECK_EXCEPTION();
2063 BEGIN_OPCODE(op_bitxor) {
2064 /* bitxor dst(r) src1(r) src2(r)
2066 Computes bitwise XOR of register src1 (converted to int32)
2067 and register src2 (converted to int32), and puts the result
2070 int dst = (++vPC)->u.operand;
2071 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2072 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2075 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2076 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
2077 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2078 r[dst] = jsNumber(exec, left ^ right);
2080 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
2081 VM_CHECK_EXCEPTION();
2088 BEGIN_OPCODE(op_bitor) {
2089 /* bitor dst(r) src1(r) src2(r)
2091 Computes bitwise OR of register src1 (converted to int32)
2092 and register src2 (converted to int32), and puts the
2093 result in register dst.
2095 int dst = (++vPC)->u.operand;
2096 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2097 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2100 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2101 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
2102 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2103 r[dst] = jsNumber(exec, left | right);
2105 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
2106 VM_CHECK_EXCEPTION();
2113 BEGIN_OPCODE(op_bitnot) {
2114 /* bitnot dst(r) src(r)
2116 Computes bitwise NOT of register src1 (converted to int32),
2117 and puts the result in register dst.
2119 int dst = (++vPC)->u.operand;
2120 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
2122 if (fastToInt32(src, value))
2123 r[dst] = jsNumber(exec, ~value);
2125 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
2126 VM_CHECK_EXCEPTION();
2132 BEGIN_OPCODE(op_not) {
2133 /* not dst(r) src(r)
2135 Computes logical NOT of register src (converted to
2136 boolean), and puts the result in register dst.
2138 int dst = (++vPC)->u.operand;
2139 int src = (++vPC)->u.operand;
2140 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
2141 VM_CHECK_EXCEPTION();
2147 BEGIN_OPCODE(op_instanceof) {
2148 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2150 Tests whether register value is an instance of register
2151 constructor, and puts the boolean result in register
2152 dst. Register constructorProto must contain the "prototype"
2153 property (not the actual prototype) of the object in
2154 register constructor. This lookup is separated so that
2155 polymorphic inline caching can apply.
2157 Raises an exception if register constructor is not an
2160 int dst = (++vPC)->u.operand;
2161 int value = (++vPC)->u.operand;
2162 int base = (++vPC)->u.operand;
2163 int baseProto = (++vPC)->u.operand;
2165 JSValue* baseVal = r[base].jsValue(exec);
2167 if (isNotObject(exec, true, codeBlock(r), vPC, baseVal, exceptionValue))
2170 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2171 r[dst] = jsBoolean(baseObj->structureID()->typeInfo().implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec), r[baseProto].jsValue(exec)) : false);
2176 BEGIN_OPCODE(op_typeof) {
2177 /* typeof dst(r) src(r)
2179 Determines the type string for src according to ECMAScript
2180 rules, and puts the result in register dst.
2182 int dst = (++vPC)->u.operand;
2183 int src = (++vPC)->u.operand;
2184 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2189 BEGIN_OPCODE(op_is_undefined) {
2190 /* is_undefined dst(r) src(r)
2192 Determines whether the type string for src according to
2193 the ECMAScript rules is "undefined", and puts the result
2196 int dst = (++vPC)->u.operand;
2197 int src = (++vPC)->u.operand;
2198 JSValue* v = r[src].jsValue(exec);
2199 r[dst] = jsBoolean(JSImmediate::isImmediate(v) ? v->isUndefined() : v->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
2204 BEGIN_OPCODE(op_is_boolean) {
2205 /* is_boolean dst(r) src(r)
2207 Determines whether the type string for src according to
2208 the ECMAScript rules is "boolean", and puts the result
2211 int dst = (++vPC)->u.operand;
2212 int src = (++vPC)->u.operand;
2213 r[dst] = jsBoolean(r[src].jsValue(exec)->isBoolean());
2218 BEGIN_OPCODE(op_is_number) {
2219 /* is_number dst(r) src(r)
2221 Determines whether the type string for src according to
2222 the ECMAScript rules is "number", and puts the result
2225 int dst = (++vPC)->u.operand;
2226 int src = (++vPC)->u.operand;
2227 r[dst] = jsBoolean(r[src].jsValue(exec)->isNumber());
2232 BEGIN_OPCODE(op_is_string) {
2233 /* is_string dst(r) src(r)
2235 Determines whether the type string for src according to
2236 the ECMAScript rules is "string", and puts the result
2239 int dst = (++vPC)->u.operand;
2240 int src = (++vPC)->u.operand;
2241 r[dst] = jsBoolean(r[src].jsValue(exec)->isString());
2246 BEGIN_OPCODE(op_is_object) {
2247 /* is_object dst(r) src(r)
2249 Determines whether the type string for src according to
2250 the ECMAScript rules is "object", and puts the result
2253 int dst = (++vPC)->u.operand;
2254 int src = (++vPC)->u.operand;
2255 r[dst] = jsBoolean(jsIsObjectType(r[src].jsValue(exec)));
2260 BEGIN_OPCODE(op_is_function) {
2261 /* is_function dst(r) src(r)
2263 Determines whether the type string for src according to
2264 the ECMAScript rules is "function", and puts the result
2267 int dst = (++vPC)->u.operand;
2268 int src = (++vPC)->u.operand;
2269 r[dst] = jsBoolean(jsIsFunctionType(r[src].jsValue(exec)));
2274 BEGIN_OPCODE(op_in) {
2275 /* in dst(r) property(r) base(r)
2277 Tests whether register base has a property named register
2278 property, and puts the boolean result in register dst.
2280 Raises an exception if register constructor is not an
2283 int dst = (++vPC)->u.operand;
2284 int property = (++vPC)->u.operand;
2285 int base = (++vPC)->u.operand;
2287 JSValue* baseVal = r[base].jsValue(exec);
2288 if (isNotObject(exec, false, codeBlock(r), vPC, baseVal, exceptionValue))
2291 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2293 JSValue* propName = r[property].jsValue(exec);
2296 if (propName->getUInt32(i))
2297 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2299 Identifier property(exec, propName->toString(exec));
2300 VM_CHECK_EXCEPTION();
2301 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2307 BEGIN_OPCODE(op_resolve) {
2308 /* resolve dst(r) property(id)
2310 Looks up the property named by identifier property in the
2311 scope chain, and writes the resulting value to register
2312 dst. If the property is not found, raises an exception.
2314 if (UNLIKELY(!resolve(exec, vPC, r, exceptionValue)))
2320 BEGIN_OPCODE(op_resolve_skip) {
2321 /* resolve_skip dst(r) property(id) skip(n)
2323 Looks up the property named by identifier property in the
2324 scope chain skipping the top 'skip' levels, and writes the resulting
2325 value to register dst. If the property is not found, raises an exception.
2327 if (UNLIKELY(!resolveSkip(exec, vPC, r, exceptionValue)))
2334 BEGIN_OPCODE(op_resolve_global) {
2335 /* resolve_skip dst(r) globalObject(c) property(id) structureID(sID) offset(n)
2337 Performs a dynamic property lookup for the given property, on the provided
2338 global object. If structureID matches the StructureID of the global then perform
2339 a fast lookup using the case offset, otherwise fall back to a full resolve and
2340 cache the new structureID and offset
2342 if (UNLIKELY(!resolveGlobal(exec, vPC, r, exceptionValue)))
2349 BEGIN_OPCODE(op_get_global_var) {
2350 /* get_global_var dst(r) globalObject(c) index(n)
2352 Gets the global var at global slot index and places it in register dst.
2354 int dst = (++vPC)->u.operand;
2355 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2356 ASSERT(scope->isGlobalObject());
2357 int index = (++vPC)->u.operand;
2359 r[dst] = scope->registerAt(index);
2363 BEGIN_OPCODE(op_put_global_var) {
2364 /* put_global_var globalObject(c) index(n) value(r)
2366 Puts value into global slot index.
2368 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2369 ASSERT(scope->isGlobalObject());
2370 int index = (++vPC)->u.operand;
2371 int value = (++vPC)->u.operand;
2373 scope->registerAt(index) = r[value].jsValue(exec);
2377 BEGIN_OPCODE(op_get_scoped_var) {
2378 /* get_scoped_var dst(r) index(n) skip(n)
2380 Loads the contents of the index-th local from the scope skip nodes from
2381 the top of the scope chain, and places it in register dst
2383 int dst = (++vPC)->u.operand;
2384 int index = (++vPC)->u.operand;
2385 int skip = (++vPC)->u.operand + codeBlock(r)->needsFullScopeChain;
2387 ScopeChainNode* scopeChain = this->scopeChain(r);
2388 ScopeChainIterator iter = scopeChain->begin();
2389 ScopeChainIterator end = scopeChain->end();
2390 ASSERT(iter != end);
2393 ASSERT(iter != end);
2396 ASSERT((*iter)->isVariableObject());
2397 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2398 r[dst] = scope->registerAt(index);
2402 BEGIN_OPCODE(op_put_scoped_var) {
2403 /* put_scoped_var index(n) skip(n) value(r)
2406 int index = (++vPC)->u.operand;
2407 int skip = (++vPC)->u.operand + codeBlock(r)->needsFullScopeChain;
2408 int value = (++vPC)->u.operand;
2410 ScopeChainNode* scopeChain = this->scopeChain(r);
2411 ScopeChainIterator iter = scopeChain->begin();
2412 ScopeChainIterator end = scopeChain->end();
2413 ASSERT(iter != end);
2416 ASSERT(iter != end);
2419 ASSERT((*iter)->isVariableObject());
2420 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2421 scope->registerAt(index) = r[value].jsValue(exec);
2425 BEGIN_OPCODE(op_resolve_base) {
2426 /* resolve_base dst(r) property(id)
2428 Searches the scope chain for an object containing
2429 identifier property, and if one is found, writes it to
2430 register dst. If none is found, the outermost scope (which
2431 will be the global object) is stored in register dst.
2433 resolveBase(exec, vPC, r);
2438 BEGIN_OPCODE(op_resolve_with_base) {
2439 /* resolve_with_base baseDst(r) propDst(r) property(id)
2441 Searches the scope chain for an object containing
2442 identifier property, and if one is found, writes it to
2443 register srcDst, and the retrieved property value to register
2444 propDst. If the property is not found, raises an exception.
2446 This is more efficient than doing resolve_base followed by
2447 resolve, or resolve_base followed by get_by_id, as it
2448 avoids duplicate hash lookups.
2450 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, exceptionValue)))
2456 BEGIN_OPCODE(op_resolve_func) {
2457 /* resolve_func baseDst(r) funcDst(r) property(id)
2459 Searches the scope chain for an object containing
2460 identifier property, and if one is found, writes the
2461 appropriate object to use as "this" when calling its
2462 properties to register baseDst; and the retrieved property
2463 value to register propDst. If the property is not found,
2464 raises an exception.
2466 This differs from resolve_with_base, because the
2467 global this value will be substituted for activations or
2468 the global object, which is the right behavior for function
2469 calls but not for other property lookup.
2471 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, exceptionValue)))
2477 BEGIN_OPCODE(op_get_by_id) {
2478 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2480 Generic property access: Gets the property named by identifier
2481 property from the value base, and puts the result in register dst.
2483 int dst = vPC[1].u.operand;
2484 int base = vPC[2].u.operand;
2485 int property = vPC[3].u.operand;
2487 CodeBlock* codeBlock = this->codeBlock(r);
2488 Identifier& ident = codeBlock->identifiers[property];
2489 JSValue* baseValue = r[base].jsValue(exec);
2490 PropertySlot slot(baseValue);
2491 JSValue* result = baseValue->get(exec, ident, slot);
2492 VM_CHECK_EXCEPTION();
2494 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2500 BEGIN_OPCODE(op_get_by_id_self) {
2501 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2503 Cached property access: Attempts to get a cached property from the
2504 value base. If the cache misses, op_get_by_id_self reverts to
2507 int base = vPC[2].u.operand;
2508 JSValue* baseValue = r[base].jsValue(exec);
2510 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2511 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2512 StructureID* structureID = vPC[4].u.structureID;
2514 if (LIKELY(baseCell->structureID() == structureID)) {
2515 ASSERT(baseCell->isObject());
2516 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2517 int dst = vPC[1].u.operand;
2518 int offset = vPC[5].u.operand;
2520 ASSERT(baseObject->get(exec, codeBlock(r)->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2521 r[dst] = baseObject->getDirectOffset(offset);
2528 uncacheGetByID(codeBlock(r), vPC);
2531 BEGIN_OPCODE(op_get_by_id_proto) {
2532 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2534 Cached property access: Attempts to get a cached property from the
2535 value base's prototype. If the cache misses, op_get_by_id_proto
2536 reverts to op_get_by_id.
2538 int base = vPC[2].u.operand;
2539 JSValue* baseValue = r[base].jsValue(exec);
2541 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2542 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2543 StructureID* structureID = vPC[4].u.structureID;
2545 if (LIKELY(baseCell->structureID() == structureID)) {
2546 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2547 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2548 StructureID* protoStructureID = vPC[5].u.structureID;
2550 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2551 int dst = vPC[1].u.operand;
2552 int offset = vPC[6].u.operand;
2554 ASSERT(protoObject->get(exec, codeBlock(r)->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2555 r[dst] = protoObject->getDirectOffset(offset);
2563 uncacheGetByID(codeBlock(r), vPC);
2566 BEGIN_OPCODE(op_get_by_id_chain) {
2567 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2569 Cached property access: Attempts to get a cached property from the
2570 value base's prototype chain. If the cache misses, op_get_by_id_chain
2571 reverts to op_get_by_id.
2573 int base = vPC[2].u.operand;
2574 JSValue* baseValue = r[base].jsValue(exec);
2576 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2577 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2578 StructureID* structureID = vPC[4].u.structureID;
2580 if (LIKELY(baseCell->structureID() == structureID)) {
2581 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2582 size_t count = vPC[6].u.operand;
2583 RefPtr<StructureID>* end = it + count;
2585 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2587 baseObject = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2588 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2592 int dst = vPC[1].u.operand;
2593 int offset = vPC[7].u.operand;
2595 ASSERT(baseObject->get(exec, codeBlock(r)->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2596 r[dst] = baseObject->getDirectOffset(offset);
2605 uncacheGetByID(codeBlock(r), vPC);
2608 BEGIN_OPCODE(op_get_by_id_generic) {
2609 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2611 Generic property access: Gets the property named by identifier
2612 property from the value base, and puts the result in register dst.
2614 int dst = vPC[1].u.operand;
2615 int base = vPC[2].u.operand;
2616 int property = vPC[3].u.operand;
2618 Identifier& ident = codeBlock(r)->identifiers[property];
2619 JSValue* baseValue = r[base].jsValue(exec);
2620 PropertySlot slot(baseValue);
2621 JSValue* result = baseValue->get(exec, ident, slot);
2622 VM_CHECK_EXCEPTION();
2628 BEGIN_OPCODE(op_get_array_length) {
2629 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2631 Cached property access: Gets the length of the array in register base,
2632 and puts the result in register dst. If register base does not hold
2633 an array, op_get_array_length reverts to op_get_by_id.
2636 int base = vPC[2].u.operand;
2637 JSValue* baseValue = r[base].jsValue(exec);
2638 if (LIKELY(isJSArray(baseValue))) {
2639 int dst = vPC[1].u.operand;
2640 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2645 uncacheGetByID(codeBlock(r), vPC);
2648 BEGIN_OPCODE(op_get_string_length) {
2649 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2651 Cached property access: Gets the length of the string in register base,
2652 and puts the result in register dst. If register base does not hold
2653 a string, op_get_string_length reverts to op_get_by_id.
2656 int base = vPC[2].u.operand;
2657 JSValue* baseValue = r[base].jsValue(exec);
2658 if (LIKELY(isJSString(baseValue))) {
2659 int dst = vPC[1].u.operand;
2660 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2665 uncacheGetByID(codeBlock(r), vPC);
2668 BEGIN_OPCODE(op_put_by_id) {
2669 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2671 Generic property access: Sets the property named by identifier
2672 property, belonging to register base, to register value.
2674 Unlike many opcodes, this one does not write any output to
2678 int base = vPC[1].u.operand;
2679 int property = vPC[2].u.operand;
2680 int value = vPC[3].u.operand;
2682 CodeBlock* codeBlock = this->codeBlock(r);
2683 JSValue* baseValue = r[base].jsValue(exec);
2684 Identifier& ident = codeBlock->identifiers[property];
2685 PutPropertySlot slot;
2686 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2687 VM_CHECK_EXCEPTION();
2689 tryCachePutByID(exec, codeBlock, vPC, baseValue, slot);
2694 BEGIN_OPCODE(op_put_by_id_transition) {
2695 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2697 Cached property access: Attempts to set a new property with a cached transition
2698 property named by identifier property, belonging to register base,
2699 to register value. If the cache misses, op_put_by_id_transition
2700 reverts to op_put_by_id_generic.
2702 Unlike many opcodes, this one does not write any output to
2705 int base = vPC[1].u.operand;
2706 JSValue* baseValue = r[base].jsValue(exec);
2708 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2709 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2710 StructureID* oldStructureID = vPC[4].u.structureID;
2711 StructureID* newStructureID = vPC[5].u.structureID;
2713 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2714 ASSERT(baseCell->isObject());
2715 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2717 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2719 JSObject* proto = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2720 while (!proto->isNull()) {
2721 if (UNLIKELY(proto->structureID() != (*it).get())) {
2722 uncachePutByID(codeBlock(r), vPC);
2726 proto = static_cast<JSObject*>(proto->structureID()->prototypeForLookup(exec));
2729 baseObject->transitionTo(newStructureID);
2731 int value = vPC[3].u.operand;
2732 unsigned offset = vPC[7].u.operand;
2733 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock(r)->identifiers[vPC[2].u.operand])) == offset);
2734 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2741 uncachePutByID(codeBlock(r), vPC);
2744 BEGIN_OPCODE(op_put_by_id_replace) {
2745 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2747 Cached property access: Attempts to set a pre-existing, cached
2748 property named by identifier property, belonging to register base,
2749 to register value. If the cache misses, op_put_by_id_replace
2750 reverts to op_put_by_id.
2752 Unlike many opcodes, this one does not write any output to
2755 int base = vPC[1].u.operand;
2756 JSValue* baseValue = r[base].jsValue(exec);
2758 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2759 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2760 StructureID* structureID = vPC[4].u.structureID;
2762 if (LIKELY(baseCell->structureID() == structureID)) {
2763 ASSERT(baseCell->isObject());
2764 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2765 int value = vPC[3].u.operand;
2766 unsigned offset = vPC[5].u.operand;
2768 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock(r)->identifiers[vPC[2].u.operand])) == offset);
2769 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2776 uncachePutByID(codeBlock(r), vPC);
2779 BEGIN_OPCODE(op_put_by_id_generic) {
2780 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2782 Generic property access: Sets the property named by identifier
2783 property, belonging to register base, to register value.
2785 Unlike many opcodes, this one does not write any output to
2788 int base = vPC[1].u.operand;
2789 int property = vPC[2].u.operand;
2790 int value = vPC[3].u.operand;
2792 JSValue* baseValue = r[base].jsValue(exec);
2793 Identifier& ident = codeBlock(r)->identifiers[property];
2794 PutPropertySlot slot;
2795 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2796 VM_CHECK_EXCEPTION();
2801 BEGIN_OPCODE(op_del_by_id) {
2802 /* del_by_id dst(r) base(r) property(id)
2804 Converts register base to Object, deletes the property
2805 named by identifier property from the object, and writes a
2806 boolean indicating success (if true) or failure (if false)
2809 int dst = (++vPC)->u.operand;
2810 int base = (++vPC)->u.operand;
2811 int property = (++vPC)->u.operand;
2813 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2814 Identifier& ident = codeBlock(r)->identifiers[property];
2815 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2816 VM_CHECK_EXCEPTION();
2821 BEGIN_OPCODE(op_get_by_val) {
2822 /* get_by_val dst(r) base(r) property(r)
2824 Converts register base to Object, gets the property named
2825 by register property from the object, and puts the result
2826 in register dst. property is nominally converted to string
2827 but numbers are treated more efficiently.
2829 int dst = (++vPC)->u.operand;
2830 int base = (++vPC)->u.operand;
2831 int property = (++vPC)->u.operand;
2833 JSValue* baseValue = r[base].jsValue(exec);
2834 JSValue* subscript = r[property].jsValue(exec);
2839 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2840 if (LIKELY(isUInt32)) {
2841 if (isJSArray(baseValue)) {
2842 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2843 if (jsArray->canGetIndex(i))
2844 result = jsArray->getIndex(i);
2846 result = jsArray->JSArray::get(exec, i);
2847 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2848 result = static_cast<JSString*>(baseValue)->getIndex(&exec->globalData(), i);
2850 result = baseValue->get(exec, i);
2852 Identifier property(exec, subscript->toString(exec));
2853 result = baseValue->get(exec, property);
2856 VM_CHECK_EXCEPTION();
2861 BEGIN_OPCODE(op_put_by_val) {
2862 /* put_by_val base(r) property(r) value(r)
2864 Sets register value on register base as the property named
2865 by register property. Base is converted to object
2866 first. register property is nominally converted to string
2867 but numbers are treated more efficiently.
2869 Unlike many opcodes, this one does not write any output to
2872 int base = (++vPC)->u.operand;
2873 int property = (++vPC)->u.operand;
2874 int value = (++vPC)->u.operand;
2876 JSValue* baseValue = r[base].jsValue(exec);
2877 JSValue* subscript = r[property].jsValue(exec);
2881 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2882 if (LIKELY(isUInt32)) {
2883 if (isJSArray(baseValue)) {
2884 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2885 if (jsArray->canSetIndex(i))
2886 jsArray->setIndex(i, r[value].jsValue(exec));
2888 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2890 baseValue->put(exec, i, r[value].jsValue(exec));
2892 Identifier property(exec, subscript->toString(exec));
2893 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2894 PutPropertySlot slot;
2895 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2899 VM_CHECK_EXCEPTION();
2903 BEGIN_OPCODE(op_del_by_val) {
2904 /* del_by_val dst(r) base(r) property(r)
2906 Converts register base to Object, deletes the property
2907 named by register property from the object, and writes a
2908 boolean indicating success (if true) or failure (if false)
2911 int dst = (++vPC)->u.operand;
2912 int base = (++vPC)->u.operand;
2913 int property = (++vPC)->u.operand;
2915 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2917 JSValue* subscript = r[property].jsValue(exec);
2920 if (subscript->getUInt32(i))
2921 result = jsBoolean(baseObj->deleteProperty(exec, i));
2923 VM_CHECK_EXCEPTION();
2924 Identifier property(exec, subscript->toString(exec));
2925 VM_CHECK_EXCEPTION();
2926 result = jsBoolean(baseObj->deleteProperty(exec, property));
2929 VM_CHECK_EXCEPTION();
2934 BEGIN_OPCODE(op_put_by_index) {
2935 /* put_by_index base(r) property(n) value(r)
2937 Sets register value on register base as the property named
2938 by the immediate number property. Base is converted to
2941 Unlike many opcodes, this one does not write any output to
2944 This opcode is mainly used to initialize array literals.
2946 int base = (++vPC)->u.operand;
2947 unsigned property = (++vPC)->u.operand;
2948 int value = (++vPC)->u.operand;
2950 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2955 BEGIN_OPCODE(op_loop) {
2956 /* loop target(offset)
2958 Jumps unconditionally to offset target from the current
2961 Additionally this loop instruction may terminate JS execution is
2962 the JS timeout is reached.
2964 #if DUMP_OPCODE_STATS
2965 OpcodeStats::resetLastInstruction();
2967 int target = (++vPC)->u.operand;
2968 CHECK_FOR_TIMEOUT();
2972 BEGIN_OPCODE(op_jmp) {
2973 /* jmp target(offset)
2975 Jumps unconditionally to offset target from the current
2978 #if DUMP_OPCODE_STATS
2979 OpcodeStats::resetLastInstruction();
2981 int target = (++vPC)->u.operand;
2986 BEGIN_OPCODE(op_loop_if_true) {
2987 /* loop_if_true cond(r) target(offset)
2989 Jumps to offset target from the current instruction, if and
2990 only if register cond converts to boolean as true.
2992 Additionally this loop instruction may terminate JS execution is
2993 the JS timeout is reached.
2995 int cond = (++vPC)->u.operand;
2996 int target = (++vPC)->u.operand;
2997 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2999 CHECK_FOR_TIMEOUT();
3006 BEGIN_OPCODE(op_jtrue) {
3007 /* jtrue cond(r) target(offset)
3009 Jumps to offset target from the current instruction, if and
3010 only if register cond converts to boolean as true.
3012 int cond = (++vPC)->u.operand;
3013 int target = (++vPC)->u.operand;
3014 if (r[cond].jsValue(exec)->toBoolean(exec)) {
3022 BEGIN_OPCODE(op_jfalse) {
3023 /* jfalse cond(r) target(offset)
3025 Jumps to offset target from the current instruction, if and
3026 only if register cond converts to boolean as false.
3028 int cond = (++vPC)->u.operand;
3029 int target = (++vPC)->u.operand;
3030 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
3038 BEGIN_OPCODE(op_loop_if_less) {
3039 /* loop_if_less src1(r) src2(r) target(offset)
3041 Checks whether register src1 is less than register src2, as
3042 with the ECMAScript '<' operator, and then jumps to offset
3043 target from the current instruction, if and only if the
3044 result of the comparison is true.
3046 Additionally this loop instruction may terminate JS execution is
3047 the JS timeout is reached.
3049 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3050 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3051 int target = (++vPC)->u.operand;
3053 bool result = jsLess(exec, src1, src2);
3054 VM_CHECK_EXCEPTION();
3058 CHECK_FOR_TIMEOUT();
3065 BEGIN_OPCODE(op_loop_if_lesseq) {
3066 /* loop_if_lesseq src1(r) src2(r) target(offset)
3068 Checks whether register src1 is less than or equal to register
3069 src2, as with the ECMAScript '<=' operator, and then jumps to
3070 offset target from the current instruction, if and only if the
3071 result of the comparison is true.
3073 Additionally this loop instruction may terminate JS execution is
3074 the JS timeout is reached.
3076 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3077 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3078 int target = (++vPC)->u.operand;
3080 bool result = jsLessEq(exec, src1, src2);
3081 VM_CHECK_EXCEPTION();
3085 CHECK_FOR_TIMEOUT();
3092 BEGIN_OPCODE(op_jnless) {
3093 /* jnless src1(r) src2(r) target(offset)
3095 Checks whether register src1 is less than register src2, as
3096 with the ECMAScript '<' operator, and then jumps to offset
3097 target from the current instruction, if and only if the
3098 result of the comparison is false.
3100 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3101 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3102 int target = (++vPC)->u.operand;
3104 bool result = jsLess(exec, src1, src2);
3105 VM_CHECK_EXCEPTION();
3115 BEGIN_OPCODE(op_switch_imm) {
3116 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3118 Performs a range checked switch on the scrutinee value, using
3119 the tableIndex-th immediate switch jump table. If the scrutinee value
3120 is an immediate number in the range covered by the referenced jump
3121 table, and the value at jumpTable[scrutinee value] is non-zero, then
3122 that value is used as the jump offset, otherwise defaultOffset is used.
3124 int tableIndex = (++vPC)->u.operand;
3125 int defaultOffset = (++vPC)->u.operand;
3126 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3127 if (!JSImmediate::isNumber(scrutinee))
3128 vPC += defaultOffset;
3130 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3131 vPC += codeBlock(r)->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
3135 BEGIN_OPCODE(op_switch_char) {
3136 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3138 Performs a range checked switch on the scrutinee value, using
3139 the tableIndex-th character switch jump table. If the scrutinee value
3140 is a single character string in the range covered by the referenced jump
3141 table, and the value at jumpTable[scrutinee value] is non-zero, then
3142 that value is used as the jump offset, otherwise defaultOffset is used.
3144 int tableIndex = (++vPC)->u.operand;
3145 int defaultOffset = (++vPC)->u.operand;
3146 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3147 if (!scrutinee->isString())
3148 vPC += defaultOffset;
3150 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
3151 if (value->size() != 1)
3152 vPC += defaultOffset;
3154 vPC += codeBlock(r)->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
3158 BEGIN_OPCODE(op_switch_string) {
3159 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3161 Performs a sparse hashmap based switch on the value in the scrutinee
3162 register, using the tableIndex-th string switch jump table. If the
3163 scrutinee value is a string that exists as a key in the referenced
3164 jump table, then the value associated with the string is used as the
3165 jump offset, otherwise defaultOffset is used.
3167 int tableIndex = (++vPC)->u.operand;
3168 int defaultOffset = (++vPC)->u.operand;
3169 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3170 if (!scrutinee->isString())
3171 vPC += defaultOffset;
3173 vPC += codeBlock(r)->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
3176 BEGIN_OPCODE(op_new_func) {
3177 /* new_func dst(r) func(f)
3179 Constructs a new Function instance from function func and
3180 the current scope chain using the original Function
3181 constructor, using the rules for function declarations, and
3182 puts the result in register dst.
3184 int dst = (++vPC)->u.operand;
3185 int func = (++vPC)->u.operand;
3187 r[dst] = codeBlock(r)->functions[func]->makeFunction(exec, scopeChain(r));
3192 BEGIN_OPCODE(op_new_func_exp) {
3193 /* new_func_exp dst(r) func(f)
3195 Constructs a new Function instance from function func and
3196 the current scope chain using the original Function
3197 constructor, using the rules for function expressions, and
3198 puts the result in register dst.
3200 int dst = (++vPC)->u.operand;
3201 int func = (++vPC)->u.operand;
3203 r[dst] = codeBlock(r)->functionExpressions[func]->makeFunction(exec, scopeChain(r));
3208 BEGIN_OPCODE(op_call_eval) {
3209 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3211 Call a function named "eval" with no explicit "this" value
3212 (which may therefore be the eval operator). If register
3213 thisVal is the global object, and register func contains
3214 that global object's original global eval function, then
3215 perform the eval operator in local scope (interpreting
3216 the argument registers as for the "call"
3217 opcode). Otherwise, act exactly as the "call" opcode would.
3220 int dst = (++vPC)->u.operand;
3221 int func = (++vPC)->u.operand;
3222 int thisVal = (++vPC)->u.operand;
3223 int firstArg = (++vPC)->u.operand;
3224 int argCount = (++vPC)->u.operand;
3225 ++vPC; // registerOffset
3227 JSValue* funcVal = r[func].jsValue(exec);
3228 JSValue* baseVal = r[thisVal].jsValue(exec);
3230 ScopeChainNode* scopeChain = this->scopeChain(r);
3231 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
3232 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock(r)->thisRegister].jsValue(exec));
3233 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
3243 // We didn't find the blessed version of eval, so reset vPC and process
3244 // this instruction as a normal function call, supplying the proper 'this'
3247 r[thisVal] = baseVal->toThisObject(exec);
3249 #if HAVE(COMPUTED_GOTO)
3250 // Hack around gcc performance quirk by performing an indirect goto
3251 // in order to set the vPC -- attempting to do so directly results in a
3252 // significant regression.
3253 goto *op_call_indirect; // indirect goto -> op_call
3255 // fall through to op_call
3257 BEGIN_OPCODE(op_call) {
3258 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n) registerOffset(n)
3260 Perform a function call. Specifically, call register func
3261 with a "this" value of register thisVal, and put the result
3264 The arguments start at register firstArg and go up to
3265 argCount, but the "this" value is considered an implicit
3266 first argument, so the argCount should be one greater than
3267 the number of explicit arguments passed, and the register
3268 after firstArg should contain the actual first
3269 argument. This opcode will copy from the thisVal register
3270 to the firstArg register, unless the register index of
3271 thisVal is the special missing this object marker, which is
3272 2^31-1; in that case, the global object will be used as the
3275 If func is a native code function, then this opcode calls
3276 it and returns the value immediately.
3278 But if it is a JS function, then the current scope chain
3279 and code block is set to the function's, and we slide the
3280 register window so that the arguments would form the first
3281 few local registers of the called function's register
3282 window. In addition, a call frame header is written
3283 immediately before the arguments; see the call frame
3284 documentation for an explanation of how many registers a
3285 call frame takes and what they contain. That many registers
3286 before the firstArg register will be overwritten by the
3287 call. In addition, any registers higher than firstArg +
3288 argCount may be overwritten. Once this setup is complete,
3289 execution continues from the called function's first
3290 argument, and does not return until a "ret" opcode is
3294 int dst = (++vPC)->u.operand;
3295 int func = (++vPC)->u.operand;
3296 int thisVal = (++vPC)->u.operand;
3297 int firstArg = (++vPC)->u.operand;
3298 int argCount = (++vPC)->u.operand;
3299 int registerOffset = (++vPC)->u.operand;
3301 JSValue* v = r[func].jsValue(exec);
3304 CallType callType = v->getCallData(callData);
3306 if (callType == CallTypeJS) {
3307 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3308 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3309 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3311 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3313 Register* savedR = r;
3315 r = slideRegisterWindowForCall(newCodeBlock, registerFile, r, registerOffset, argCount);
3318 exceptionValue = createStackOverflowError(CallFrame::create(r));
3322 initializeCallFrame(r, newCodeBlock, vPC + 1, callDataScopeChain, savedR, dst, argCount, v);
3324 if (*enabledProfilerReference)
3325 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3327 vPC = newCodeBlock->instructions.begin();
3329 #if DUMP_OPCODE_STATS
3330 OpcodeStats::resetLastInstruction();
3336 if (callType == CallTypeHost) {
3337 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3338 ArgList args(r + firstArg + 1, argCount - 1);
3340 ScopeChainNode* scopeChain = this->scopeChain(r);
3341 initializeCallFrame(r + registerOffset, 0, vPC + 1, scopeChain, r, dst, argCount, v);
3342 ExecState* callFrame = CallFrame::create(r + registerOffset);
3344 if (*enabledProfilerReference)
3345 (*enabledProfilerReference)->willExecute(callFrame, static_cast<JSObject*>(v));
3347 MACHINE_SAMPLING_callingHostFunction();
3349 JSValue* returnValue = callData.native.function(callFrame, static_cast<JSObject*>(v), thisValue, args);
3350 VM_CHECK_EXCEPTION();
3352 r[dst] = returnValue;
3354 if (*enabledProfilerReference)
3355 (*enabledProfilerReference)->didExecute(CallFrame::create(r), static_cast<JSObject*>(v));
3361 ASSERT(callType == CallTypeNone);
3363 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock(r));
3366 BEGIN_OPCODE(op_tear_off_activation) {
3367 int src = (++vPC)->u.operand;
3368 JSActivation* activation = static_cast<JSActivation*>(r[src].getJSValue());
3369 ASSERT(codeBlock(r)->needsFullScopeChain);
3370 ASSERT(activation->isObject(&JSActivation::info));
3372 Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
3373 ASSERT(!arguments || arguments->isObject(&Arguments::info));
3374 activation->copyRegisters(arguments);
3379 BEGIN_OPCODE(op_tear_off_arguments) {
3380 Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
3381 ASSERT(codeBlock(r)->usesArguments && !codeBlock(r)->needsFullScopeChain);
3382 ASSERT(arguments->isObject(&Arguments::info));
3384 arguments->copyRegisters();
3389 BEGIN_OPCODE(op_ret) {
3392 Return register result as the return value of the current
3393 function call, writing it into the caller's expected return
3394 value register. In addition, unwind one call frame and
3395 restore the scope chain, code block instruction pointer and
3396 register base to those of the calling function.
3399 int result = (++vPC)->u.operand;
3401 if (*enabledProfilerReference)
3402 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
3404 if (codeBlock(r)->needsFullScopeChain)
3405 scopeChain(r)->deref();
3407 JSValue* returnValue = r[result].jsValue(exec);
3409 vPC = r[RegisterFile::ReturnPC].vPC();
3410 int dst = r[RegisterFile::ReturnValueRegister].i();
3411 r = r[RegisterFile::CallerRegisters].r();
3413 if (isHostCallFrame(r))
3416 r[dst] = returnValue;
3420 BEGIN_OPCODE(op_enter) {
3423 Initializes local variables to undefined and fills constant
3424 registers with their values. If the code block requires an
3425 activation, enter_with_activation should be used instead.
3427 This opcode should only be used at the beginning of a code
3432 CodeBlock* codeBlock = this->codeBlock(r);
3434 for (size_t count = codeBlock->numVars; i < count; ++i)
3435 r[i] = jsUndefined();
3437 for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
3438 r[i] = codeBlock->constantRegisters[j];
3443 BEGIN_OPCODE(op_enter_with_activation) {
3444 /* enter_with_activation dst(r)
3446 Initializes local variables to undefined, fills constant
3447 registers with their values, creates an activation object,
3448 and places the new activation both in dst and at the top
3449 of the scope chain. If the code block does not require an
3450 activation, enter should be used instead.
3452 This opcode should only be used at the beginning of a code
3457 CodeBlock* codeBlock = this->codeBlock(r);
3459 for (size_t count = codeBlock->numVars; i < count; ++i)
3460 r[i] = jsUndefined();
3462 for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
3463 r[i] = codeBlock->constantRegisters[j];
3465 int dst = (++vPC)->u.operand;
3466 JSActivation* activation = new (globalData) JSActivation(exec, static_cast<FunctionBodyNode*>(codeBlock->ownerNode), r);
3467 r[dst] = activation;
3468 r[RegisterFile::ScopeChain] = scopeChain(r)->copy()->push(activation);
3473 BEGIN_OPCODE(op_convert_this) {
3474 int thisRegister = (++vPC)->u.operand;
3475 JSValue* thisVal = r[thisRegister].getJSValue();
3476 if (thisVal->needsThisConversion())
3477 r[thisRegister] = thisVal->toThisObject(exec);
3482 BEGIN_OPCODE(op_create_arguments) {
3485 Creates the 'arguments' object and places it in both the
3486 'arguments' call frame slot and the local 'arguments'
3489 This opcode should only be used at the beginning of a code
3493 Arguments* arguments = new (globalData) Arguments(exec, r);
3494 r[RegisterFile::OptionalCalleeArguments] = arguments;
3495 r[RegisterFile::ArgumentsRegister] = arguments;
3500 BEGIN_OPCODE(op_construct) {
3501 /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n) registerOffset(n)
3503 Invoke register "constr" as a constructor. For JS
3504 functions, the calling convention is exactly as for the
3505 "call" opcode, except that the "this" value is a newly
3506 created Object. For native constructors, a null "this"
3507 value is passed. In either case, the firstArg and argCount
3508 registers are interpreted as for the "call" opcode.
3510 Register constrProto must contain the prototype property of
3511 register constsr. This is to enable polymorphic inline
3512 caching of this lookup.
3515 int dst = (++vPC)->u.operand;
3516 int constr = (++vPC)->u.operand;
3517 int constrProto = (++vPC)->u.operand;
3518 int firstArg = (++vPC)->u.operand;
3519 int argCount = (++vPC)->u.operand;
3520 int registerOffset = (++vPC)->u.operand;