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 "BatchedTransitionOptimizer.h"
34 #include "CodeBlock.h"
35 #include "DebuggerCallFrame.h"
36 #include "ExceptionHelpers.h"
37 #include "ExecState.h"
38 #include "GlobalEvalFunction.h"
39 #include "JSActivation.h"
41 #include "JSFunction.h"
42 #include "JSNotAnObject.h"
43 #include "JSPropertyNameIterator.h"
44 #include "JSStaticScopeObject.h"
46 #include "ObjectPrototype.h"
49 #include "RegExpObject.h"
50 #include "RegExpPrototype.h"
52 #include "collector.h"
54 #include "operations.h"
55 #include "SamplingTool.h"
59 #include <mach/mach.h>
78 // Preferred number of milliseconds between each timeout check
79 static const int preferredScriptCheckTimeInterval = 1000;
81 #if HAVE(COMPUTED_GOTO)
82 static void* op_throw_end_indirect;
83 static void* op_call_indirect;
88 ALWAYS_INLINE static Instruction* vPCForPC(CodeBlock* codeBlock, void* pc)
90 if (pc >= codeBlock->instructions.begin() && pc < codeBlock->instructions.end())
91 return static_cast<Instruction*>(pc);
93 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(pc));
94 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(pc);
95 return codeBlock->instructions.begin() + vPCIndex;
100 ALWAYS_INLINE static Instruction* vPCForPC(CodeBlock*, void* pc)
102 return static_cast<Instruction*>(pc);
105 #endif // #ENABLE(CTI)
107 // Returns the depth of the scope chain within a given call frame.
108 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
110 if (!codeBlock->needsFullScopeChain)
113 ScopeChainIterator iter = sc.begin();
114 ScopeChainIterator end = sc.end();
115 while (!(*iter)->isActivationObject()) {
124 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
125 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
126 static bool fastIsNumber(JSValue* value, double& arg)
128 if (JSImmediate::isNumber(value))
129 arg = JSImmediate::getTruncatedInt32(value);
130 else if (Heap::isNumber(static_cast<JSCell*>(value)))
131 arg = static_cast<JSNumberCell*>(value)->value();
137 // FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
138 static bool fastToInt32(JSValue* value, int32_t& arg)
140 if (JSImmediate::isNumber(value))
141 arg = JSImmediate::getTruncatedInt32(value);
142 else if (Heap::isNumber(static_cast<JSCell*>(value)))
143 arg = static_cast<JSNumberCell*>(value)->toInt32();
149 static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
151 if (JSImmediate::isNumber(value)) {
152 if (JSImmediate::getTruncatedUInt32(value, arg))
155 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
157 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
158 arg = static_cast<JSNumberCell*>(value)->toUInt32();
164 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
166 if (JSImmediate::areBothImmediateNumbers(v1, v2))
167 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
171 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
174 Machine* machine = exec->machine();
175 if (machine->isJSString(v1) && machine->isJSString(v2))
176 return static_cast<const JSString*>(v1)->value() < static_cast<const JSString*>(v2)->value();
180 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
181 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
183 if (wasNotString1 | wasNotString2)
186 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
189 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
191 if (JSImmediate::areBothImmediateNumbers(v1, v2))
192 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
196 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
199 Machine* machine = exec->machine();
200 if (machine->isJSString(v1) && machine->isJSString(v2))
201 return !(static_cast<const JSString*>(v2)->value() < static_cast<const JSString*>(v1)->value());
205 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
206 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
208 if (wasNotString1 | wasNotString2)
211 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
214 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
216 // exception for the Date exception in defaultValue()
217 JSValue* p1 = v1->toPrimitive(exec);
218 JSValue* p2 = v2->toPrimitive(exec);
220 if (p1->isString() || p2->isString()) {
221 RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
223 return throwOutOfMemoryError(exec);
224 return jsString(exec, value.release());
227 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
230 // Fast-path choices here are based on frequency data from SunSpider:
231 // <times> Add case: <t1> <t2>
232 // ---------------------------
233 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
234 // 247412 Add case: 5 5
235 // 20900 Add case: 5 6
236 // 13962 Add case: 5 3
237 // 4000 Add case: 3 5
239 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
243 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
244 return jsNumber(exec, left + right);
246 if (v1->isString() && v2->isString()) {
247 RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
249 return throwOutOfMemoryError(exec);
250 return jsString(exec, value.release());
253 // All other cases are pretty uncommon
254 return jsAddSlowCase(exec, v1, v2);
257 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
259 if (v->isUndefined())
260 return jsNontrivialString(exec, "undefined");
262 return jsNontrivialString(exec, "boolean");
264 return jsNontrivialString(exec, "number");
266 return jsNontrivialString(exec, "string");
268 // Return "undefined" for objects that should be treated
269 // as null when doing comparisons.
270 if (static_cast<JSObject*>(v)->structureID()->typeInfo().masqueradesAsUndefined())
271 return jsNontrivialString(exec, "undefined");
273 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
274 return jsNontrivialString(exec, "function");
276 return jsNontrivialString(exec, "object");
279 static bool jsIsObjectType(JSValue* v)
281 if (JSImmediate::isImmediate(v))
284 JSType type = static_cast<JSCell*>(v)->structureID()->typeInfo().type();
285 if (type == NumberType || type == StringType)
287 if (type == ObjectType) {
288 if (static_cast<JSObject*>(v)->structureID()->typeInfo().masqueradesAsUndefined())
291 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
297 static bool jsIsFunctionType(JSValue* v)
301 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
307 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
309 int dst = (vPC + 1)->u.operand;
310 int property = (vPC + 2)->u.operand;
312 ScopeChainIterator iter = scopeChain->begin();
313 ScopeChainIterator end = scopeChain->end();
316 Identifier& ident = codeBlock->identifiers[property];
319 PropertySlot slot(o);
320 if (o->getPropertySlot(exec, ident, slot)) {
321 JSValue* result = slot.getValue(exec, ident);
322 exceptionValue = exec->exception();
328 } while (++iter != end);
329 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
333 static bool NEVER_INLINE resolveSkip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
335 int dst = (vPC + 1)->u.operand;
336 int property = (vPC + 2)->u.operand;
337 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
339 ScopeChainIterator iter = scopeChain->begin();
340 ScopeChainIterator end = scopeChain->end();
346 Identifier& ident = codeBlock->identifiers[property];
349 PropertySlot slot(o);
350 if (o->getPropertySlot(exec, ident, slot)) {
351 JSValue* result = slot.getValue(exec, ident);
352 exceptionValue = exec->exception();
358 } while (++iter != end);
359 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
363 static bool NEVER_INLINE resolveGlobal(ExecState* exec, Instruction* vPC, Register* r, CodeBlock* codeBlock, JSValue*& exceptionValue)
365 int dst = (vPC + 1)->u.operand;
366 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
367 ASSERT(globalObject->isGlobalObject());
368 int property = (vPC + 3)->u.operand;
369 StructureID* structureID = (vPC + 4)->u.structureID;
370 int offset = (vPC + 5)->u.operand;
372 if (structureID == globalObject->structureID()) {
373 r[dst] = globalObject->getDirectOffset(offset);
377 Identifier& ident = codeBlock->identifiers[property];
378 PropertySlot slot(globalObject);
379 if (globalObject->getPropertySlot(exec, ident, slot)) {
380 JSValue* result = slot.getValue(exec, ident);
381 if (slot.isCacheable()) {
382 if (vPC[4].u.structureID)
383 vPC[4].u.structureID->deref();
384 globalObject->structureID()->ref();
385 vPC[4] = globalObject->structureID();
386 vPC[5] = slot.cachedOffset();
391 exceptionValue = exec->exception();
398 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
402 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
404 ScopeChainIterator iter = scopeChain->begin();
405 ScopeChainIterator next = iter;
407 ScopeChainIterator end = scopeChain->end();
414 if (next == end || base->getPropertySlot(exec, property, slot))
421 ASSERT_NOT_REACHED();
425 NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
427 int dst = (vPC + 1)->u.operand;
428 int property = (vPC + 2)->u.operand;
429 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
432 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
434 int baseDst = (vPC + 1)->u.operand;
435 int propDst = (vPC + 2)->u.operand;
436 int property = (vPC + 3)->u.operand;
438 ScopeChainIterator iter = scopeChain->begin();
439 ScopeChainIterator end = scopeChain->end();
441 // FIXME: add scopeDepthIsZero optimization
445 Identifier& ident = codeBlock->identifiers[property];
449 PropertySlot slot(base);
450 if (base->getPropertySlot(exec, ident, slot)) {
451 JSValue* result = slot.getValue(exec, ident);
452 exceptionValue = exec->exception();
460 } while (iter != end);
462 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
466 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
468 int baseDst = (vPC + 1)->u.operand;
469 int funcDst = (vPC + 2)->u.operand;
470 int property = (vPC + 3)->u.operand;
472 ScopeChainIterator iter = scopeChain->begin();
473 ScopeChainIterator end = scopeChain->end();
475 // FIXME: add scopeDepthIsZero optimization
479 Identifier& ident = codeBlock->identifiers[property];
483 PropertySlot slot(base);
484 if (base->getPropertySlot(exec, ident, slot)) {
485 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
486 // However, section 10.2.3 says that in the case where the value provided
487 // by the caller is null, the global object should be used. It also says
488 // that the section does not apply to internal functions, but for simplicity
489 // of implementation we use the global object anyway here. This guarantees
490 // that in host objects you always get a valid object for this.
491 // We also handle wrapper substitution for the global object at the same time.
492 JSObject* thisObj = base->toThisObject(exec);
493 JSValue* result = slot.getValue(exec, ident);
494 exceptionValue = exec->exception();
498 r[baseDst] = thisObj;
503 } while (iter != end);
505 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
509 #if HAVE(COMPUTED_GOTO)
510 Opcode Machine::s_opcodeTable[numOpcodeIDs];
513 Opcode Machine::getOpcode(OpcodeID id)
515 #if HAVE(COMPUTED_GOTO)
516 return s_opcodeTable[id];
522 ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argc, JSValue* function)
524 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
525 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
526 callFrame[RegisterFile::CallerRegisters] = r;
527 callFrame[RegisterFile::ReturnPC] = vPC + 1;
528 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
529 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
530 callFrame[RegisterFile::Callee] = function;
531 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
534 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, size_t registerOffset, int argc, JSValue*& exceptionValue)
536 size_t size = r - registerBase + registerOffset + newCodeBlock->numCalleeRegisters;
538 if (argc == newCodeBlock->numParameters) { // correct number of arguments
539 if (!registerFile->grow(size)) {
540 exceptionValue = createStackOverflowError(exec);
544 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
545 size_t omittedArgCount = newCodeBlock->numParameters - argc;
546 registerOffset += omittedArgCount;
547 size += omittedArgCount;
548 if (!registerFile->grow(size)) {
549 exceptionValue = createStackOverflowError(exec);
554 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
555 for (size_t i = 0; i < omittedArgCount; ++i)
556 argv[i] = jsUndefined();
557 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
558 size_t numParameters = newCodeBlock->numParameters;
559 registerOffset += numParameters;
560 size += numParameters;
562 if (!registerFile->grow(size)) {
563 exceptionValue = createStackOverflowError(exec);
568 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
569 for (size_t i = 0; i < numParameters; ++i)
570 argv[i + argc] = argv[i];
576 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
578 if (newCodeBlock->needsFullScopeChain) {
579 JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
580 r[RegisterFile::OptionalCalleeActivation] = activation;
582 return callDataScopeChain->copy()->push(activation);
585 return callDataScopeChain;
588 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
590 if (value->isObject())
592 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
596 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
599 return jsUndefined();
601 JSValue* program = r[argv + 1].jsValue(exec);
603 if (!program->isString())
606 Profiler** profiler = Profiler::enabledProfilerReference();
608 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
610 UString programSource = static_cast<JSString*>(program)->value();
612 RefPtr<EvalNode> evalNode = callingCodeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
616 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + 1 + RegisterFile::CallFrameHeaderSize, scopeChain, &exceptionValue);
619 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
627 , m_ctiArrayLengthTrampoline(0)
628 , m_ctiStringLengthTrampoline(0)
629 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
633 , m_timeAtLastCheckTimeout(0)
635 , m_timeoutCheckCount(0)
636 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
639 privateExecute(InitializeAndReturn);
641 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
642 void* storage = fastMalloc(sizeof(CollectorBlock));
644 JSArray* jsArray = new (storage) JSArray(JSArray::createStructureID(jsNull()));
645 m_jsArrayVptr = jsArray->vptr();
646 static_cast<JSCell*>(jsArray)->~JSCell();
648 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
649 m_jsStringVptr = jsString->vptr();
650 static_cast<JSCell*>(jsString)->~JSCell();
652 JSFunction* jsFunction = new (storage) JSFunction(JSFunction::createStructureID(jsNull()));
653 m_jsFunctionVptr = jsFunction->vptr();
654 static_cast<JSCell*>(jsFunction)->~JSCell();
662 if (m_ctiArrayLengthTrampoline)
663 fastFree(m_ctiArrayLengthTrampoline);
664 if (m_ctiStringLengthTrampoline)
665 fastFree(m_ctiStringLengthTrampoline);
671 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
673 ScopeChain sc(scopeChain);
674 JSGlobalObject* globalObject = sc.globalObject();
675 codeBlock->dump(globalObject->globalExec());
676 dumpRegisters(codeBlock, registerFile, r);
679 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
681 printf("Register frame: \n\n");
682 printf("----------------------------------------------------\n");
683 printf(" use | address | value \n");
684 printf("----------------------------------------------------\n");
689 if (codeBlock->codeType == GlobalCode) {
690 it = registerFile->lastGlobal();
691 end = it + registerFile->numGlobals();
693 printf("[global var] | %10p | %10p \n", it, (*it).v());
696 printf("----------------------------------------------------\n");
699 it = r - RegisterFile::CallFrameHeaderSize - codeBlock->numParameters;
700 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
701 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
704 printf("[param] | %10p | %10p \n", it, (*it).v());
708 printf("----------------------------------------------------\n");
710 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
711 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
712 printf("[CallerRegisters] | %10p | %10p \n", it, (*it).v()); ++it;
713 printf("[ReturnPC] | %10p | %10p \n", it, (*it).v()); ++it;
714 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
715 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
716 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
717 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
718 printf("----------------------------------------------------\n");
720 int registerCount = 0;
722 end = it + codeBlock->numVars;
725 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
730 printf("----------------------------------------------------\n");
732 end = it + codeBlock->numConstants;
735 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
740 printf("----------------------------------------------------\n");
742 end = it + codeBlock->numCalleeRegisters - codeBlock->numConstants - codeBlock->numVars;
745 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
750 printf("----------------------------------------------------\n");
755 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
757 bool Machine::isOpcode(Opcode opcode)
759 #if HAVE(COMPUTED_GOTO)
760 return opcode != HashTraits<Opcode>::emptyValue()
761 && !HashTraits<Opcode>::isDeletedValue(opcode)
762 && m_opcodeIDTable.contains(opcode);
764 return opcode >= 0 && opcode <= op_end;
770 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
772 CodeBlock* oldCodeBlock = codeBlock;
774 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
775 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
776 if (r[RegisterFile::Callee].jsValue(exec))
777 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
779 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
782 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
783 if (r[RegisterFile::Callee].jsValue(exec))
784 profiler->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
786 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
789 if (oldCodeBlock->needsFullScopeChain)
792 // If this call frame created an activation, tear it off.
793 if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
794 ASSERT(activation->isActivationObject());
795 activation->copyRegisters();
798 codeBlock = r[RegisterFile::CallerCodeBlock].codeBlock();
802 scopeChain = r[RegisterFile::CallerScopeChain].scopeChain();
803 vPC = vPCForPC(codeBlock, r[RegisterFile::ReturnPC].v());
804 r = r[RegisterFile::CallerRegisters].r();
805 exec->m_callFrame = r;
810 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
812 // Set up the exception object
814 if (exceptionValue->isObject()) {
815 JSObject* exception = static_cast<JSObject*>(exceptionValue);
816 if (exception->isNotAnObjectErrorStub()) {
817 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
818 exceptionValue = exception;
820 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
821 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
822 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
823 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
824 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
825 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
830 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
831 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
833 // We only hit this path for error messages and throw statements, which don't have a specific failure position
834 // So we just give the full range of the error/throw statement.
835 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
836 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
838 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
839 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
840 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
843 if (exception->isWatchdogException()) {
844 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
845 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
852 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
853 DebuggerCallFrame debuggerCallFrame(exec, 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, scopeChain, r))
867 // Now unwind the scope chain within the exception handler's call frame.
869 ScopeChain sc(scopeChain);
870 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
871 ASSERT(scopeDelta >= 0);
874 setScopeChain(exec, scopeChain, sc.node());
879 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
881 ASSERT(!exec->hadException());
883 if (m_reentryDepth >= MaxReentryDepth) {
884 *exception = createStackOverflowError(exec);
888 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
890 size_t oldSize = m_registerFile.size();
891 size_t newSize = oldSize + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->numCalleeRegisters;
892 if (!m_registerFile.grow(newSize)) {
893 *exception = createStackOverflowError(exec);
897 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
898 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
899 globalObject->copyGlobalsTo(m_registerFile);
901 Register* r = m_registerFile.base() + oldSize + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize;
902 r[codeBlock->thisRegister] = thisObj;
903 initializeCallFrame(r, 0, 0, 0, 0, 0, 0, 0);
905 if (codeBlock->needsFullScopeChain)
906 scopeChain = scopeChain->copy();
908 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
910 Profiler** profiler = Profiler::enabledProfilerReference();
912 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
916 if (!codeBlock->ctiCode)
917 CTI::compile(this, exec, codeBlock);
918 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
920 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
924 MACHINE_SAMPLING_privateExecuteReturned();
927 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
929 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
930 lastGlobalObject->copyGlobalsTo(m_registerFile);
932 m_registerFile.shrink(oldSize);
936 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
938 ASSERT(!exec->hadException());
940 if (m_reentryDepth >= MaxReentryDepth) {
941 *exception = createStackOverflowError(exec);
945 size_t oldSize = m_registerFile.size();
946 int argc = 1 + args.size(); // implicit "this" parameter
948 if (!m_registerFile.grow(oldSize + argc)) {
949 *exception = createStackOverflowError(exec);
953 Register* argv = m_registerFile.base() + oldSize;
957 ArgList::const_iterator end = args.end();
958 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
961 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
962 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), argv, argc + RegisterFile::CallFrameHeaderSize, argc, *exception);
963 if (UNLIKELY(*exception != 0)) {
964 m_registerFile.shrink(oldSize);
967 // a 0 codeBlock indicates a built-in caller
968 initializeCallFrame(r, 0, 0, 0, argv, 0, argc, function);
970 ExecState newExec(exec, &m_registerFile, scopeChain, r);
972 Profiler** profiler = Profiler::enabledProfilerReference();
974 (*profiler)->willExecute(exec, function);
978 if (!newCodeBlock->ctiCode)
979 CTI::compile(this, exec, newCodeBlock);
980 JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
982 setScopeChain(&newExec, scopeChain, scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r));
983 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
987 MACHINE_SAMPLING_privateExecuteReturned();
989 m_registerFile.shrink(oldSize);
993 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception)
995 return execute(evalNode, exec, thisObj, m_registerFile.size() + evalNode->byteCode(scopeChain).numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
998 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
1000 ASSERT(!exec->hadException());
1002 if (m_reentryDepth >= MaxReentryDepth) {
1003 *exception = createStackOverflowError(exec);
1007 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
1009 JSVariableObject* variableObject;
1010 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
1012 if (node->object->isVariableObject()) {
1013 variableObject = static_cast<JSVariableObject*>(node->object);
1018 { // Scope for BatchedTransitionOptimizer
1020 BatchedTransitionOptimizer optimizer(variableObject);
1022 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
1023 Node::VarStack::const_iterator varStackEnd = varStack.end();
1024 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
1025 const Identifier& ident = (*it).first;
1026 if (!variableObject->hasProperty(exec, ident)) {
1027 PutPropertySlot slot;
1028 variableObject->put(exec, ident, jsUndefined(), slot);
1032 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
1033 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
1034 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
1035 PutPropertySlot slot;
1036 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
1041 size_t oldSize = m_registerFile.size();
1042 size_t newSize = registerOffset + codeBlock->numCalleeRegisters;
1043 if (!m_registerFile.grow(newSize)) {
1044 *exception = createStackOverflowError(exec);
1048 Register* r = m_registerFile.base() + registerOffset;
1050 // a 0 codeBlock indicates a built-in caller
1051 r[codeBlock->thisRegister] = thisObj;
1052 initializeCallFrame(r, 0, 0, 0, 0, 0, 0, 0);
1054 if (codeBlock->needsFullScopeChain)
1055 scopeChain = scopeChain->copy();
1057 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
1059 Profiler** profiler = Profiler::enabledProfilerReference();
1061 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1065 if (!codeBlock->ctiCode)
1066 CTI::compile(this, exec, codeBlock);
1067 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
1069 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
1073 MACHINE_SAMPLING_privateExecuteReturned();
1076 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1078 m_registerFile.shrink(oldSize);
1082 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
1084 scopeChain = newScopeChain;
1085 exec->m_scopeChain = newScopeChain;
1088 NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
1090 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
1094 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
1096 switch (debugHookID) {
1097 case DidEnterCallFrame:
1098 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1100 case WillLeaveCallFrame:
1101 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1103 case WillExecuteStatement:
1104 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1106 case WillExecuteProgram:
1107 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1109 case DidExecuteProgram:
1110 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1112 case DidReachBreakpoint:
1113 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1118 void Machine::resetTimeoutCheck()
1120 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1121 m_timeAtLastCheckTimeout = 0;
1122 m_timeExecuting = 0;
1125 // Returns the time the current thread has spent executing, in milliseconds.
1126 static inline unsigned getCPUTime()
1128 #if PLATFORM(DARWIN)
1129 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1130 thread_basic_info_data_t info;
1132 // Get thread information
1133 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1135 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1136 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1139 #elif HAVE(SYS_TIME_H)
1140 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1142 gettimeofday(&tv, 0);
1143 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1145 QDateTime t = QDateTime::currentDateTime();
1146 return t.toTime_t() * 1000 + t.time().msec();
1147 #elif PLATFORM(WIN_OS)
1150 unsigned long long fileTimeAsLong;
1151 } userTime, kernelTime;
1153 // GetThreadTimes won't accept NULL arguments so we pass these even though
1154 // they're not used.
1155 FILETIME creationTime, exitTime;
1157 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1159 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1161 #error Platform does not have getCurrentTime function
1165 // We have to return a JSValue here, gcc seems to produce worse code if
1166 // we attempt to return a bool
1167 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1169 unsigned currentTime = getCPUTime();
1171 if (!m_timeAtLastCheckTimeout) {
1172 // Suspicious amount of looping in a script -- start timing it
1173 m_timeAtLastCheckTimeout = currentTime;
1177 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1182 m_timeExecuting += timeDiff;
1183 m_timeAtLastCheckTimeout = currentTime;
1185 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1186 // preferredScriptCheckTimeInterval
1187 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1188 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1189 // preferred script check time interval.
1190 if (m_ticksUntilNextTimeoutCheck == 0)
1191 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1193 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1194 if (globalObject->shouldInterruptScript())
1195 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1197 resetTimeoutCheck();
1203 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1205 int dst = (++vPC)->u.operand;
1206 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1207 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1208 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1210 return scopeChain->push(scope);
1213 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1215 JSValue* prototype = structureID->prototypeForLookup(exec);
1216 if (JSImmediate::isImmediate(prototype))
1218 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(prototype)->structureID());
1219 structureID->setCachedPrototypeChain(chain.release());
1220 return structureID->cachedPrototypeChain();
1223 NEVER_INLINE void Machine::tryCachePutByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1225 // Recursive invocation may already have specialized this instruction.
1226 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1229 if (JSImmediate::isImmediate(baseValue))
1232 // Uncacheable: give up.
1233 if (!slot.isCacheable()) {
1234 vPC[0] = getOpcode(op_put_by_id_generic);
1238 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1239 StructureID* structureID = baseCell->structureID();
1241 if (structureID->isDictionary()) {
1242 vPC[0] = getOpcode(op_put_by_id_generic);
1246 // Cache miss: record StructureID to compare against next time.
1247 StructureID* lastStructureID = vPC[4].u.structureID;
1248 if (structureID != lastStructureID) {
1249 // First miss: record StructureID to compare against next time.
1250 if (!lastStructureID) {
1251 vPC[4] = structureID;
1255 // Second miss: give up.
1256 vPC[0] = getOpcode(op_put_by_id_generic);
1260 // Cache hit: Specialize instruction and ref StructureIDs.
1262 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1263 if (baseCell != slot.base()) {
1264 vPC[0] = getOpcode(op_put_by_id_generic);
1268 // StructureID transition, cache transition info
1269 if (slot.type() == PutPropertySlot::NewProperty) {
1270 vPC[0] = getOpcode(op_put_by_id_transition);
1271 vPC[4] = structureID->previousID();
1272 vPC[5] = structureID;
1273 StructureIDChain* chain = structureID->cachedPrototypeChain();
1275 chain = cachePrototypeChain(exec, structureID);
1277 // This happens if someone has manually inserted null into the prototype chain
1278 vPC[0] = getOpcode(op_put_by_id_generic);
1283 vPC[7] = slot.cachedOffset();
1284 codeBlock->refStructureIDs(vPC);
1288 vPC[0] = getOpcode(op_put_by_id_replace);
1289 vPC[5] = slot.cachedOffset();
1290 codeBlock->refStructureIDs(vPC);
1293 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1295 codeBlock->derefStructureIDs(vPC);
1296 vPC[0] = getOpcode(op_put_by_id);
1300 NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1302 // Recursive invocation may already have specialized this instruction.
1303 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1306 // FIXME: Cache property access for immediates.
1307 if (JSImmediate::isImmediate(baseValue)) {
1308 vPC[0] = getOpcode(op_get_by_id_generic);
1312 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1313 vPC[0] = getOpcode(op_get_array_length);
1317 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1318 vPC[0] = getOpcode(op_get_string_length);
1322 // Uncacheable: give up.
1323 if (!slot.isCacheable()) {
1324 vPC[0] = getOpcode(op_get_by_id_generic);
1328 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1330 if (structureID->isDictionary()) {
1331 vPC[0] = getOpcode(op_get_by_id_generic);
1336 StructureID* lastStructureID = vPC[4].u.structureID;
1337 if (structureID != lastStructureID) {
1338 // First miss: record StructureID to compare against next time.
1339 if (!lastStructureID) {
1340 vPC[4] = structureID;
1344 // Second miss: give up.
1345 vPC[0] = getOpcode(op_get_by_id_generic);
1349 // Cache hit: Specialize instruction and ref StructureIDs.
1351 if (slot.slotBase() == baseValue) {
1352 vPC[0] = getOpcode(op_get_by_id_self);
1353 vPC[5] = slot.cachedOffset();
1355 codeBlock->refStructureIDs(vPC);
1359 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1360 ASSERT(slot.slotBase()->isObject());
1362 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1364 // Heavy access to a prototype is a good indication that it's not being
1365 // used as a dictionary.
1366 if (baseObject->structureID()->isDictionary()) {
1367 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1368 baseObject->setStructureID(transition.release());
1369 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1372 vPC[0] = getOpcode(op_get_by_id_proto);
1373 vPC[5] = baseObject->structureID();
1374 vPC[6] = slot.cachedOffset();
1376 codeBlock->refStructureIDs(vPC);
1381 JSObject* o = static_cast<JSObject*>(baseValue);
1382 while (slot.slotBase() != o) {
1383 JSValue* v = o->structureID()->prototypeForLookup(exec);
1385 // If we didn't find base in baseValue's prototype chain, then baseValue
1386 // must be a proxy for another object.
1388 vPC[0] = getOpcode(op_get_by_id_generic);
1392 o = static_cast<JSObject*>(v);
1394 // Heavy access to a prototype is a good indication that it's not being
1395 // used as a dictionary.
1396 if (o->structureID()->isDictionary()) {
1397 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1398 o->setStructureID(transition.release());
1399 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1405 StructureIDChain* chain = structureID->cachedPrototypeChain();
1407 chain = cachePrototypeChain(exec, structureID);
1410 vPC[0] = getOpcode(op_get_by_id_chain);
1411 vPC[4] = structureID;
1414 vPC[7] = slot.cachedOffset();
1415 codeBlock->refStructureIDs(vPC);
1418 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1420 codeBlock->derefStructureIDs(vPC);
1421 vPC[0] = getOpcode(op_get_by_id);
1425 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1427 // One-time initialization of our address tables. We have to put this code
1428 // here because our labels are only in scope inside this function.
1429 if (flag == InitializeAndReturn) {
1430 #if HAVE(COMPUTED_GOTO)
1431 #define ADD_OPCODE(id) s_opcodeTable[id] = &&id;
1432 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1435 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1436 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1437 #undef ADD_OPCODE_ID
1438 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1439 op_throw_end_indirect = &&op_throw_end;
1440 op_call_indirect = &&op_call;
1441 #endif // HAVE(COMPUTED_GOTO)
1446 // Currently with CTI enabled we never interpret functions
1447 ASSERT_NOT_REACHED();
1450 JSValue* exceptionValue = 0;
1451 Instruction* handlerVPC = 0;
1453 Register* registerBase = registerFile->base();
1454 Instruction* vPC = codeBlock->instructions.begin();
1455 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1456 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1458 #define VM_CHECK_EXCEPTION() \
1460 if (UNLIKELY(exec->hadException())) { \
1461 exceptionValue = exec->exception(); \
1466 #if DUMP_OPCODE_STATS
1467 OpcodeStats::resetLastInstruction();
1470 #define CHECK_FOR_TIMEOUT() \
1471 if (!--tickCount) { \
1472 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1474 tickCount = m_ticksUntilNextTimeoutCheck; \
1477 #if HAVE(COMPUTED_GOTO)
1478 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1479 #if DUMP_OPCODE_STATS
1480 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1482 #define BEGIN_OPCODE(opcode) opcode:
1486 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1487 #if DUMP_OPCODE_STATS
1488 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1490 #define BEGIN_OPCODE(opcode) case opcode:
1492 while (1) // iterator loop begins
1493 switch (vPC->u.opcode)
1496 BEGIN_OPCODE(op_new_object) {
1497 /* new_object dst(r)
1499 Constructs a new empty Object instance using the original
1500 constructor, and puts the result in register dst.
1502 int dst = (++vPC)->u.operand;
1503 r[dst] = constructEmptyObject(exec);
1508 BEGIN_OPCODE(op_new_array) {
1509 /* new_array dst(r) firstArg(r) argCount(n)
1511 Constructs a new Array instance using the original
1512 constructor, and puts the result in register dst.
1513 The array will contain argCount elements with values
1514 taken from registers starting at register firstArg.
1516 int dst = (++vPC)->u.operand;
1517 int firstArg = (++vPC)->u.operand;
1518 int argCount = (++vPC)->u.operand;
1519 ArgList args(r + firstArg, argCount);
1520 r[dst] = constructArray(exec, args);
1525 BEGIN_OPCODE(op_new_regexp) {
1526 /* new_regexp dst(r) regExp(re)
1528 Constructs a new RegExp instance using the original
1529 constructor from regexp regExp, and puts the result in
1532 int dst = (++vPC)->u.operand;
1533 int regExp = (++vPC)->u.operand;
1534 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpStructure(), codeBlock->regexps[regExp]);
1539 BEGIN_OPCODE(op_mov) {
1540 /* mov dst(r) src(r)
1542 Copies register src to register dst.
1544 int dst = (++vPC)->u.operand;
1545 int src = (++vPC)->u.operand;
1551 BEGIN_OPCODE(op_eq) {
1552 /* eq dst(r) src1(r) src2(r)
1554 Checks whether register src1 and register src2 are equal,
1555 as with the ECMAScript '==' operator, and puts the result
1556 as a boolean in register dst.
1558 int dst = (++vPC)->u.operand;
1559 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1560 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1561 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1562 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1564 JSValue* result = jsBoolean(equalSlowCase(exec, src1, src2));
1565 VM_CHECK_EXCEPTION();
1572 BEGIN_OPCODE(op_eq_null) {
1573 /* neq dst(r) src(r)
1575 Checks whether register src is null, as with the ECMAScript '!='
1576 operator, and puts the result as a boolean in register dst.
1578 int dst = (++vPC)->u.operand;
1579 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1581 if (src->isUndefinedOrNull()) {
1582 r[dst] = jsBoolean(true);
1587 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && src->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
1591 BEGIN_OPCODE(op_neq) {
1592 /* neq dst(r) src1(r) src2(r)
1594 Checks whether register src1 and register src2 are not
1595 equal, as with the ECMAScript '!=' operator, and puts the
1596 result as a boolean in register dst.
1598 int dst = (++vPC)->u.operand;
1599 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1600 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1601 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1602 r[dst] = jsBoolean(src1 != src2);
1604 JSValue* result = jsBoolean(!equalSlowCase(exec, src1, src2));
1605 VM_CHECK_EXCEPTION();
1612 BEGIN_OPCODE(op_neq_null) {
1613 /* neq dst(r) src(r)
1615 Checks whether register src is not null, as with the ECMAScript '!='
1616 operator, and puts the result as a boolean in register dst.
1618 int dst = (++vPC)->u.operand;
1619 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1621 if (src->isUndefinedOrNull()) {
1622 r[dst] = jsBoolean(false);
1627 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
1631 BEGIN_OPCODE(op_stricteq) {
1632 /* stricteq dst(r) src1(r) src2(r)
1634 Checks whether register src1 and register src2 are strictly
1635 equal, as with the ECMAScript '===' operator, and puts the
1636 result as a boolean in register dst.
1638 int dst = (++vPC)->u.operand;
1639 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1640 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1641 if (JSImmediate::areBothImmediate(src1, src2))
1642 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1643 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1644 r[dst] = jsBoolean(false);
1646 r[dst] = jsBoolean(strictEqualSlowCase(src1, src2));
1651 BEGIN_OPCODE(op_nstricteq) {
1652 /* nstricteq dst(r) src1(r) src2(r)
1654 Checks whether register src1 and register src2 are not
1655 strictly equal, as with the ECMAScript '!==' operator, and
1656 puts the 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);
1662 if (JSImmediate::areBothImmediate(src1, src2))
1663 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1664 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1665 r[dst] = jsBoolean(true);
1667 r[dst] = jsBoolean(!strictEqualSlowCase(src1, src2));
1672 BEGIN_OPCODE(op_less) {
1673 /* less dst(r) src1(r) src2(r)
1675 Checks whether register src1 is less than register src2, as
1676 with the ECMAScript '<' operator, and puts the result as
1677 a boolean in register dst.
1679 int dst = (++vPC)->u.operand;
1680 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1681 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1682 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1683 VM_CHECK_EXCEPTION();
1689 BEGIN_OPCODE(op_lesseq) {
1690 /* lesseq dst(r) src1(r) src2(r)
1692 Checks whether register src1 is less than or equal to
1693 register src2, as with the ECMAScript '<=' operator, and
1694 puts the result as a boolean in register dst.
1696 int dst = (++vPC)->u.operand;
1697 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1698 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1699 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1700 VM_CHECK_EXCEPTION();
1706 BEGIN_OPCODE(op_pre_inc) {
1707 /* pre_inc srcDst(r)
1709 Converts register srcDst to number, adds one, and puts the result
1710 back in register srcDst.
1712 int srcDst = (++vPC)->u.operand;
1713 JSValue* v = r[srcDst].jsValue(exec);
1714 if (JSImmediate::canDoFastAdditiveOperations(v))
1715 r[srcDst] = JSImmediate::incImmediateNumber(v);
1717 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1718 VM_CHECK_EXCEPTION();
1725 BEGIN_OPCODE(op_pre_dec) {
1726 /* pre_dec srcDst(r)
1728 Converts register srcDst to number, subtracts one, and puts the result
1729 back in register srcDst.
1731 int srcDst = (++vPC)->u.operand;
1732 JSValue* v = r[srcDst].jsValue(exec);
1733 if (JSImmediate::canDoFastAdditiveOperations(v))
1734 r[srcDst] = JSImmediate::decImmediateNumber(v);
1736 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1737 VM_CHECK_EXCEPTION();
1744 BEGIN_OPCODE(op_post_inc) {
1745 /* post_inc dst(r) srcDst(r)
1747 Converts register srcDst to number. The number itself is
1748 written to register dst, and the number plus one is written
1749 back to register srcDst.
1751 int dst = (++vPC)->u.operand;
1752 int srcDst = (++vPC)->u.operand;
1753 JSValue* v = r[srcDst].jsValue(exec);
1754 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1756 r[srcDst] = JSImmediate::incImmediateNumber(v);
1758 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1759 VM_CHECK_EXCEPTION();
1761 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1767 BEGIN_OPCODE(op_post_dec) {
1768 /* post_dec dst(r) srcDst(r)
1770 Converts register srcDst to number. The number itself is
1771 written to register dst, and the number minus one is written
1772 back to register srcDst.
1774 int dst = (++vPC)->u.operand;
1775 int srcDst = (++vPC)->u.operand;
1776 JSValue* v = r[srcDst].jsValue(exec);
1777 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1779 r[srcDst] = JSImmediate::decImmediateNumber(v);
1781 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1782 VM_CHECK_EXCEPTION();
1784 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1790 BEGIN_OPCODE(op_to_jsnumber) {
1791 /* to_jsnumber dst(r) src(r)
1793 Converts register src to number, and puts the result
1796 int dst = (++vPC)->u.operand;
1797 int src = (++vPC)->u.operand;
1798 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1799 VM_CHECK_EXCEPTION();
1806 BEGIN_OPCODE(op_negate) {
1807 /* negate dst(r) src(r)
1809 Converts register src to number, negates it, and puts the
1810 result in register dst.
1812 int dst = (++vPC)->u.operand;
1813 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1815 if (fastIsNumber(src, v))
1816 r[dst] = jsNumber(exec, -v);
1818 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1819 VM_CHECK_EXCEPTION();
1826 BEGIN_OPCODE(op_add) {
1827 /* add dst(r) src1(r) src2(r)
1829 Adds register src1 and register src2, and puts the result
1830 in register dst. (JS add may be string concatenation or
1831 numeric add, depending on the types of the operands.)
1833 int dst = (++vPC)->u.operand;
1834 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1835 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1836 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1837 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1839 JSValue* result = jsAdd(exec, src1, src2);
1840 VM_CHECK_EXCEPTION();
1846 BEGIN_OPCODE(op_mul) {
1847 /* mul dst(r) src1(r) src2(r)
1849 Multiplies register src1 and register src2 (converted to
1850 numbers), and puts the product in register dst.
1852 int dst = (++vPC)->u.operand;
1853 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1854 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1857 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1858 r[dst] = jsNumber(exec, left * right);
1860 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1861 VM_CHECK_EXCEPTION();
1868 BEGIN_OPCODE(op_div) {
1869 /* div dst(r) dividend(r) divisor(r)
1871 Divides register dividend (converted to number) by the
1872 register divisor (converted to number), and puts the
1873 quotient in register dst.
1875 int dst = (++vPC)->u.operand;
1876 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1877 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1880 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1881 r[dst] = jsNumber(exec, left / right);
1883 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1884 VM_CHECK_EXCEPTION();
1890 BEGIN_OPCODE(op_mod) {
1891 /* mod dst(r) dividend(r) divisor(r)
1893 Divides register dividend (converted to number) by
1894 register divisor (converted to number), and puts the
1895 remainder in register dst.
1897 int dst = (++vPC)->u.operand;
1898 int dividend = (++vPC)->u.operand;
1899 int divisor = (++vPC)->u.operand;
1901 JSValue* dividendValue = r[dividend].jsValue(exec);
1902 JSValue* divisorValue = r[divisor].jsValue(exec);
1904 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1905 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1910 double d = dividendValue->toNumber(exec);
1911 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1912 VM_CHECK_EXCEPTION();
1917 BEGIN_OPCODE(op_sub) {
1918 /* sub dst(r) src1(r) src2(r)
1920 Subtracts register src2 (converted to number) from register
1921 src1 (converted to number), and puts the difference in
1924 int dst = (++vPC)->u.operand;
1925 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1926 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1929 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1930 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1931 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1932 r[dst] = jsNumber(exec, left - right);
1934 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1935 VM_CHECK_EXCEPTION();
1941 BEGIN_OPCODE(op_lshift) {
1942 /* lshift dst(r) val(r) shift(r)
1944 Performs left shift of register val (converted to int32) by
1945 register shift (converted to uint32), and puts the result
1948 int dst = (++vPC)->u.operand;
1949 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1950 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1953 if (JSImmediate::areBothImmediateNumbers(val, shift))
1954 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1955 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1956 r[dst] = jsNumber(exec, left << (right & 0x1f));
1958 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1959 VM_CHECK_EXCEPTION();
1966 BEGIN_OPCODE(op_rshift) {
1967 /* rshift dst(r) val(r) shift(r)
1969 Performs arithmetic right shift of register val (converted
1970 to int32) by register shift (converted to
1971 uint32), and puts the result in register dst.
1973 int dst = (++vPC)->u.operand;
1974 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1975 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1978 if (JSImmediate::areBothImmediateNumbers(val, shift))
1979 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1980 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1981 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1983 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1984 VM_CHECK_EXCEPTION();
1991 BEGIN_OPCODE(op_urshift) {
1992 /* rshift dst(r) val(r) shift(r)
1994 Performs logical right shift of register val (converted
1995 to uint32) by register shift (converted to
1996 uint32), and puts the result in register dst.
1998 int dst = (++vPC)->u.operand;
1999 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
2000 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
2001 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
2002 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
2004 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
2005 VM_CHECK_EXCEPTION();
2012 BEGIN_OPCODE(op_bitand) {
2013 /* bitand dst(r) src1(r) src2(r)
2015 Computes bitwise AND of register src1 (converted to int32)
2016 and register src2 (converted to int32), and puts the result
2019 int dst = (++vPC)->u.operand;
2020 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2021 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2024 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2025 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
2026 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2027 r[dst] = jsNumber(exec, left & right);
2029 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
2030 VM_CHECK_EXCEPTION();
2037 BEGIN_OPCODE(op_bitxor) {
2038 /* bitxor dst(r) src1(r) src2(r)
2040 Computes bitwise XOR of register src1 (converted to int32)
2041 and register src2 (converted to int32), and puts the result
2044 int dst = (++vPC)->u.operand;
2045 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2046 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2049 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2050 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
2051 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2052 r[dst] = jsNumber(exec, left ^ right);
2054 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
2055 VM_CHECK_EXCEPTION();
2062 BEGIN_OPCODE(op_bitor) {
2063 /* bitor dst(r) src1(r) src2(r)
2065 Computes bitwise OR of register src1 (converted to int32)
2066 and register src2 (converted to int32), and puts the
2067 result in register dst.
2069 int dst = (++vPC)->u.operand;
2070 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2071 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2074 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2075 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
2076 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2077 r[dst] = jsNumber(exec, left | right);
2079 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
2080 VM_CHECK_EXCEPTION();
2087 BEGIN_OPCODE(op_bitnot) {
2088 /* bitnot dst(r) src(r)
2090 Computes bitwise NOT of register src1 (converted to int32),
2091 and puts the result in register dst.
2093 int dst = (++vPC)->u.operand;
2094 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
2096 if (fastToInt32(src, value))
2097 r[dst] = jsNumber(exec, ~value);
2099 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
2100 VM_CHECK_EXCEPTION();
2106 BEGIN_OPCODE(op_not) {
2107 /* not dst(r) src(r)
2109 Computes logical NOT of register src (converted to
2110 boolean), and puts the result in register dst.
2112 int dst = (++vPC)->u.operand;
2113 int src = (++vPC)->u.operand;
2114 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
2115 VM_CHECK_EXCEPTION();
2121 BEGIN_OPCODE(op_instanceof) {
2122 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2124 Tests whether register value is an instance of register
2125 constructor, and puts the boolean result in register
2126 dst. Register constructorProto must contain the "prototype"
2127 property (not the actual prototype) of the object in
2128 register constructor. This lookup is separated so that
2129 polymorphic inline caching can apply.
2131 Raises an exception if register constructor is not an
2134 int dst = (++vPC)->u.operand;
2135 int value = (++vPC)->u.operand;
2136 int base = (++vPC)->u.operand;
2137 int baseProto = (++vPC)->u.operand;
2139 JSValue* baseVal = r[base].jsValue(exec);
2141 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
2144 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2145 r[dst] = jsBoolean(baseObj->structureID()->typeInfo().implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec), r[baseProto].jsValue(exec)) : false);
2150 BEGIN_OPCODE(op_typeof) {
2151 /* typeof dst(r) src(r)
2153 Determines the type string for src according to ECMAScript
2154 rules, and puts the result in register dst.
2156 int dst = (++vPC)->u.operand;
2157 int src = (++vPC)->u.operand;
2158 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2163 BEGIN_OPCODE(op_is_undefined) {
2164 /* is_undefined dst(r) src(r)
2166 Determines whether the type string for src according to
2167 the ECMAScript rules is "undefined", and puts the result
2170 int dst = (++vPC)->u.operand;
2171 int src = (++vPC)->u.operand;
2172 JSValue* v = r[src].jsValue(exec);
2173 r[dst] = jsBoolean(JSImmediate::isImmediate(v) ? v->isUndefined() : v->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
2178 BEGIN_OPCODE(op_is_boolean) {
2179 /* is_boolean dst(r) src(r)
2181 Determines whether the type string for src according to
2182 the ECMAScript rules is "boolean", and puts the result
2185 int dst = (++vPC)->u.operand;
2186 int src = (++vPC)->u.operand;
2187 r[dst] = jsBoolean(r[src].jsValue(exec)->isBoolean());
2192 BEGIN_OPCODE(op_is_number) {
2193 /* is_number dst(r) src(r)
2195 Determines whether the type string for src according to
2196 the ECMAScript rules is "number", and puts the result
2199 int dst = (++vPC)->u.operand;
2200 int src = (++vPC)->u.operand;
2201 r[dst] = jsBoolean(r[src].jsValue(exec)->isNumber());
2206 BEGIN_OPCODE(op_is_string) {
2207 /* is_string dst(r) src(r)
2209 Determines whether the type string for src according to
2210 the ECMAScript rules is "string", and puts the result
2213 int dst = (++vPC)->u.operand;
2214 int src = (++vPC)->u.operand;
2215 r[dst] = jsBoolean(r[src].jsValue(exec)->isString());
2220 BEGIN_OPCODE(op_is_object) {
2221 /* is_object dst(r) src(r)
2223 Determines whether the type string for src according to
2224 the ECMAScript rules is "object", and puts the result
2227 int dst = (++vPC)->u.operand;
2228 int src = (++vPC)->u.operand;
2229 r[dst] = jsBoolean(jsIsObjectType(r[src].jsValue(exec)));
2234 BEGIN_OPCODE(op_is_function) {
2235 /* is_function dst(r) src(r)
2237 Determines whether the type string for src according to
2238 the ECMAScript rules is "function", and puts the result
2241 int dst = (++vPC)->u.operand;
2242 int src = (++vPC)->u.operand;
2243 r[dst] = jsBoolean(jsIsFunctionType(r[src].jsValue(exec)));
2248 BEGIN_OPCODE(op_in) {
2249 /* in dst(r) property(r) base(r)
2251 Tests whether register base has a property named register
2252 property, and puts the boolean result in register dst.
2254 Raises an exception if register constructor is not an
2257 int dst = (++vPC)->u.operand;
2258 int property = (++vPC)->u.operand;
2259 int base = (++vPC)->u.operand;
2261 JSValue* baseVal = r[base].jsValue(exec);
2262 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
2265 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2267 JSValue* propName = r[property].jsValue(exec);
2270 if (propName->getUInt32(i))
2271 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2273 Identifier property(exec, propName->toString(exec));
2274 VM_CHECK_EXCEPTION();
2275 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2281 BEGIN_OPCODE(op_resolve) {
2282 /* resolve dst(r) property(id)
2284 Looks up the property named by identifier property in the
2285 scope chain, and writes the resulting value to register
2286 dst. If the property is not found, raises an exception.
2288 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2294 BEGIN_OPCODE(op_resolve_skip) {
2295 /* resolve_skip dst(r) property(id) skip(n)
2297 Looks up the property named by identifier property in the
2298 scope chain skipping the top 'skip' levels, and writes the resulting
2299 value to register dst. If the property is not found, raises an exception.
2301 if (UNLIKELY(!resolveSkip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2308 BEGIN_OPCODE(op_resolve_global) {
2309 /* resolve_skip dst(r) globalObject(c) property(id) structureID(sID) offset(n)
2311 Performs a dynamic property lookup for the given property, on the provided
2312 global object. If structureID matches the StructureID of the global then perform
2313 a fast lookup using the case offset, otherwise fall back to a full resolve and
2314 cache the new structureID and offset
2316 if (UNLIKELY(!resolveGlobal(exec, vPC, r, codeBlock, exceptionValue)))
2323 BEGIN_OPCODE(op_get_global_var) {
2324 /* get_global_var dst(r) globalObject(c) index(n)
2326 Gets the global var at global slot index and places it in register dst.
2328 int dst = (++vPC)->u.operand;
2329 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2330 ASSERT(scope->isGlobalObject());
2331 int index = (++vPC)->u.operand;
2333 r[dst] = scope->registerAt(index);
2337 BEGIN_OPCODE(op_put_global_var) {
2338 /* put_global_var globalObject(c) index(n) value(r)
2340 Puts value into global slot index.
2342 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2343 ASSERT(scope->isGlobalObject());
2344 int index = (++vPC)->u.operand;
2345 int value = (++vPC)->u.operand;
2347 scope->registerAt(index) = r[value].jsValue(exec);
2351 BEGIN_OPCODE(op_get_scoped_var) {
2352 /* get_scoped_var dst(r) index(n) skip(n)
2354 Loads the contents of the index-th local from the scope skip nodes from
2355 the top of the scope chain, and places it in register dst
2357 int dst = (++vPC)->u.operand;
2358 int index = (++vPC)->u.operand;
2359 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2361 ScopeChainIterator iter = scopeChain->begin();
2362 ScopeChainIterator end = scopeChain->end();
2363 ASSERT(iter != end);
2366 ASSERT(iter != end);
2369 ASSERT((*iter)->isVariableObject());
2370 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2371 r[dst] = scope->registerAt(index);
2375 BEGIN_OPCODE(op_put_scoped_var) {
2376 /* put_scoped_var index(n) skip(n) value(r)
2379 int index = (++vPC)->u.operand;
2380 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2381 int value = (++vPC)->u.operand;
2383 ScopeChainIterator iter = scopeChain->begin();
2384 ScopeChainIterator end = scopeChain->end();
2385 ASSERT(iter != end);
2388 ASSERT(iter != end);
2391 ASSERT((*iter)->isVariableObject());
2392 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2393 scope->registerAt(index) = r[value].jsValue(exec);
2397 BEGIN_OPCODE(op_resolve_base) {
2398 /* resolve_base dst(r) property(id)
2400 Searches the scope chain for an object containing
2401 identifier property, and if one is found, writes it to
2402 register dst. If none is found, the outermost scope (which
2403 will be the global object) is stored in register dst.
2405 resolveBase(exec, vPC, r, scopeChain, codeBlock);
2410 BEGIN_OPCODE(op_resolve_with_base) {
2411 /* resolve_with_base baseDst(r) propDst(r) property(id)
2413 Searches the scope chain for an object containing
2414 identifier property, and if one is found, writes it to
2415 register srcDst, and the retrieved property value to register
2416 propDst. If the property is not found, raises an exception.
2418 This is more efficient than doing resolve_base followed by
2419 resolve, or resolve_base followed by get_by_id, as it
2420 avoids duplicate hash lookups.
2422 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2428 BEGIN_OPCODE(op_resolve_func) {
2429 /* resolve_func baseDst(r) funcDst(r) property(id)
2431 Searches the scope chain for an object containing
2432 identifier property, and if one is found, writes the
2433 appropriate object to use as "this" when calling its
2434 properties to register baseDst; and the retrieved property
2435 value to register propDst. If the property is not found,
2436 raises an exception.
2438 This differs from resolve_with_base, because the
2439 global this value will be substituted for activations or
2440 the global object, which is the right behavior for function
2441 calls but not for other property lookup.
2443 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2449 BEGIN_OPCODE(op_get_by_id) {
2450 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2452 Generic property access: Gets the property named by identifier
2453 property from the value base, and puts the result in register dst.
2455 int dst = vPC[1].u.operand;
2456 int base = vPC[2].u.operand;
2457 int property = vPC[3].u.operand;
2459 Identifier& ident = codeBlock->identifiers[property];
2460 JSValue* baseValue = r[base].jsValue(exec);
2461 PropertySlot slot(baseValue);
2462 JSValue* result = baseValue->get(exec, ident, slot);
2463 VM_CHECK_EXCEPTION();
2465 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2471 BEGIN_OPCODE(op_get_by_id_self) {
2472 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2474 Cached property access: Attempts to get a cached property from the
2475 value base. If the cache misses, op_get_by_id_self reverts to
2478 int base = vPC[2].u.operand;
2479 JSValue* baseValue = r[base].jsValue(exec);
2481 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2482 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2483 StructureID* structureID = vPC[4].u.structureID;
2485 if (LIKELY(baseCell->structureID() == structureID)) {
2486 ASSERT(baseCell->isObject());
2487 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2488 int dst = vPC[1].u.operand;
2489 int offset = vPC[5].u.operand;
2491 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2492 r[dst] = baseObject->getDirectOffset(offset);
2499 uncacheGetByID(codeBlock, vPC);
2502 BEGIN_OPCODE(op_get_by_id_proto) {
2503 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2505 Cached property access: Attempts to get a cached property from the
2506 value base's prototype. If the cache misses, op_get_by_id_proto
2507 reverts to op_get_by_id.
2509 int base = vPC[2].u.operand;
2510 JSValue* baseValue = r[base].jsValue(exec);
2512 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2513 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2514 StructureID* structureID = vPC[4].u.structureID;
2516 if (LIKELY(baseCell->structureID() == structureID)) {
2517 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2518 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2519 StructureID* protoStructureID = vPC[5].u.structureID;
2521 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2522 int dst = vPC[1].u.operand;
2523 int offset = vPC[6].u.operand;
2525 ASSERT(protoObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2526 r[dst] = protoObject->getDirectOffset(offset);
2534 uncacheGetByID(codeBlock, vPC);
2537 BEGIN_OPCODE(op_get_by_id_chain) {
2538 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2540 Cached property access: Attempts to get a cached property from the
2541 value base's prototype chain. If the cache misses, op_get_by_id_chain
2542 reverts to op_get_by_id.
2544 int base = vPC[2].u.operand;
2545 JSValue* baseValue = r[base].jsValue(exec);
2547 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2548 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2549 StructureID* structureID = vPC[4].u.structureID;
2551 if (LIKELY(baseCell->structureID() == structureID)) {
2552 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2553 size_t count = vPC[6].u.operand;
2554 RefPtr<StructureID>* end = it + count;
2556 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2558 baseObject = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2559 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2563 int dst = vPC[1].u.operand;
2564 int offset = vPC[7].u.operand;
2566 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2567 r[dst] = baseObject->getDirectOffset(offset);
2576 uncacheGetByID(codeBlock, vPC);
2579 BEGIN_OPCODE(op_get_by_id_generic) {
2580 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2582 Generic property access: Gets the property named by identifier
2583 property from the value base, and puts the result in register dst.
2585 int dst = vPC[1].u.operand;
2586 int base = vPC[2].u.operand;
2587 int property = vPC[3].u.operand;
2589 Identifier& ident = codeBlock->identifiers[property];
2591 JSValue* baseValue = r[base].jsValue(exec);
2592 PropertySlot slot(baseValue);
2593 JSValue* result = baseValue->get(exec, ident, slot);
2594 VM_CHECK_EXCEPTION();
2600 BEGIN_OPCODE(op_get_array_length) {
2601 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2603 Cached property access: Gets the length of the array in register base,
2604 and puts the result in register dst. If register base does not hold
2605 an array, op_get_array_length reverts to op_get_by_id.
2608 int base = vPC[2].u.operand;
2609 JSValue* baseValue = r[base].jsValue(exec);
2610 if (LIKELY(isJSArray(baseValue))) {
2611 int dst = vPC[1].u.operand;
2612 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2617 uncacheGetByID(codeBlock, vPC);
2620 BEGIN_OPCODE(op_get_string_length) {
2621 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2623 Cached property access: Gets the length of the string in register base,
2624 and puts the result in register dst. If register base does not hold
2625 a string, op_get_string_length reverts to op_get_by_id.
2628 int base = vPC[2].u.operand;
2629 JSValue* baseValue = r[base].jsValue(exec);
2630 if (LIKELY(isJSString(baseValue))) {
2631 int dst = vPC[1].u.operand;
2632 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2637 uncacheGetByID(codeBlock, vPC);
2640 BEGIN_OPCODE(op_put_by_id) {
2641 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2643 Generic property access: Sets the property named by identifier
2644 property, belonging to register base, to register value.
2646 Unlike many opcodes, this one does not write any output to
2650 int base = vPC[1].u.operand;
2651 int property = vPC[2].u.operand;
2652 int value = vPC[3].u.operand;
2654 JSValue* baseValue = r[base].jsValue(exec);
2656 PutPropertySlot slot;
2657 Identifier& ident = codeBlock->identifiers[property];
2658 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2659 VM_CHECK_EXCEPTION();
2661 tryCachePutByID(exec, codeBlock, vPC, baseValue, slot);
2666 BEGIN_OPCODE(op_put_by_id_transition) {
2667 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2669 Cached property access: Attempts to set a new property with a cached transition
2670 property named by identifier property, belonging to register base,
2671 to register value. If the cache misses, op_put_by_id_transition
2672 reverts to op_put_by_id_generic.
2674 Unlike many opcodes, this one does not write any output to
2677 int base = vPC[1].u.operand;
2678 JSValue* baseValue = r[base].jsValue(exec);
2680 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2681 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2682 StructureID* oldStructureID = vPC[4].u.structureID;
2683 StructureID* newStructureID = vPC[5].u.structureID;
2685 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2686 ASSERT(baseCell->isObject());
2687 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2689 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2691 JSObject* proto = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2692 while (!proto->isNull()) {
2693 if (UNLIKELY(proto->structureID() != (*it).get())) {
2694 uncachePutByID(codeBlock, vPC);
2698 proto = static_cast<JSObject*>(proto->structureID()->prototypeForLookup(exec));
2701 baseObject->transitionTo(newStructureID);
2702 if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
2703 baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
2705 int value = vPC[3].u.operand;
2706 unsigned offset = vPC[7].u.operand;
2707 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2708 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2715 uncachePutByID(codeBlock, vPC);
2718 BEGIN_OPCODE(op_put_by_id_replace) {
2719 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2721 Cached property access: Attempts to set a pre-existing, cached
2722 property named by identifier property, belonging to register base,
2723 to register value. If the cache misses, op_put_by_id_replace
2724 reverts to op_put_by_id.
2726 Unlike many opcodes, this one does not write any output to
2729 int base = vPC[1].u.operand;
2730 JSValue* baseValue = r[base].jsValue(exec);
2732 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2733 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2734 StructureID* structureID = vPC[4].u.structureID;
2736 if (LIKELY(baseCell->structureID() == structureID)) {
2737 ASSERT(baseCell->isObject());
2738 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2739 int value = vPC[3].u.operand;
2740 unsigned offset = vPC[5].u.operand;
2742 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2743 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2750 uncachePutByID(codeBlock, vPC);
2753 BEGIN_OPCODE(op_put_by_id_generic) {
2754 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2756 Generic property access: Sets the property named by identifier
2757 property, belonging to register base, to register value.
2759 Unlike many opcodes, this one does not write any output to
2762 int base = vPC[1].u.operand;
2763 int property = vPC[2].u.operand;
2764 int value = vPC[3].u.operand;
2766 JSValue* baseValue = r[base].jsValue(exec);
2768 PutPropertySlot slot;
2769 Identifier& ident = codeBlock->identifiers[property];
2770 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2771 VM_CHECK_EXCEPTION();
2776 BEGIN_OPCODE(op_del_by_id) {
2777 /* del_by_id dst(r) base(r) property(id)
2779 Converts register base to Object, deletes the property
2780 named by identifier property from the object, and writes a
2781 boolean indicating success (if true) or failure (if false)
2784 int dst = (++vPC)->u.operand;
2785 int base = (++vPC)->u.operand;
2786 int property = (++vPC)->u.operand;
2788 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2790 Identifier& ident = codeBlock->identifiers[property];
2791 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2792 VM_CHECK_EXCEPTION();
2797 BEGIN_OPCODE(op_get_by_val) {
2798 /* get_by_val dst(r) base(r) property(r)
2800 Converts register base to Object, gets the property named
2801 by register property from the object, and puts the result
2802 in register dst. property is nominally converted to string
2803 but numbers are treated more efficiently.
2805 int dst = (++vPC)->u.operand;
2806 int base = (++vPC)->u.operand;
2807 int property = (++vPC)->u.operand;
2809 JSValue* baseValue = r[base].jsValue(exec);
2810 JSValue* subscript = r[property].jsValue(exec);
2815 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2816 if (LIKELY(isUInt32)) {
2817 if (isJSArray(baseValue)) {
2818 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2819 if (jsArray->canGetIndex(i))
2820 result = jsArray->getIndex(i);
2822 result = jsArray->JSArray::get(exec, i);
2823 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2824 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2826 result = baseValue->get(exec, i);
2828 Identifier property(exec, subscript->toString(exec));
2829 result = baseValue->get(exec, property);
2832 VM_CHECK_EXCEPTION();
2837 BEGIN_OPCODE(op_put_by_val) {
2838 /* put_by_val base(r) property(r) value(r)
2840 Sets register value on register base as the property named
2841 by register property. Base is converted to object
2842 first. register property is nominally converted to string
2843 but numbers are treated more efficiently.
2845 Unlike many opcodes, this one does not write any output to
2848 int base = (++vPC)->u.operand;
2849 int property = (++vPC)->u.operand;
2850 int value = (++vPC)->u.operand;
2852 JSValue* baseValue = r[base].jsValue(exec);
2853 JSValue* subscript = r[property].jsValue(exec);
2857 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2858 if (LIKELY(isUInt32)) {
2859 if (isJSArray(baseValue)) {
2860 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2861 if (jsArray->canSetIndex(i))
2862 jsArray->setIndex(i, r[value].jsValue(exec));
2864 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2866 baseValue->put(exec, i, r[value].jsValue(exec));
2868 Identifier property(exec, subscript->toString(exec));
2869 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2870 PutPropertySlot slot;
2871 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2875 VM_CHECK_EXCEPTION();
2879 BEGIN_OPCODE(op_del_by_val) {
2880 /* del_by_val dst(r) base(r) property(r)
2882 Converts register base to Object, deletes the property
2883 named by register property from the object, and writes a
2884 boolean indicating success (if true) or failure (if false)
2887 int dst = (++vPC)->u.operand;
2888 int base = (++vPC)->u.operand;
2889 int property = (++vPC)->u.operand;
2891 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2893 JSValue* subscript = r[property].jsValue(exec);
2896 if (subscript->getUInt32(i))
2897 result = jsBoolean(baseObj->deleteProperty(exec, i));
2899 VM_CHECK_EXCEPTION();
2900 Identifier property(exec, subscript->toString(exec));
2901 VM_CHECK_EXCEPTION();
2902 result = jsBoolean(baseObj->deleteProperty(exec, property));
2905 VM_CHECK_EXCEPTION();
2910 BEGIN_OPCODE(op_put_by_index) {
2911 /* put_by_index base(r) property(n) value(r)
2913 Sets register value on register base as the property named
2914 by the immediate number property. Base is converted to
2917 Unlike many opcodes, this one does not write any output to
2920 This opcode is mainly used to initialize array literals.
2922 int base = (++vPC)->u.operand;
2923 unsigned property = (++vPC)->u.operand;
2924 int value = (++vPC)->u.operand;
2926 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2931 BEGIN_OPCODE(op_loop) {
2932 /* loop target(offset)
2934 Jumps unconditionally to offset target from the current
2937 Additionally this loop instruction may terminate JS execution is
2938 the JS timeout is reached.
2940 #if DUMP_OPCODE_STATS
2941 OpcodeStats::resetLastInstruction();
2943 int target = (++vPC)->u.operand;
2944 CHECK_FOR_TIMEOUT();
2948 BEGIN_OPCODE(op_jmp) {
2949 /* jmp target(offset)
2951 Jumps unconditionally to offset target from the current
2954 #if DUMP_OPCODE_STATS
2955 OpcodeStats::resetLastInstruction();
2957 int target = (++vPC)->u.operand;
2962 BEGIN_OPCODE(op_loop_if_true) {
2963 /* loop_if_true cond(r) target(offset)
2965 Jumps to offset target from the current instruction, if and
2966 only if register cond converts to boolean as true.
2968 Additionally this loop instruction may terminate JS execution is
2969 the JS timeout is reached.
2971 int cond = (++vPC)->u.operand;
2972 int target = (++vPC)->u.operand;
2973 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2975 CHECK_FOR_TIMEOUT();
2982 BEGIN_OPCODE(op_jtrue) {
2983 /* jtrue cond(r) target(offset)
2985 Jumps to offset target from the current instruction, if and
2986 only if register cond converts to boolean as true.
2988 int cond = (++vPC)->u.operand;
2989 int target = (++vPC)->u.operand;
2990 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2998 BEGIN_OPCODE(op_jfalse) {
2999 /* jfalse cond(r) target(offset)
3001 Jumps to offset target from the current instruction, if and
3002 only if register cond converts to boolean as false.
3004 int cond = (++vPC)->u.operand;
3005 int target = (++vPC)->u.operand;
3006 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
3014 BEGIN_OPCODE(op_loop_if_less) {
3015 /* loop_if_less src1(r) src2(r) target(offset)
3017 Checks whether register src1 is less than register src2, as
3018 with the ECMAScript '<' operator, and then jumps to offset
3019 target from the current instruction, if and only if the
3020 result of the comparison is true.
3022 Additionally this loop instruction may terminate JS execution is
3023 the JS timeout is reached.
3025 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3026 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3027 int target = (++vPC)->u.operand;
3029 bool result = jsLess(exec, src1, src2);
3030 VM_CHECK_EXCEPTION();
3034 CHECK_FOR_TIMEOUT();
3041 BEGIN_OPCODE(op_loop_if_lesseq) {
3042 /* loop_if_lesseq src1(r) src2(r) target(offset)
3044 Checks whether register src1 is less than or equal to register
3045 src2, as with the ECMAScript '<=' operator, and then jumps to
3046 offset target from the current instruction, if and only if the
3047 result of the comparison is true.
3049 Additionally this loop instruction may terminate JS execution is
3050 the JS timeout is reached.
3052 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3053 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3054 int target = (++vPC)->u.operand;
3056 bool result = jsLessEq(exec, src1, src2);
3057 VM_CHECK_EXCEPTION();
3061 CHECK_FOR_TIMEOUT();
3068 BEGIN_OPCODE(op_jnless) {
3069 /* jnless src1(r) src2(r) target(offset)
3071 Checks whether register src1 is less than register src2, as
3072 with the ECMAScript '<' operator, and then jumps to offset
3073 target from the current instruction, if and only if the
3074 result of the comparison is false.
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 = jsLess(exec, src1, src2);
3081 VM_CHECK_EXCEPTION();
3091 BEGIN_OPCODE(op_switch_imm) {
3092 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3094 Performs a range checked switch on the scrutinee value, using
3095 the tableIndex-th immediate switch jump table. If the scrutinee value
3096 is an immediate number in the range covered by the referenced jump
3097 table, and the value at jumpTable[scrutinee value] is non-zero, then
3098 that value is used as the jump offset, otherwise defaultOffset is used.
3100 int tableIndex = (++vPC)->u.operand;
3101 int defaultOffset = (++vPC)->u.operand;
3102 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3103 if (!JSImmediate::isNumber(scrutinee))
3104 vPC += defaultOffset;
3106 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3107 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
3111 BEGIN_OPCODE(op_switch_char) {
3112 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3114 Performs a range checked switch on the scrutinee value, using
3115 the tableIndex-th character switch jump table. If the scrutinee value
3116 is a single character string in the range covered by the referenced jump
3117 table, and the value at jumpTable[scrutinee value] is non-zero, then
3118 that value is used as the jump offset, otherwise defaultOffset is used.
3120 int tableIndex = (++vPC)->u.operand;
3121 int defaultOffset = (++vPC)->u.operand;
3122 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3123 if (!scrutinee->isString())
3124 vPC += defaultOffset;
3126 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
3127 if (value->size() != 1)
3128 vPC += defaultOffset;
3130 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
3134 BEGIN_OPCODE(op_switch_string) {
3135 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3137 Performs a sparse hashmap based switch on the value in the scrutinee
3138 register, using the tableIndex-th string switch jump table. If the
3139 scrutinee value is a string that exists as a key in the referenced
3140 jump table, then the value associated with the string is used as the
3141 jump offset, otherwise defaultOffset is used.
3143 int tableIndex = (++vPC)->u.operand;
3144 int defaultOffset = (++vPC)->u.operand;
3145 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3146 if (!scrutinee->isString())
3147 vPC += defaultOffset;
3149 vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
3152 BEGIN_OPCODE(op_new_func) {
3153 /* new_func dst(r) func(f)
3155 Constructs a new Function instance from function func and
3156 the current scope chain using the original Function
3157 constructor, using the rules for function declarations, and
3158 puts the result in register dst.
3160 int dst = (++vPC)->u.operand;
3161 int func = (++vPC)->u.operand;
3163 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
3168 BEGIN_OPCODE(op_new_func_exp) {
3169 /* new_func_exp dst(r) func(f)
3171 Constructs a new Function instance from function func and
3172 the current scope chain using the original Function
3173 constructor, using the rules for function expressions, and
3174 puts the result in register dst.
3176 int dst = (++vPC)->u.operand;
3177 int func = (++vPC)->u.operand;
3179 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
3184 BEGIN_OPCODE(op_call_eval) {
3185 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3187 Call a function named "eval" with no explicit "this" value
3188 (which may therefore be the eval operator). If register
3189 thisVal is the global object, and register func contains
3190 that global object's original global eval function, then
3191 perform the eval operator in local scope (interpreting
3192 the argument registers as for the "call"
3193 opcode). Otherwise, act exactly as the "call" opcode would.
3196 int dst = (++vPC)->u.operand;
3197 int func = (++vPC)->u.operand;
3198 int thisVal = (++vPC)->u.operand;
3199 int firstArg = (++vPC)->u.operand;
3200 int argCount = (++vPC)->u.operand;
3201 ++vPC; // registerOffset
3203 JSValue* funcVal = r[func].jsValue(exec);
3204 JSValue* baseVal = r[thisVal].jsValue(exec);
3206 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
3207 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
3208 JSValue* result = callEval(exec, codeBlock, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
3218 // We didn't find the blessed version of eval, so reset vPC and process
3219 // this instruction as a normal function call, supplying the proper 'this'
3222 r[thisVal] = baseVal->toThisObject(exec);
3224 #if HAVE(COMPUTED_GOTO)
3225 // Hack around gcc performance quirk by performing an indirect goto
3226 // in order to set the vPC -- attempting to do so directly results in a
3227 // significant regression.
3228 goto *op_call_indirect; // indirect goto -> op_call
3230 // fall through to op_call
3232 BEGIN_OPCODE(op_call) {
3233 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n) registerOffset(n)
3235 Perform a function call. Specifically, call register func
3236 with a "this" value of register thisVal, and put the result
3239 The arguments start at register firstArg and go up to
3240 argCount, but the "this" value is considered an implicit
3241 first argument, so the argCount should be one greater than
3242 the number of explicit arguments passed, and the register
3243 after firstArg should contain the actual first
3244 argument. This opcode will copy from the thisVal register
3245 to the firstArg register, unless the register index of
3246 thisVal is the special missing this object marker, which is
3247 2^31-1; in that case, the global object will be used as the
3250 If func is a native code function, then this opcode calls
3251 it and returns the value immediately.
3253 But if it is a JS function, then the current scope chain
3254 and code block is set to the function's, and we slide the
3255 register window so that the arguments would form the first
3256 few local registers of the called function's register
3257 window. In addition, a call frame header is written
3258 immediately before the arguments; see the call frame
3259 documentation for an explanation of how many registers a
3260 call frame takes and what they contain. That many registers
3261 before the firstArg register will be overwritten by the
3262 call. In addition, any registers higher than firstArg +
3263 argCount may be overwritten. Once this setup is complete,
3264 execution continues from the called function's first
3265 argument, and does not return until a "ret" opcode is
3269 int dst = (++vPC)->u.operand;
3270 int func = (++vPC)->u.operand;
3271 int thisVal = (++vPC)->u.operand;
3272 int firstArg = (++vPC)->u.operand;
3273 int argCount = (++vPC)->u.operand;
3274 int registerOffset = (++vPC)->u.operand;
3276 JSValue* v = r[func].jsValue(exec);
3279 CallType callType = v->getCallData(callData);
3281 if (callType == CallTypeJS) {
3282 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3283 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3284 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3286 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3288 Register* savedR = r;
3290 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, registerOffset, argCount, exceptionValue);
3291 if (UNLIKELY(exceptionValue != 0))
3294 initializeCallFrame(r, codeBlock, vPC, scopeChain, savedR, dst, argCount, v);
3295 exec->m_callFrame = r;
3297 if (*enabledProfilerReference)
3298 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3300 codeBlock = newCodeBlock;
3301 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3302 vPC = codeBlock->instructions.begin();
3304 #if DUMP_OPCODE_STATS
3305 OpcodeStats::resetLastInstruction();
3311 if (callType == CallTypeHost) {
3312 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3313 ArgList args(r + firstArg + 1, argCount - 1);
3315 initializeCallFrame(r + registerOffset, codeBlock, vPC, scopeChain, r, dst, argCount, v);
3316 exec->m_callFrame = r + registerOffset;
3318 if (*enabledProfilerReference)
3319 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3321 MACHINE_SAMPLING_callingHostFunction();
3323 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
3324 exec->m_callFrame = r;
3325 VM_CHECK_EXCEPTION();
3327 r[dst] = returnValue;
3329 if (*enabledProfilerReference)
3330 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3336 ASSERT(callType == CallTypeNone);
3338 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
3341 BEGIN_OPCODE(op_ret) {
3344 Return register result as the return value of the current
3345 function call, writing it into the caller's expected return
3346 value register. In addition, unwind one call frame and
3347 restore the scope chain, code block instruction pointer and
3348 register base to those of the calling function.
3351 int result = (++vPC)->u.operand;
3353 if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
3354 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
3355 ASSERT(activation->isActivationObject());
3356 activation->copyRegisters();
3359 if (*enabledProfilerReference)
3360 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
3362 if (codeBlock->needsFullScopeChain)
3363 scopeChain->deref();
3365 JSValue* returnValue = r[result].jsValue(exec);
3367 codeBlock = r[RegisterFile::CallerCodeBlock].codeBlock();
3371 vPC = r[RegisterFile::ReturnPC].vPC();
3372 setScopeChain(exec, scopeChain, r[RegisterFile::CallerScopeChain].scopeChain());
3373 int dst = r[RegisterFile::ReturnValueRegister].i();
3374 r = r[RegisterFile::CallerRegisters].r();
3375 exec->m_callFrame = r;
3376 r[dst] = returnValue;
3380 BEGIN_OPCODE(op_init) {
3383 for (size_t count = codeBlock->numVars; i < count; ++i)
3384 r[i] = jsUndefined();
3386 for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
3387 r[i] = codeBlock->constantRegisters[j];
3392 BEGIN_OPCODE(op_construct) {
3393 /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n) registerOffset(n)
3395 Invoke register "constr" as a constructor. For JS
3396 functions, the calling convention is exactly as for the
3397 "call" opcode, except that the "this" value is a newly
3398 created Object. For native constructors, a null "this"
3399 value is passed. In either case, the firstArg and argCount
3400 registers are interpreted as for the "call" opcode.
3402 Register constrProto must contain the prototype property of
3403 register constsr. This is to enable polymorphic inline
3404 caching of this lookup.
3407 int dst = (++vPC)->u.operand;
3408 int constr = (++vPC)->u.operand;
3409 int constrProto = (++vPC)->u.operand;
3410 int firstArg = (++vPC)->u.operand;
3411 int argCount = (++vPC)->u.operand;
3412 int registerOffset = (++vPC)->u.operand;
3414 JSValue* v = r[constr].jsValue(exec);
3416 ConstructData constructData;
3417 ConstructType constructType = v->getConstructData(constructData);
3419 if (constructType == ConstructTypeJS) {
3420 if (*enabledProfilerReference)
3421 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3423 StructureID* structure;
3424 JSValue* prototype = r[constrProto].jsValue(exec);
3425 if (prototype->isObject())
3426 structure = static_cast<JSObject*>(prototype)->inheritorID();
3428 structure = scopeChain->globalObject()->emptyObjectStructure();
3429 JSObject* newObject = new (exec) JSObject(structure);
3431 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3432 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3433 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3435 r[firstArg] = newObject; // "this" value
3437 Register* savedR = r;
3439 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, registerOffset, argCount, exceptionValue);
3440 if (UNLIKELY(exceptionValue != 0))
3443 initializeCallFrame(r, codeBlock, vPC, scopeChain, savedR, dst, argCount, v);
3444 exec->m_callFrame = r;
3446 if (*enabledProfilerReference)
3447 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3449 codeBlock = newCodeBlock;
3450 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3451 vPC = codeBlock->instructions.begin();
3453 #if DUMP_OPCODE_STATS
3454 OpcodeStats::resetLastInstruction();
3460 if (constructType == ConstructTypeHost) {
3461 ArgList args(r + firstArg + 1, argCount - 1);
3463 initializeCallFrame(r + registerOffset, codeBlock, vPC, scopeChain, r, dst, argCount, v);
3464 exec->m_callFrame = r + registerOffset;
3466 if (*enabledProfilerReference)
3467 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3469 MACHINE_SAMPLING_callingHostFunction();
3471 JSValue* returnValue = constructData.native.function(exec, static_cast<JSObject*>(v), args);
3472 exec->m_callFrame = r;
3474 VM_CHECK_EXCEPTION();
3475 r[dst] = returnValue;
3477 if (*enabledProfilerReference)
3478 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3484 ASSERT(constructType == ConstructTypeNone);
3486 exceptionValue = createNotAConstructorError(exec, v, vPC, codeBlock);
3489 BEGIN_OPCODE(op_construct_verify) {
3490 /* construct_verify dst(r) override(r)
3492 Verifies that register dst holds an object. If not, moves
3493 the object in register override to register dst.
3496 int dst = vPC[1].u.operand;;
3497 if (LIKELY(r[dst].jsValue(exec)->isObject())) {
3502 int override = vPC[2].u.operand;
3503 r[dst] = r[override];
3508 BEGIN_OPCODE(op_push_scope) {
3509 /* push_scope scope(r)
3511 Converts register scope to object, and pushes it onto the top
3512 of the current scope chain.
3514 int scope = (++vPC)->u.operand;
3515 JSValue* v = r[scope].jsValue(exec);
3516 JSObject* o = v->toObject(exec);
3517 VM_CHECK_EXCEPTION();
3519 setScopeChain(exec, scopeChain, scopeChain->push(o));