2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "Arguments.h"
34 #include "BatchedTransitionOptimizer.h"
35 #include "CodeBlock.h"
36 #include "DebuggerCallFrame.h"
37 #include "ExceptionHelpers.h"
38 #include "ExecState.h"
39 #include "GlobalEvalFunction.h"
40 #include "JSActivation.h"
42 #include "JSFunction.h"
43 #include "JSNotAnObject.h"
44 #include "JSPropertyNameIterator.h"
45 #include "JSStaticScopeObject.h"
47 #include "ObjectPrototype.h"
50 #include "RegExpObject.h"
51 #include "RegExpPrototype.h"
53 #include "collector.h"
55 #include "operations.h"
56 #include "SamplingTool.h"
60 #include <mach/mach.h>
79 // Preferred number of milliseconds between each timeout check
80 static const int preferredScriptCheckTimeInterval = 1000;
82 #if HAVE(COMPUTED_GOTO)
83 static void* op_throw_end_indirect;
84 static void* op_call_indirect;
89 ALWAYS_INLINE static Instruction* vPCForPC(CodeBlock* codeBlock, void* pc)
91 if (pc >= codeBlock->instructions.begin() && pc < codeBlock->instructions.end())
92 return static_cast<Instruction*>(pc);
94 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(pc));
95 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(pc);
96 return codeBlock->instructions.begin() + vPCIndex;
101 ALWAYS_INLINE static Instruction* vPCForPC(CodeBlock*, void* pc)
103 return static_cast<Instruction*>(pc);
106 #endif // #ENABLE(CTI)
108 // Returns the depth of the scope chain within a given call frame.
109 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
111 if (!codeBlock->needsFullScopeChain)
114 ScopeChainIterator iter = sc.begin();
115 ScopeChainIterator end = sc.end();
116 while (!(*iter)->isObject(&JSActivation::info)) {
125 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
126 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
127 static bool fastIsNumber(JSValue* value, double& arg)
129 if (JSImmediate::isNumber(value))
130 arg = JSImmediate::getTruncatedInt32(value);
131 else if (Heap::isNumber(static_cast<JSCell*>(value)))
132 arg = static_cast<JSNumberCell*>(value)->value();
138 // FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
139 static bool fastToInt32(JSValue* value, int32_t& arg)
141 if (JSImmediate::isNumber(value))
142 arg = JSImmediate::getTruncatedInt32(value);
143 else if (Heap::isNumber(static_cast<JSCell*>(value)))
144 arg = static_cast<JSNumberCell*>(value)->toInt32();
150 static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
152 if (JSImmediate::isNumber(value)) {
153 if (JSImmediate::getTruncatedUInt32(value, arg))
156 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
158 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
159 arg = static_cast<JSNumberCell*>(value)->toUInt32();
165 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
167 if (JSImmediate::areBothImmediateNumbers(v1, v2))
168 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
172 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
175 Machine* machine = exec->machine();
176 if (machine->isJSString(v1) && machine->isJSString(v2))
177 return static_cast<const JSString*>(v1)->value() < static_cast<const JSString*>(v2)->value();
181 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
182 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
184 if (wasNotString1 | wasNotString2)
187 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
190 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
192 if (JSImmediate::areBothImmediateNumbers(v1, v2))
193 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
197 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
200 Machine* machine = exec->machine();
201 if (machine->isJSString(v1) && machine->isJSString(v2))
202 return !(static_cast<const JSString*>(v2)->value() < static_cast<const JSString*>(v1)->value());
206 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
207 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
209 if (wasNotString1 | wasNotString2)
212 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
215 static NEVER_INLINE JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
217 // exception for the Date exception in defaultValue()
218 JSValue* p1 = v1->toPrimitive(exec);
219 JSValue* p2 = v2->toPrimitive(exec);
221 if (p1->isString() || p2->isString()) {
222 RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
224 return throwOutOfMemoryError(exec);
225 return jsString(exec, value.release());
228 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
231 // Fast-path choices here are based on frequency data from SunSpider:
232 // <times> Add case: <t1> <t2>
233 // ---------------------------
234 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
235 // 247412 Add case: 5 5
236 // 20900 Add case: 5 6
237 // 13962 Add case: 5 3
238 // 4000 Add case: 3 5
240 static ALWAYS_INLINE JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
245 bool rightIsNumber = fastIsNumber(v2, right);
246 if (rightIsNumber && fastIsNumber(v1, left))
247 return jsNumber(exec, left + right);
249 bool leftIsString = v1->isString();
250 if (leftIsString && v2->isString()) {
251 RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
253 return throwOutOfMemoryError(exec);
254 return jsString(exec, value.release());
257 if (rightIsNumber & leftIsString) {
258 RefPtr<UString::Rep> value = JSImmediate::isImmediate(v2) ?
259 concatenate(static_cast<JSString*>(v1)->value().rep(), JSImmediate::getTruncatedInt32(v2)) :
260 concatenate(static_cast<JSString*>(v1)->value().rep(), right);
263 return throwOutOfMemoryError(exec);
264 return jsString(exec, value.release());
267 // All other cases are pretty uncommon
268 return jsAddSlowCase(exec, v1, v2);
271 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
273 if (v->isUndefined())
274 return jsNontrivialString(exec, "undefined");
276 return jsNontrivialString(exec, "boolean");
278 return jsNontrivialString(exec, "number");
280 return jsNontrivialString(exec, "string");
282 // Return "undefined" for objects that should be treated
283 // as null when doing comparisons.
284 if (static_cast<JSObject*>(v)->structureID()->typeInfo().masqueradesAsUndefined())
285 return jsNontrivialString(exec, "undefined");
287 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
288 return jsNontrivialString(exec, "function");
290 return jsNontrivialString(exec, "object");
293 static bool jsIsObjectType(JSValue* v)
295 if (JSImmediate::isImmediate(v))
298 JSType type = static_cast<JSCell*>(v)->structureID()->typeInfo().type();
299 if (type == NumberType || type == StringType)
301 if (type == ObjectType) {
302 if (static_cast<JSObject*>(v)->structureID()->typeInfo().masqueradesAsUndefined())
305 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
311 static bool jsIsFunctionType(JSValue* v)
315 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
321 NEVER_INLINE bool Machine::resolve(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
323 int dst = (vPC + 1)->u.operand;
324 int property = (vPC + 2)->u.operand;
326 ScopeChainNode* scopeChain = this->scopeChain(r);
327 ScopeChainIterator iter = scopeChain->begin();
328 ScopeChainIterator end = scopeChain->end();
331 CodeBlock* codeBlock = this->codeBlock(r);
332 Identifier& ident = codeBlock->identifiers[property];
335 PropertySlot slot(o);
336 if (o->getPropertySlot(exec, ident, slot)) {
337 JSValue* result = slot.getValue(exec, ident);
338 exceptionValue = exec->exception();
344 } while (++iter != end);
345 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
349 NEVER_INLINE bool Machine::resolveSkip(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
351 CodeBlock* codeBlock = this->codeBlock(r);
353 int dst = (vPC + 1)->u.operand;
354 int property = (vPC + 2)->u.operand;
355 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
357 ScopeChainNode* scopeChain = this->scopeChain(r);
358 ScopeChainIterator iter = scopeChain->begin();
359 ScopeChainIterator end = scopeChain->end();
365 Identifier& ident = codeBlock->identifiers[property];
368 PropertySlot slot(o);
369 if (o->getPropertySlot(exec, ident, slot)) {
370 JSValue* result = slot.getValue(exec, ident);
371 exceptionValue = exec->exception();
377 } while (++iter != end);
378 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
382 NEVER_INLINE bool Machine::resolveGlobal(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
384 int dst = (vPC + 1)->u.operand;
385 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
386 ASSERT(globalObject->isGlobalObject());
387 int property = (vPC + 3)->u.operand;
388 StructureID* structureID = (vPC + 4)->u.structureID;
389 int offset = (vPC + 5)->u.operand;
391 if (structureID == globalObject->structureID()) {
392 r[dst] = globalObject->getDirectOffset(offset);
396 CodeBlock* codeBlock = this->codeBlock(r);
397 Identifier& ident = codeBlock->identifiers[property];
398 PropertySlot slot(globalObject);
399 if (globalObject->getPropertySlot(exec, ident, slot)) {
400 JSValue* result = slot.getValue(exec, ident);
401 if (slot.isCacheable()) {
402 if (vPC[4].u.structureID)
403 vPC[4].u.structureID->deref();
404 globalObject->structureID()->ref();
405 vPC[4] = globalObject->structureID();
406 vPC[5] = slot.cachedOffset();
411 exceptionValue = exec->exception();
418 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
422 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
424 ScopeChainIterator iter = scopeChain->begin();
425 ScopeChainIterator next = iter;
427 ScopeChainIterator end = scopeChain->end();
434 if (next == end || base->getPropertySlot(exec, property, slot))
441 ASSERT_NOT_REACHED();
445 NEVER_INLINE void Machine::resolveBase(ExecState* exec, Instruction* vPC, Register* r)
447 int dst = (vPC + 1)->u.operand;
448 int property = (vPC + 2)->u.operand;
449 CodeBlock* codeBlock = this->codeBlock(r);
450 ScopeChainNode* scopeChain = this->scopeChain(r);
451 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
454 NEVER_INLINE bool Machine::resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
456 int baseDst = (vPC + 1)->u.operand;
457 int propDst = (vPC + 2)->u.operand;
458 int property = (vPC + 3)->u.operand;
460 ScopeChainNode* scopeChain = this->scopeChain(r);
461 ScopeChainIterator iter = scopeChain->begin();
462 ScopeChainIterator end = scopeChain->end();
464 // FIXME: add scopeDepthIsZero optimization
468 CodeBlock* codeBlock = this->codeBlock(r);
469 Identifier& ident = codeBlock->identifiers[property];
473 PropertySlot slot(base);
474 if (base->getPropertySlot(exec, ident, slot)) {
475 JSValue* result = slot.getValue(exec, ident);
476 exceptionValue = exec->exception();
484 } while (iter != end);
486 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
490 NEVER_INLINE bool Machine::resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, JSValue*& exceptionValue)
492 int baseDst = (vPC + 1)->u.operand;
493 int funcDst = (vPC + 2)->u.operand;
494 int property = (vPC + 3)->u.operand;
496 ScopeChainNode* scopeChain = this->scopeChain(r);
497 ScopeChainIterator iter = scopeChain->begin();
498 ScopeChainIterator end = scopeChain->end();
500 // FIXME: add scopeDepthIsZero optimization
504 CodeBlock* codeBlock = this->codeBlock(r);
505 Identifier& ident = codeBlock->identifiers[property];
509 PropertySlot slot(base);
510 if (base->getPropertySlot(exec, ident, slot)) {
511 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
512 // However, section 10.2.3 says that in the case where the value provided
513 // by the caller is null, the global object should be used. It also says
514 // that the section does not apply to internal functions, but for simplicity
515 // of implementation we use the global object anyway here. This guarantees
516 // that in host objects you always get a valid object for this.
517 // We also handle wrapper substitution for the global object at the same time.
518 JSObject* thisObj = base->toThisObject(exec);
519 JSValue* result = slot.getValue(exec, ident);
520 exceptionValue = exec->exception();
524 r[baseDst] = thisObj;
529 } while (iter != end);
531 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
535 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* r, size_t registerOffset, int argc, JSValue*& exceptionValue)
537 Register* newEnd = r + registerOffset + newCodeBlock->numCalleeRegisters;
539 if (argc == newCodeBlock->numParameters) { // correct number of arguments
540 if (!registerFile->grow(newEnd)) {
541 exceptionValue = createStackOverflowError(exec);
545 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
546 size_t omittedArgCount = newCodeBlock->numParameters - argc;
547 registerOffset += omittedArgCount;
548 newEnd += omittedArgCount;
549 if (!registerFile->grow(newEnd)) {
550 exceptionValue = createStackOverflowError(exec);
555 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
556 for (size_t i = 0; i < omittedArgCount; ++i)
557 argv[i] = jsUndefined();
558 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
559 size_t numParameters = newCodeBlock->numParameters;
560 registerOffset += numParameters;
561 newEnd += numParameters;
563 if (!registerFile->grow(newEnd)) {
564 exceptionValue = createStackOverflowError(exec);
569 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
570 for (size_t i = 0; i < numParameters; ++i)
571 argv[i + argc] = argv[i];
577 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
579 if (value->isObject())
581 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
585 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
588 return jsUndefined();
590 JSValue* program = r[argv + 1].jsValue(exec);
592 if (!program->isString())
595 Profiler** profiler = Profiler::enabledProfilerReference();
597 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
599 UString programSource = static_cast<JSString*>(program)->value();
601 CodeBlock* codeBlock = this->codeBlock(r);
602 RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
606 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->start() + argv + 1 + RegisterFile::CallFrameHeaderSize, scopeChain, &exceptionValue);
609 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
617 , m_ctiArrayLengthTrampoline(0)
618 , m_ctiStringLengthTrampoline(0)
619 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
623 , m_timeAtLastCheckTimeout(0)
625 , m_timeoutCheckCount(0)
626 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
629 privateExecute(InitializeAndReturn);
631 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
632 void* storage = fastMalloc(sizeof(CollectorBlock));
634 JSArray* jsArray = new (storage) JSArray(JSArray::createStructureID(jsNull()));
635 m_jsArrayVptr = jsArray->vptr();
636 static_cast<JSCell*>(jsArray)->~JSCell();
638 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
639 m_jsStringVptr = jsString->vptr();
640 static_cast<JSCell*>(jsString)->~JSCell();
642 JSFunction* jsFunction = new (storage) JSFunction(JSFunction::createStructureID(jsNull()));
643 m_jsFunctionVptr = jsFunction->vptr();
644 static_cast<JSCell*>(jsFunction)->~JSCell();
652 if (m_ctiArrayLengthTrampoline)
653 fastFree(m_ctiArrayLengthTrampoline);
654 if (m_ctiStringLengthTrampoline)
655 fastFree(m_ctiStringLengthTrampoline);
661 void Machine::dumpCallFrame(const RegisterFile* registerFile, const Register* r)
663 JSGlobalObject* globalObject = scopeChain(r)->globalObject();
665 CodeBlock* codeBlock = this->codeBlock(r);
666 codeBlock->dump(globalObject->globalExec());
668 dumpRegisters(registerFile, r);
671 void Machine::dumpRegisters(const RegisterFile* registerFile, const Register* r)
673 printf("Register frame: \n\n");
674 printf("----------------------------------------------------\n");
675 printf(" use | address | value \n");
676 printf("----------------------------------------------------\n");
678 CodeBlock* codeBlock = this->codeBlock(r);
682 if (codeBlock->codeType == GlobalCode) {
683 it = registerFile->lastGlobal();
684 end = it + registerFile->numGlobals();
686 printf("[global var] | %10p | %10p \n", it, (*it).v());
689 printf("----------------------------------------------------\n");
692 it = r - RegisterFile::CallFrameHeaderSize - codeBlock->numParameters;
693 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
694 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
697 printf("[param] | %10p | %10p \n", it, (*it).v());
701 printf("----------------------------------------------------\n");
703 printf("[CodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
704 printf("[ScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
705 printf("[CallerRegisters] | %10p | %10p \n", it, (*it).v()); ++it;
706 printf("[ReturnPC] | %10p | %10p \n", it, (*it).v()); ++it;
707 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
708 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
709 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
710 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
711 printf("[OptionalCalleeArguments] | %10p | %10p \n", it, (*it).v()); ++it;
712 printf("----------------------------------------------------\n");
714 int registerCount = 0;
716 end = it + codeBlock->numVars;
719 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
724 printf("----------------------------------------------------\n");
726 end = it + codeBlock->numConstants;
729 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
734 printf("----------------------------------------------------\n");
736 end = it + codeBlock->numCalleeRegisters - codeBlock->numConstants - codeBlock->numVars;
739 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
744 printf("----------------------------------------------------\n");
749 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
751 bool Machine::isOpcode(Opcode opcode)
753 #if HAVE(COMPUTED_GOTO)
754 return opcode != HashTraits<Opcode>::emptyValue()
755 && !HashTraits<Opcode>::isDeletedValue(opcode)
756 && m_opcodeIDTable.contains(opcode);
758 return opcode >= 0 && opcode <= op_end;
764 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, Register*& r)
766 CodeBlock* oldCodeBlock = codeBlock;
767 ScopeChainNode* scopeChain = this->scopeChain(r);
769 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
770 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
771 if (r[RegisterFile::Callee].jsValue(exec))
772 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->lastLine());
774 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->lastLine());
777 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
778 if (r[RegisterFile::Callee].jsValue(exec))
779 profiler->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
781 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
784 if (oldCodeBlock->needsFullScopeChain)
787 // If this call frame created an activation or an 'arguments' object, tear it off.
788 if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
789 ASSERT(activation->isObject(&JSActivation::info));
790 activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
791 } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
792 ASSERT(arguments->isObject(&Arguments::info));
793 arguments->copyRegisters();
796 void* returnPC = r[RegisterFile::ReturnPC].v();
797 r = r[RegisterFile::CallerRegisters].r();
798 if (isHostCallFrame(r))
801 exec->m_callFrame = r;
802 codeBlock = this->codeBlock(r);
803 vPC = vPCForPC(codeBlock, returnPC);
807 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, Register*& r, bool explicitThrow)
809 // Set up the exception object
811 CodeBlock* codeBlock = this->codeBlock(r);
812 if (exceptionValue->isObject()) {
813 JSObject* exception = static_cast<JSObject*>(exceptionValue);
814 if (exception->isNotAnObjectErrorStub()) {
815 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
816 exceptionValue = exception;
818 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
819 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
820 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
821 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
822 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
823 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
828 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
829 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
831 // We only hit this path for error messages and throw statements, which don't have a specific failure position
832 // So we just give the full range of the error/throw statement.
833 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
834 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
836 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
837 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceID()), ReadOnly | DontDelete);
838 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
841 if (exception->isWatchdogException()) {
842 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, r)) {
843 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
850 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
851 ScopeChainNode* scopeChain = this->scopeChain(r);
852 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
853 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceID(), codeBlock->lineNumberForVPC(vPC));
856 // Calculate an exception handler vPC, unwinding call frames as necessary.
859 Instruction* handlerVPC;
861 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
862 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, r))
866 // Now unwind the scope chain within the exception handler's call frame.
868 ScopeChain sc(this->scopeChain(r));
869 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
870 ASSERT(scopeDelta >= 0);
873 r[RegisterFile::ScopeChain] = sc.node();
878 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
880 ASSERT(!exec->hadException());
882 if (m_reentryDepth >= MaxReentryDepth) {
883 *exception = createStackOverflowError(exec);
887 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
889 Register* oldEnd = m_registerFile.end();
890 Register* newEnd = oldEnd + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->numCalleeRegisters;
891 if (!m_registerFile.grow(newEnd)) {
892 *exception = createStackOverflowError(exec);
896 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
897 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
898 globalObject->copyGlobalsTo(m_registerFile);
900 Register* r = oldEnd + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize;
901 r[codeBlock->thisRegister] = thisObj;
902 initializeCallFrame(r, codeBlock, 0, scopeChain, makeHostCallFramePointer(0), 0, 0, 0);
904 if (codeBlock->needsFullScopeChain)
905 scopeChain = scopeChain->copy();
907 ExecState newExec(r);
909 Profiler** profiler = Profiler::enabledProfilerReference();
911 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
915 if (!codeBlock->ctiCode)
916 CTI::compile(this, exec, codeBlock);
917 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, &newExec.globalData(), exception);
919 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, exception);
923 MACHINE_SAMPLING_privateExecuteReturned();
926 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
928 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
929 lastGlobalObject->copyGlobalsTo(m_registerFile);
931 m_registerFile.shrink(oldEnd);
935 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
937 ASSERT(!exec->hadException());
939 if (m_reentryDepth >= MaxReentryDepth) {
940 *exception = createStackOverflowError(exec);
944 Register* oldEnd = m_registerFile.end();
945 int argc = 1 + args.size(); // implicit "this" parameter
947 if (!m_registerFile.grow(oldEnd + argc)) {
948 *exception = createStackOverflowError(exec);
952 Register* argv = oldEnd;
956 ArgList::const_iterator end = args.end();
957 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
960 CodeBlock* codeBlock = &functionBodyNode->byteCode(scopeChain);
961 Register* r = slideRegisterWindowForCall(exec, codeBlock, &m_registerFile, argv, argc + RegisterFile::CallFrameHeaderSize, argc, *exception);
962 if (UNLIKELY(*exception != 0)) {
963 m_registerFile.shrink(oldEnd);
966 // a 0 codeBlock indicates a built-in caller
967 initializeCallFrame(r, codeBlock, 0, scopeChain, makeHostCallFramePointer(exec->m_callFrame), 0, argc, function);
969 ExecState newExec(r);
971 Profiler** profiler = Profiler::enabledProfilerReference();
973 (*profiler)->willExecute(exec, function);
977 if (!codeBlock->ctiCode)
978 CTI::compile(this, exec, codeBlock);
979 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, &newExec.globalData(), exception);
981 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, exception);
985 MACHINE_SAMPLING_privateExecuteReturned();
987 m_registerFile.shrink(oldEnd);
991 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception)
993 return execute(evalNode, exec, thisObj, m_registerFile.size() + evalNode->byteCode(scopeChain).numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
996 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
998 ASSERT(!exec->hadException());
1000 if (m_reentryDepth >= MaxReentryDepth) {
1001 *exception = createStackOverflowError(exec);
1005 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
1007 JSVariableObject* variableObject;
1008 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
1010 if (node->object->isVariableObject()) {
1011 variableObject = static_cast<JSVariableObject*>(node->object);
1016 { // Scope for BatchedTransitionOptimizer
1018 BatchedTransitionOptimizer optimizer(variableObject);
1020 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
1021 Node::VarStack::const_iterator varStackEnd = varStack.end();
1022 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
1023 const Identifier& ident = (*it).first;
1024 if (!variableObject->hasProperty(exec, ident)) {
1025 PutPropertySlot slot;
1026 variableObject->put(exec, ident, jsUndefined(), slot);
1030 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
1031 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
1032 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
1033 PutPropertySlot slot;
1034 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
1039 Register* oldEnd = m_registerFile.end();
1040 Register* newEnd = m_registerFile.start() + registerOffset + codeBlock->numCalleeRegisters;
1041 if (!m_registerFile.grow(newEnd)) {
1042 *exception = createStackOverflowError(exec);
1046 Register* r = m_registerFile.start() + registerOffset;
1048 // a 0 codeBlock indicates a built-in caller
1049 r[codeBlock->thisRegister] = thisObj;
1050 initializeCallFrame(r, codeBlock, 0, scopeChain, makeHostCallFramePointer(exec->m_callFrame), 0, 0, 0);
1052 if (codeBlock->needsFullScopeChain)
1053 scopeChain = scopeChain->copy();
1055 ExecState newExec(r);
1057 Profiler** profiler = Profiler::enabledProfilerReference();
1059 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1063 if (!codeBlock->ctiCode)
1064 CTI::compile(this, exec, codeBlock);
1065 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, &newExec.globalData(), exception);
1067 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, exception);
1071 MACHINE_SAMPLING_privateExecuteReturned();
1074 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1076 m_registerFile.shrink(oldEnd);
1080 NEVER_INLINE void Machine::debug(ExecState* exec, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
1082 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
1086 CodeBlock* codeBlock = this->codeBlock(r);
1087 ScopeChainNode* scopeChain = this->scopeChain(r);
1088 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
1090 switch (debugHookID) {
1091 case DidEnterCallFrame:
1092 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceID(), firstLine);
1094 case WillLeaveCallFrame:
1095 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceID(), lastLine);
1097 case WillExecuteStatement:
1098 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceID(), firstLine);
1100 case WillExecuteProgram:
1101 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceID(), firstLine);
1103 case DidExecuteProgram:
1104 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceID(), lastLine);
1106 case DidReachBreakpoint:
1107 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceID(), lastLine);
1112 void Machine::resetTimeoutCheck()
1114 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1115 m_timeAtLastCheckTimeout = 0;
1116 m_timeExecuting = 0;
1119 // Returns the time the current thread has spent executing, in milliseconds.
1120 static inline unsigned getCPUTime()
1122 #if PLATFORM(DARWIN)
1123 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1124 thread_basic_info_data_t info;
1126 // Get thread information
1127 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1129 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1130 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1133 #elif HAVE(SYS_TIME_H)
1134 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1136 gettimeofday(&tv, 0);
1137 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1139 QDateTime t = QDateTime::currentDateTime();
1140 return t.toTime_t() * 1000 + t.time().msec();
1141 #elif PLATFORM(WIN_OS)
1144 unsigned long long fileTimeAsLong;
1145 } userTime, kernelTime;
1147 // GetThreadTimes won't accept NULL arguments so we pass these even though
1148 // they're not used.
1149 FILETIME creationTime, exitTime;
1151 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1153 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1155 #error Platform does not have getCurrentTime function
1159 // We have to return a JSValue here, gcc seems to produce worse code if
1160 // we attempt to return a bool
1161 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1163 unsigned currentTime = getCPUTime();
1165 if (!m_timeAtLastCheckTimeout) {
1166 // Suspicious amount of looping in a script -- start timing it
1167 m_timeAtLastCheckTimeout = currentTime;
1171 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1176 m_timeExecuting += timeDiff;
1177 m_timeAtLastCheckTimeout = currentTime;
1179 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1180 // preferredScriptCheckTimeInterval
1181 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1182 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1183 // preferred script check time interval.
1184 if (m_ticksUntilNextTimeoutCheck == 0)
1185 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1187 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1188 if (globalObject->shouldInterruptScript())
1189 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1191 resetTimeoutCheck();
1197 NEVER_INLINE ScopeChainNode* Machine::createExceptionScope(ExecState* exec, const Instruction* vPC, Register* r)
1199 int dst = (++vPC)->u.operand;
1200 CodeBlock* codeBlock = this->codeBlock(r);
1201 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1202 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1203 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1206 return scopeChain(r)->push(scope);
1209 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1211 JSValue* prototype = structureID->prototypeForLookup(exec);
1212 if (JSImmediate::isImmediate(prototype))
1214 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(prototype)->structureID());
1215 structureID->setCachedPrototypeChain(chain.release());
1216 return structureID->cachedPrototypeChain();
1219 NEVER_INLINE void Machine::tryCachePutByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1221 // Recursive invocation may already have specialized this instruction.
1222 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1225 if (JSImmediate::isImmediate(baseValue))
1228 // Uncacheable: give up.
1229 if (!slot.isCacheable()) {
1230 vPC[0] = getOpcode(op_put_by_id_generic);
1234 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1235 StructureID* structureID = baseCell->structureID();
1237 if (structureID->isDictionary()) {
1238 vPC[0] = getOpcode(op_put_by_id_generic);
1242 // Cache miss: record StructureID to compare against next time.
1243 StructureID* lastStructureID = vPC[4].u.structureID;
1244 if (structureID != lastStructureID) {
1245 // First miss: record StructureID to compare against next time.
1246 if (!lastStructureID) {
1247 vPC[4] = structureID;
1251 // Second miss: give up.
1252 vPC[0] = getOpcode(op_put_by_id_generic);
1256 // Cache hit: Specialize instruction and ref StructureIDs.
1258 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1259 if (baseCell != slot.base()) {
1260 vPC[0] = getOpcode(op_put_by_id_generic);
1264 // StructureID transition, cache transition info
1265 if (slot.type() == PutPropertySlot::NewProperty) {
1266 vPC[0] = getOpcode(op_put_by_id_transition);
1267 vPC[4] = structureID->previousID();
1268 vPC[5] = structureID;
1269 StructureIDChain* chain = structureID->cachedPrototypeChain();
1271 chain = cachePrototypeChain(exec, structureID);
1273 // This happens if someone has manually inserted null into the prototype chain
1274 vPC[0] = getOpcode(op_put_by_id_generic);
1279 vPC[7] = slot.cachedOffset();
1280 codeBlock->refStructureIDs(vPC);
1284 vPC[0] = getOpcode(op_put_by_id_replace);
1285 vPC[5] = slot.cachedOffset();
1286 codeBlock->refStructureIDs(vPC);
1289 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1291 codeBlock->derefStructureIDs(vPC);
1292 vPC[0] = getOpcode(op_put_by_id);
1296 NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1298 // Recursive invocation may already have specialized this instruction.
1299 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1302 // FIXME: Cache property access for immediates.
1303 if (JSImmediate::isImmediate(baseValue)) {
1304 vPC[0] = getOpcode(op_get_by_id_generic);
1308 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1309 vPC[0] = getOpcode(op_get_array_length);
1313 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1314 vPC[0] = getOpcode(op_get_string_length);
1318 // Uncacheable: give up.
1319 if (!slot.isCacheable()) {
1320 vPC[0] = getOpcode(op_get_by_id_generic);
1324 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1326 if (structureID->isDictionary()) {
1327 vPC[0] = getOpcode(op_get_by_id_generic);
1332 StructureID* lastStructureID = vPC[4].u.structureID;
1333 if (structureID != lastStructureID) {
1334 // First miss: record StructureID to compare against next time.
1335 if (!lastStructureID) {
1336 vPC[4] = structureID;
1340 // Second miss: give up.
1341 vPC[0] = getOpcode(op_get_by_id_generic);
1345 // Cache hit: Specialize instruction and ref StructureIDs.
1347 if (slot.slotBase() == baseValue) {
1348 vPC[0] = getOpcode(op_get_by_id_self);
1349 vPC[5] = slot.cachedOffset();
1351 codeBlock->refStructureIDs(vPC);
1355 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1356 ASSERT(slot.slotBase()->isObject());
1358 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1360 // Heavy access to a prototype is a good indication that it's not being
1361 // used as a dictionary.
1362 if (baseObject->structureID()->isDictionary()) {
1363 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1364 baseObject->setStructureID(transition.release());
1365 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1368 vPC[0] = getOpcode(op_get_by_id_proto);
1369 vPC[5] = baseObject->structureID();
1370 vPC[6] = slot.cachedOffset();
1372 codeBlock->refStructureIDs(vPC);
1377 JSObject* o = static_cast<JSObject*>(baseValue);
1378 while (slot.slotBase() != o) {
1379 JSValue* v = o->structureID()->prototypeForLookup(exec);
1381 // If we didn't find base in baseValue's prototype chain, then baseValue
1382 // must be a proxy for another object.
1384 vPC[0] = getOpcode(op_get_by_id_generic);
1388 o = static_cast<JSObject*>(v);
1390 // Heavy access to a prototype is a good indication that it's not being
1391 // used as a dictionary.
1392 if (o->structureID()->isDictionary()) {
1393 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1394 o->setStructureID(transition.release());
1395 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1401 StructureIDChain* chain = structureID->cachedPrototypeChain();
1403 chain = cachePrototypeChain(exec, structureID);
1406 vPC[0] = getOpcode(op_get_by_id_chain);
1407 vPC[4] = structureID;
1410 vPC[7] = slot.cachedOffset();
1411 codeBlock->refStructureIDs(vPC);
1414 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1416 codeBlock->derefStructureIDs(vPC);
1417 vPC[0] = getOpcode(op_get_by_id);
1421 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, JSValue** exception)
1423 // One-time initialization of our address tables. We have to put this code
1424 // here because our labels are only in scope inside this function.
1425 if (flag == InitializeAndReturn) {
1426 #if HAVE(COMPUTED_GOTO)
1427 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1428 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1431 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1432 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1433 #undef ADD_OPCODE_ID
1434 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1435 op_throw_end_indirect = &&op_throw_end;
1436 op_call_indirect = &&op_call;
1437 #endif // HAVE(COMPUTED_GOTO)
1442 // Currently with CTI enabled we never interpret functions
1443 ASSERT_NOT_REACHED();
1446 JSValue* exceptionValue = 0;
1447 Instruction* handlerVPC = 0;
1449 Instruction* vPC = this->codeBlock(r)->instructions.begin();
1450 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1451 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1453 #define VM_CHECK_EXCEPTION() \
1455 if (UNLIKELY(exec->hadException())) { \
1456 exceptionValue = exec->exception(); \
1461 #if DUMP_OPCODE_STATS
1462 OpcodeStats::resetLastInstruction();
1465 #define CHECK_FOR_TIMEOUT() \
1466 if (!--tickCount) { \
1467 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1469 tickCount = m_ticksUntilNextTimeoutCheck; \
1472 #if HAVE(COMPUTED_GOTO)
1473 #define NEXT_OPCODE MACHINE_SAMPLING_sample(this->codeBlock(r), vPC); goto *vPC->u.opcode
1474 #if DUMP_OPCODE_STATS
1475 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1477 #define BEGIN_OPCODE(opcode) opcode:
1481 #define NEXT_OPCODE MACHINE_SAMPLING_sample(this->codeBlock(r), vPC); continue
1482 #if DUMP_OPCODE_STATS
1483 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1485 #define BEGIN_OPCODE(opcode) case opcode:
1487 while (1) // iterator loop begins
1488 switch (vPC->u.opcode)
1491 BEGIN_OPCODE(op_new_object) {
1492 /* new_object dst(r)
1494 Constructs a new empty Object instance using the original
1495 constructor, and puts the result in register dst.
1497 int dst = (++vPC)->u.operand;
1498 r[dst] = constructEmptyObject(exec);
1503 BEGIN_OPCODE(op_new_array) {
1504 /* new_array dst(r) firstArg(r) argCount(n)
1506 Constructs a new Array instance using the original
1507 constructor, and puts the result in register dst.
1508 The array will contain argCount elements with values
1509 taken from registers starting at register firstArg.
1511 int dst = (++vPC)->u.operand;
1512 int firstArg = (++vPC)->u.operand;
1513 int argCount = (++vPC)->u.operand;
1514 ArgList args(r + firstArg, argCount);
1515 r[dst] = constructArray(exec, args);
1520 BEGIN_OPCODE(op_new_regexp) {
1521 /* new_regexp dst(r) regExp(re)
1523 Constructs a new RegExp instance using the original
1524 constructor from regexp regExp, and puts the result in
1527 int dst = (++vPC)->u.operand;
1528 int regExp = (++vPC)->u.operand;
1529 r[dst] = new (exec) RegExpObject(scopeChain(r)->globalObject()->regExpStructure(), codeBlock(r)->regexps[regExp]);
1534 BEGIN_OPCODE(op_mov) {
1535 /* mov dst(r) src(r)
1537 Copies register src to register dst.
1539 int dst = (++vPC)->u.operand;
1540 int src = (++vPC)->u.operand;
1546 BEGIN_OPCODE(op_eq) {
1547 /* eq dst(r) src1(r) src2(r)
1549 Checks whether register src1 and register src2 are equal,
1550 as with the ECMAScript '==' operator, and puts the result
1551 as a boolean in register dst.
1553 int dst = (++vPC)->u.operand;
1554 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1555 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1556 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1557 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1559 JSValue* result = jsBoolean(equalSlowCase(exec, src1, src2));
1560 VM_CHECK_EXCEPTION();
1567 BEGIN_OPCODE(op_eq_null) {
1568 /* neq dst(r) src(r)
1570 Checks whether register src is null, as with the ECMAScript '!='
1571 operator, and puts the result as a boolean in register dst.
1573 int dst = (++vPC)->u.operand;
1574 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1576 if (src->isUndefinedOrNull()) {
1577 r[dst] = jsBoolean(true);
1582 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && src->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
1586 BEGIN_OPCODE(op_neq) {
1587 /* neq dst(r) src1(r) src2(r)
1589 Checks whether register src1 and register src2 are not
1590 equal, as with the ECMAScript '!=' operator, and puts the
1591 result as a boolean in register dst.
1593 int dst = (++vPC)->u.operand;
1594 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1595 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1596 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1597 r[dst] = jsBoolean(src1 != src2);
1599 JSValue* result = jsBoolean(!equalSlowCase(exec, src1, src2));
1600 VM_CHECK_EXCEPTION();
1607 BEGIN_OPCODE(op_neq_null) {
1608 /* neq dst(r) src(r)
1610 Checks whether register src is not null, as with the ECMAScript '!='
1611 operator, and puts the result as a boolean in register dst.
1613 int dst = (++vPC)->u.operand;
1614 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1616 if (src->isUndefinedOrNull()) {
1617 r[dst] = jsBoolean(false);
1622 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
1626 BEGIN_OPCODE(op_stricteq) {
1627 /* stricteq dst(r) src1(r) src2(r)
1629 Checks whether register src1 and register src2 are strictly
1630 equal, as with the ECMAScript '===' operator, and puts the
1631 result as a boolean in register dst.
1633 int dst = (++vPC)->u.operand;
1634 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1635 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1636 if (JSImmediate::areBothImmediate(src1, src2))
1637 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1638 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1639 r[dst] = jsBoolean(false);
1641 r[dst] = jsBoolean(strictEqualSlowCase(src1, src2));
1646 BEGIN_OPCODE(op_nstricteq) {
1647 /* nstricteq dst(r) src1(r) src2(r)
1649 Checks whether register src1 and register src2 are not
1650 strictly equal, as with the ECMAScript '!==' operator, and
1651 puts the result as a boolean in register dst.
1653 int dst = (++vPC)->u.operand;
1654 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1655 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1657 if (JSImmediate::areBothImmediate(src1, src2))
1658 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1659 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1660 r[dst] = jsBoolean(true);
1662 r[dst] = jsBoolean(!strictEqualSlowCase(src1, src2));
1667 BEGIN_OPCODE(op_less) {
1668 /* less dst(r) src1(r) src2(r)
1670 Checks whether register src1 is less than register src2, as
1671 with the ECMAScript '<' operator, and puts the result as
1672 a boolean in register dst.
1674 int dst = (++vPC)->u.operand;
1675 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1676 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1677 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1678 VM_CHECK_EXCEPTION();
1684 BEGIN_OPCODE(op_lesseq) {
1685 /* lesseq dst(r) src1(r) src2(r)
1687 Checks whether register src1 is less than or equal to
1688 register src2, as with the ECMAScript '<=' operator, and
1689 puts the result as a boolean in register dst.
1691 int dst = (++vPC)->u.operand;
1692 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1693 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1694 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1695 VM_CHECK_EXCEPTION();
1701 BEGIN_OPCODE(op_pre_inc) {
1702 /* pre_inc srcDst(r)
1704 Converts register srcDst to number, adds one, and puts the result
1705 back in register srcDst.
1707 int srcDst = (++vPC)->u.operand;
1708 JSValue* v = r[srcDst].jsValue(exec);
1709 if (JSImmediate::canDoFastAdditiveOperations(v))
1710 r[srcDst] = JSImmediate::incImmediateNumber(v);
1712 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1713 VM_CHECK_EXCEPTION();
1720 BEGIN_OPCODE(op_pre_dec) {
1721 /* pre_dec srcDst(r)
1723 Converts register srcDst to number, subtracts one, and puts the result
1724 back in register srcDst.
1726 int srcDst = (++vPC)->u.operand;
1727 JSValue* v = r[srcDst].jsValue(exec);
1728 if (JSImmediate::canDoFastAdditiveOperations(v))
1729 r[srcDst] = JSImmediate::decImmediateNumber(v);
1731 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1732 VM_CHECK_EXCEPTION();
1739 BEGIN_OPCODE(op_post_inc) {
1740 /* post_inc dst(r) srcDst(r)
1742 Converts register srcDst to number. The number itself is
1743 written to register dst, and the number plus one is written
1744 back to register srcDst.
1746 int dst = (++vPC)->u.operand;
1747 int srcDst = (++vPC)->u.operand;
1748 JSValue* v = r[srcDst].jsValue(exec);
1749 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1751 r[srcDst] = JSImmediate::incImmediateNumber(v);
1753 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1754 VM_CHECK_EXCEPTION();
1756 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1762 BEGIN_OPCODE(op_post_dec) {
1763 /* post_dec dst(r) srcDst(r)
1765 Converts register srcDst to number. The number itself is
1766 written to register dst, and the number minus one is written
1767 back to register srcDst.
1769 int dst = (++vPC)->u.operand;
1770 int srcDst = (++vPC)->u.operand;
1771 JSValue* v = r[srcDst].jsValue(exec);
1772 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1774 r[srcDst] = JSImmediate::decImmediateNumber(v);
1776 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1777 VM_CHECK_EXCEPTION();
1779 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1785 BEGIN_OPCODE(op_to_jsnumber) {
1786 /* to_jsnumber dst(r) src(r)
1788 Converts register src to number, and puts the result
1791 int dst = (++vPC)->u.operand;
1792 int src = (++vPC)->u.operand;
1793 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1794 VM_CHECK_EXCEPTION();
1801 BEGIN_OPCODE(op_negate) {
1802 /* negate dst(r) src(r)
1804 Converts register src to number, negates it, and puts the
1805 result in register dst.
1807 int dst = (++vPC)->u.operand;
1808 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1810 if (fastIsNumber(src, v))
1811 r[dst] = jsNumber(exec, -v);
1813 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1814 VM_CHECK_EXCEPTION();
1821 BEGIN_OPCODE(op_add) {
1822 /* add dst(r) src1(r) src2(r)
1824 Adds register src1 and register src2, and puts the result
1825 in register dst. (JS add may be string concatenation or
1826 numeric add, depending on the types of the operands.)
1828 int dst = (++vPC)->u.operand;
1829 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1830 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1831 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1832 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1834 JSValue* result = jsAdd(exec, src1, src2);
1835 VM_CHECK_EXCEPTION();
1841 BEGIN_OPCODE(op_mul) {
1842 /* mul dst(r) src1(r) src2(r)
1844 Multiplies register src1 and register src2 (converted to
1845 numbers), and puts the product in register dst.
1847 int dst = (++vPC)->u.operand;
1848 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1849 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1852 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1853 r[dst] = jsNumber(exec, left * right);
1855 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1856 VM_CHECK_EXCEPTION();
1863 BEGIN_OPCODE(op_div) {
1864 /* div dst(r) dividend(r) divisor(r)
1866 Divides register dividend (converted to number) by the
1867 register divisor (converted to number), and puts the
1868 quotient in register dst.
1870 int dst = (++vPC)->u.operand;
1871 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1872 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1875 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1876 r[dst] = jsNumber(exec, left / right);
1878 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1879 VM_CHECK_EXCEPTION();
1885 BEGIN_OPCODE(op_mod) {
1886 /* mod dst(r) dividend(r) divisor(r)
1888 Divides register dividend (converted to number) by
1889 register divisor (converted to number), and puts the
1890 remainder in register dst.
1892 int dst = (++vPC)->u.operand;
1893 int dividend = (++vPC)->u.operand;
1894 int divisor = (++vPC)->u.operand;
1896 JSValue* dividendValue = r[dividend].jsValue(exec);
1897 JSValue* divisorValue = r[divisor].jsValue(exec);
1899 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1900 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1905 double d = dividendValue->toNumber(exec);
1906 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1907 VM_CHECK_EXCEPTION();
1912 BEGIN_OPCODE(op_sub) {
1913 /* sub dst(r) src1(r) src2(r)
1915 Subtracts register src2 (converted to number) from register
1916 src1 (converted to number), and puts the difference in
1919 int dst = (++vPC)->u.operand;
1920 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1921 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1924 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1925 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1926 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1927 r[dst] = jsNumber(exec, left - right);
1929 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1930 VM_CHECK_EXCEPTION();
1936 BEGIN_OPCODE(op_lshift) {
1937 /* lshift dst(r) val(r) shift(r)
1939 Performs left shift of register val (converted to int32) by
1940 register shift (converted to uint32), and puts the result
1943 int dst = (++vPC)->u.operand;
1944 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1945 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1948 if (JSImmediate::areBothImmediateNumbers(val, shift))
1949 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1950 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1951 r[dst] = jsNumber(exec, left << (right & 0x1f));
1953 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1954 VM_CHECK_EXCEPTION();
1961 BEGIN_OPCODE(op_rshift) {
1962 /* rshift dst(r) val(r) shift(r)
1964 Performs arithmetic right shift of register val (converted
1965 to int32) by register shift (converted to
1966 uint32), and puts the result in register dst.
1968 int dst = (++vPC)->u.operand;
1969 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1970 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1973 if (JSImmediate::areBothImmediateNumbers(val, shift))
1974 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1975 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1976 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1978 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1979 VM_CHECK_EXCEPTION();
1986 BEGIN_OPCODE(op_urshift) {
1987 /* rshift dst(r) val(r) shift(r)
1989 Performs logical right shift of register val (converted
1990 to uint32) by register shift (converted to
1991 uint32), and puts the result in register dst.
1993 int dst = (++vPC)->u.operand;
1994 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1995 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1996 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1997 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1999 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
2000 VM_CHECK_EXCEPTION();
2007 BEGIN_OPCODE(op_bitand) {
2008 /* bitand dst(r) src1(r) src2(r)
2010 Computes bitwise AND of register src1 (converted to int32)
2011 and register src2 (converted to int32), and puts the result
2014 int dst = (++vPC)->u.operand;
2015 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2016 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2019 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2020 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
2021 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2022 r[dst] = jsNumber(exec, left & right);
2024 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
2025 VM_CHECK_EXCEPTION();
2032 BEGIN_OPCODE(op_bitxor) {
2033 /* bitxor dst(r) src1(r) src2(r)
2035 Computes bitwise XOR of register src1 (converted to int32)
2036 and register src2 (converted to int32), and puts the result
2039 int dst = (++vPC)->u.operand;
2040 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2041 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2044 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2045 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
2046 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2047 r[dst] = jsNumber(exec, left ^ right);
2049 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
2050 VM_CHECK_EXCEPTION();
2057 BEGIN_OPCODE(op_bitor) {
2058 /* bitor dst(r) src1(r) src2(r)
2060 Computes bitwise OR of register src1 (converted to int32)
2061 and register src2 (converted to int32), and puts the
2062 result in register dst.
2064 int dst = (++vPC)->u.operand;
2065 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2066 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2069 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2070 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
2071 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2072 r[dst] = jsNumber(exec, left | right);
2074 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
2075 VM_CHECK_EXCEPTION();
2082 BEGIN_OPCODE(op_bitnot) {
2083 /* bitnot dst(r) src(r)
2085 Computes bitwise NOT of register src1 (converted to int32),
2086 and puts the result in register dst.
2088 int dst = (++vPC)->u.operand;
2089 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
2091 if (fastToInt32(src, value))
2092 r[dst] = jsNumber(exec, ~value);
2094 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
2095 VM_CHECK_EXCEPTION();
2101 BEGIN_OPCODE(op_not) {
2102 /* not dst(r) src(r)
2104 Computes logical NOT of register src (converted to
2105 boolean), and puts the result in register dst.
2107 int dst = (++vPC)->u.operand;
2108 int src = (++vPC)->u.operand;
2109 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
2110 VM_CHECK_EXCEPTION();
2116 BEGIN_OPCODE(op_instanceof) {
2117 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2119 Tests whether register value is an instance of register
2120 constructor, and puts the boolean result in register
2121 dst. Register constructorProto must contain the "prototype"
2122 property (not the actual prototype) of the object in
2123 register constructor. This lookup is separated so that
2124 polymorphic inline caching can apply.
2126 Raises an exception if register constructor is not an
2129 int dst = (++vPC)->u.operand;
2130 int value = (++vPC)->u.operand;
2131 int base = (++vPC)->u.operand;
2132 int baseProto = (++vPC)->u.operand;
2134 JSValue* baseVal = r[base].jsValue(exec);
2136 if (isNotObject(exec, true, codeBlock(r), vPC, baseVal, exceptionValue))
2139 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2140 r[dst] = jsBoolean(baseObj->structureID()->typeInfo().implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec), r[baseProto].jsValue(exec)) : false);
2145 BEGIN_OPCODE(op_typeof) {
2146 /* typeof dst(r) src(r)
2148 Determines the type string for src according to ECMAScript
2149 rules, and puts the result in register dst.
2151 int dst = (++vPC)->u.operand;
2152 int src = (++vPC)->u.operand;
2153 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2158 BEGIN_OPCODE(op_is_undefined) {
2159 /* is_undefined dst(r) src(r)
2161 Determines whether the type string for src according to
2162 the ECMAScript rules is "undefined", and puts the result
2165 int dst = (++vPC)->u.operand;
2166 int src = (++vPC)->u.operand;
2167 JSValue* v = r[src].jsValue(exec);
2168 r[dst] = jsBoolean(JSImmediate::isImmediate(v) ? v->isUndefined() : v->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
2173 BEGIN_OPCODE(op_is_boolean) {
2174 /* is_boolean dst(r) src(r)
2176 Determines whether the type string for src according to
2177 the ECMAScript rules is "boolean", and puts the result
2180 int dst = (++vPC)->u.operand;
2181 int src = (++vPC)->u.operand;
2182 r[dst] = jsBoolean(r[src].jsValue(exec)->isBoolean());
2187 BEGIN_OPCODE(op_is_number) {
2188 /* is_number dst(r) src(r)
2190 Determines whether the type string for src according to
2191 the ECMAScript rules is "number", and puts the result
2194 int dst = (++vPC)->u.operand;
2195 int src = (++vPC)->u.operand;
2196 r[dst] = jsBoolean(r[src].jsValue(exec)->isNumber());
2201 BEGIN_OPCODE(op_is_string) {
2202 /* is_string dst(r) src(r)
2204 Determines whether the type string for src according to
2205 the ECMAScript rules is "string", and puts the result
2208 int dst = (++vPC)->u.operand;
2209 int src = (++vPC)->u.operand;
2210 r[dst] = jsBoolean(r[src].jsValue(exec)->isString());
2215 BEGIN_OPCODE(op_is_object) {
2216 /* is_object dst(r) src(r)
2218 Determines whether the type string for src according to
2219 the ECMAScript rules is "object", and puts the result
2222 int dst = (++vPC)->u.operand;
2223 int src = (++vPC)->u.operand;
2224 r[dst] = jsBoolean(jsIsObjectType(r[src].jsValue(exec)));
2229 BEGIN_OPCODE(op_is_function) {
2230 /* is_function dst(r) src(r)
2232 Determines whether the type string for src according to
2233 the ECMAScript rules is "function", and puts the result
2236 int dst = (++vPC)->u.operand;
2237 int src = (++vPC)->u.operand;
2238 r[dst] = jsBoolean(jsIsFunctionType(r[src].jsValue(exec)));
2243 BEGIN_OPCODE(op_in) {
2244 /* in dst(r) property(r) base(r)
2246 Tests whether register base has a property named register
2247 property, and puts the boolean result in register dst.
2249 Raises an exception if register constructor is not an
2252 int dst = (++vPC)->u.operand;
2253 int property = (++vPC)->u.operand;
2254 int base = (++vPC)->u.operand;
2256 JSValue* baseVal = r[base].jsValue(exec);
2257 if (isNotObject(exec, false, codeBlock(r), vPC, baseVal, exceptionValue))
2260 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2262 JSValue* propName = r[property].jsValue(exec);
2265 if (propName->getUInt32(i))
2266 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2268 Identifier property(exec, propName->toString(exec));
2269 VM_CHECK_EXCEPTION();
2270 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2276 BEGIN_OPCODE(op_resolve) {
2277 /* resolve dst(r) property(id)
2279 Looks up the property named by identifier property in the
2280 scope chain, and writes the resulting value to register
2281 dst. If the property is not found, raises an exception.
2283 if (UNLIKELY(!resolve(exec, vPC, r, exceptionValue)))
2289 BEGIN_OPCODE(op_resolve_skip) {
2290 /* resolve_skip dst(r) property(id) skip(n)
2292 Looks up the property named by identifier property in the
2293 scope chain skipping the top 'skip' levels, and writes the resulting
2294 value to register dst. If the property is not found, raises an exception.
2296 if (UNLIKELY(!resolveSkip(exec, vPC, r, exceptionValue)))
2303 BEGIN_OPCODE(op_resolve_global) {
2304 /* resolve_skip dst(r) globalObject(c) property(id) structureID(sID) offset(n)
2306 Performs a dynamic property lookup for the given property, on the provided
2307 global object. If structureID matches the StructureID of the global then perform
2308 a fast lookup using the case offset, otherwise fall back to a full resolve and
2309 cache the new structureID and offset
2311 if (UNLIKELY(!resolveGlobal(exec, vPC, r, exceptionValue)))
2318 BEGIN_OPCODE(op_get_global_var) {
2319 /* get_global_var dst(r) globalObject(c) index(n)
2321 Gets the global var at global slot index and places it in register dst.
2323 int dst = (++vPC)->u.operand;
2324 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2325 ASSERT(scope->isGlobalObject());
2326 int index = (++vPC)->u.operand;
2328 r[dst] = scope->registerAt(index);
2332 BEGIN_OPCODE(op_put_global_var) {
2333 /* put_global_var globalObject(c) index(n) value(r)
2335 Puts value into global slot index.
2337 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2338 ASSERT(scope->isGlobalObject());
2339 int index = (++vPC)->u.operand;
2340 int value = (++vPC)->u.operand;
2342 scope->registerAt(index) = r[value].jsValue(exec);
2346 BEGIN_OPCODE(op_get_scoped_var) {
2347 /* get_scoped_var dst(r) index(n) skip(n)
2349 Loads the contents of the index-th local from the scope skip nodes from
2350 the top of the scope chain, and places it in register dst
2352 int dst = (++vPC)->u.operand;
2353 int index = (++vPC)->u.operand;
2354 int skip = (++vPC)->u.operand + codeBlock(r)->needsFullScopeChain;
2356 ScopeChainNode* scopeChain = this->scopeChain(r);
2357 ScopeChainIterator iter = scopeChain->begin();
2358 ScopeChainIterator end = scopeChain->end();
2359 ASSERT(iter != end);
2362 ASSERT(iter != end);
2365 ASSERT((*iter)->isVariableObject());
2366 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2367 r[dst] = scope->registerAt(index);
2371 BEGIN_OPCODE(op_put_scoped_var) {
2372 /* put_scoped_var index(n) skip(n) value(r)
2375 int index = (++vPC)->u.operand;
2376 int skip = (++vPC)->u.operand + codeBlock(r)->needsFullScopeChain;
2377 int value = (++vPC)->u.operand;
2379 ScopeChainNode* scopeChain = this->scopeChain(r);
2380 ScopeChainIterator iter = scopeChain->begin();
2381 ScopeChainIterator end = scopeChain->end();
2382 ASSERT(iter != end);
2385 ASSERT(iter != end);
2388 ASSERT((*iter)->isVariableObject());
2389 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2390 scope->registerAt(index) = r[value].jsValue(exec);
2394 BEGIN_OPCODE(op_resolve_base) {
2395 /* resolve_base dst(r) property(id)
2397 Searches the scope chain for an object containing
2398 identifier property, and if one is found, writes it to
2399 register dst. If none is found, the outermost scope (which
2400 will be the global object) is stored in register dst.
2402 resolveBase(exec, vPC, r);
2407 BEGIN_OPCODE(op_resolve_with_base) {
2408 /* resolve_with_base baseDst(r) propDst(r) property(id)
2410 Searches the scope chain for an object containing
2411 identifier property, and if one is found, writes it to
2412 register srcDst, and the retrieved property value to register
2413 propDst. If the property is not found, raises an exception.
2415 This is more efficient than doing resolve_base followed by
2416 resolve, or resolve_base followed by get_by_id, as it
2417 avoids duplicate hash lookups.
2419 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, exceptionValue)))
2425 BEGIN_OPCODE(op_resolve_func) {
2426 /* resolve_func baseDst(r) funcDst(r) property(id)
2428 Searches the scope chain for an object containing
2429 identifier property, and if one is found, writes the
2430 appropriate object to use as "this" when calling its
2431 properties to register baseDst; and the retrieved property
2432 value to register propDst. If the property is not found,
2433 raises an exception.
2435 This differs from resolve_with_base, because the
2436 global this value will be substituted for activations or
2437 the global object, which is the right behavior for function
2438 calls but not for other property lookup.
2440 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, exceptionValue)))
2446 BEGIN_OPCODE(op_get_by_id) {
2447 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2449 Generic property access: Gets the property named by identifier
2450 property from the value base, and puts the result in register dst.
2452 int dst = vPC[1].u.operand;
2453 int base = vPC[2].u.operand;
2454 int property = vPC[3].u.operand;
2456 CodeBlock* codeBlock = this->codeBlock(r);
2457 Identifier& ident = codeBlock->identifiers[property];
2458 JSValue* baseValue = r[base].jsValue(exec);
2459 PropertySlot slot(baseValue);
2460 JSValue* result = baseValue->get(exec, ident, slot);
2461 VM_CHECK_EXCEPTION();
2463 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2469 BEGIN_OPCODE(op_get_by_id_self) {
2470 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2472 Cached property access: Attempts to get a cached property from the
2473 value base. If the cache misses, op_get_by_id_self reverts to
2476 int base = vPC[2].u.operand;
2477 JSValue* baseValue = r[base].jsValue(exec);
2479 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2480 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2481 StructureID* structureID = vPC[4].u.structureID;
2483 if (LIKELY(baseCell->structureID() == structureID)) {
2484 ASSERT(baseCell->isObject());
2485 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2486 int dst = vPC[1].u.operand;
2487 int offset = vPC[5].u.operand;
2489 ASSERT(baseObject->get(exec, codeBlock(r)->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2490 r[dst] = baseObject->getDirectOffset(offset);
2497 uncacheGetByID(codeBlock(r), vPC);
2500 BEGIN_OPCODE(op_get_by_id_proto) {
2501 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2503 Cached property access: Attempts to get a cached property from the
2504 value base's prototype. If the cache misses, op_get_by_id_proto
2505 reverts to op_get_by_id.
2507 int base = vPC[2].u.operand;
2508 JSValue* baseValue = r[base].jsValue(exec);
2510 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2511 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2512 StructureID* structureID = vPC[4].u.structureID;
2514 if (LIKELY(baseCell->structureID() == structureID)) {
2515 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2516 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2517 StructureID* protoStructureID = vPC[5].u.structureID;
2519 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2520 int dst = vPC[1].u.operand;
2521 int offset = vPC[6].u.operand;
2523 ASSERT(protoObject->get(exec, codeBlock(r)->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2524 r[dst] = protoObject->getDirectOffset(offset);
2532 uncacheGetByID(codeBlock(r), vPC);
2535 BEGIN_OPCODE(op_get_by_id_chain) {
2536 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2538 Cached property access: Attempts to get a cached property from the
2539 value base's prototype chain. If the cache misses, op_get_by_id_chain
2540 reverts to op_get_by_id.
2542 int base = vPC[2].u.operand;
2543 JSValue* baseValue = r[base].jsValue(exec);
2545 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2546 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2547 StructureID* structureID = vPC[4].u.structureID;
2549 if (LIKELY(baseCell->structureID() == structureID)) {
2550 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2551 size_t count = vPC[6].u.operand;
2552 RefPtr<StructureID>* end = it + count;
2554 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2556 baseObject = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2557 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2561 int dst = vPC[1].u.operand;
2562 int offset = vPC[7].u.operand;
2564 ASSERT(baseObject->get(exec, codeBlock(r)->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2565 r[dst] = baseObject->getDirectOffset(offset);
2574 uncacheGetByID(codeBlock(r), vPC);
2577 BEGIN_OPCODE(op_get_by_id_generic) {
2578 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2580 Generic property access: Gets the property named by identifier
2581 property from the value base, and puts the result in register dst.
2583 int dst = vPC[1].u.operand;
2584 int base = vPC[2].u.operand;
2585 int property = vPC[3].u.operand;
2587 Identifier& ident = codeBlock(r)->identifiers[property];
2588 JSValue* baseValue = r[base].jsValue(exec);
2589 PropertySlot slot(baseValue);
2590 JSValue* result = baseValue->get(exec, ident, slot);
2591 VM_CHECK_EXCEPTION();
2597 BEGIN_OPCODE(op_get_array_length) {
2598 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2600 Cached property access: Gets the length of the array in register base,
2601 and puts the result in register dst. If register base does not hold
2602 an array, op_get_array_length reverts to op_get_by_id.
2605 int base = vPC[2].u.operand;
2606 JSValue* baseValue = r[base].jsValue(exec);
2607 if (LIKELY(isJSArray(baseValue))) {
2608 int dst = vPC[1].u.operand;
2609 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2614 uncacheGetByID(codeBlock(r), vPC);
2617 BEGIN_OPCODE(op_get_string_length) {
2618 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2620 Cached property access: Gets the length of the string in register base,
2621 and puts the result in register dst. If register base does not hold
2622 a string, op_get_string_length reverts to op_get_by_id.
2625 int base = vPC[2].u.operand;
2626 JSValue* baseValue = r[base].jsValue(exec);
2627 if (LIKELY(isJSString(baseValue))) {
2628 int dst = vPC[1].u.operand;
2629 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2634 uncacheGetByID(codeBlock(r), vPC);
2637 BEGIN_OPCODE(op_put_by_id) {
2638 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2640 Generic property access: Sets the property named by identifier
2641 property, belonging to register base, to register value.
2643 Unlike many opcodes, this one does not write any output to
2647 int base = vPC[1].u.operand;
2648 int property = vPC[2].u.operand;
2649 int value = vPC[3].u.operand;
2651 CodeBlock* codeBlock = this->codeBlock(r);
2652 JSValue* baseValue = r[base].jsValue(exec);
2653 Identifier& ident = codeBlock->identifiers[property];
2654 PutPropertySlot slot;
2655 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2656 VM_CHECK_EXCEPTION();
2658 tryCachePutByID(exec, codeBlock, vPC, baseValue, slot);
2663 BEGIN_OPCODE(op_put_by_id_transition) {
2664 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2666 Cached property access: Attempts to set a new property with a cached transition
2667 property named by identifier property, belonging to register base,
2668 to register value. If the cache misses, op_put_by_id_transition
2669 reverts to op_put_by_id_generic.
2671 Unlike many opcodes, this one does not write any output to
2674 int base = vPC[1].u.operand;
2675 JSValue* baseValue = r[base].jsValue(exec);
2677 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2678 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2679 StructureID* oldStructureID = vPC[4].u.structureID;
2680 StructureID* newStructureID = vPC[5].u.structureID;
2682 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2683 ASSERT(baseCell->isObject());
2684 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2686 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2688 JSObject* proto = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2689 while (!proto->isNull()) {
2690 if (UNLIKELY(proto->structureID() != (*it).get())) {
2691 uncachePutByID(codeBlock(r), vPC);
2695 proto = static_cast<JSObject*>(proto->structureID()->prototypeForLookup(exec));
2698 baseObject->transitionTo(newStructureID);
2699 if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
2700 baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
2702 int value = vPC[3].u.operand;
2703 unsigned offset = vPC[7].u.operand;
2704 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock(r)->identifiers[vPC[2].u.operand])) == offset);
2705 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2712 uncachePutByID(codeBlock(r), vPC);
2715 BEGIN_OPCODE(op_put_by_id_replace) {
2716 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2718 Cached property access: Attempts to set a pre-existing, cached
2719 property named by identifier property, belonging to register base,
2720 to register value. If the cache misses, op_put_by_id_replace
2721 reverts to op_put_by_id.
2723 Unlike many opcodes, this one does not write any output to
2726 int base = vPC[1].u.operand;
2727 JSValue* baseValue = r[base].jsValue(exec);
2729 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2730 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2731 StructureID* structureID = vPC[4].u.structureID;
2733 if (LIKELY(baseCell->structureID() == structureID)) {
2734 ASSERT(baseCell->isObject());
2735 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2736 int value = vPC[3].u.operand;
2737 unsigned offset = vPC[5].u.operand;
2739 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock(r)->identifiers[vPC[2].u.operand])) == offset);
2740 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2747 uncachePutByID(codeBlock(r), vPC);
2750 BEGIN_OPCODE(op_put_by_id_generic) {
2751 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2753 Generic property access: Sets the property named by identifier
2754 property, belonging to register base, to register value.
2756 Unlike many opcodes, this one does not write any output to
2759 int base = vPC[1].u.operand;
2760 int property = vPC[2].u.operand;
2761 int value = vPC[3].u.operand;
2763 JSValue* baseValue = r[base].jsValue(exec);
2764 Identifier& ident = codeBlock(r)->identifiers[property];
2765 PutPropertySlot slot;
2766 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2767 VM_CHECK_EXCEPTION();
2772 BEGIN_OPCODE(op_del_by_id) {
2773 /* del_by_id dst(r) base(r) property(id)
2775 Converts register base to Object, deletes the property
2776 named by identifier property from the object, and writes a
2777 boolean indicating success (if true) or failure (if false)
2780 int dst = (++vPC)->u.operand;
2781 int base = (++vPC)->u.operand;
2782 int property = (++vPC)->u.operand;
2784 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2785 Identifier& ident = codeBlock(r)->identifiers[property];
2786 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2787 VM_CHECK_EXCEPTION();
2792 BEGIN_OPCODE(op_get_by_val) {
2793 /* get_by_val dst(r) base(r) property(r)
2795 Converts register base to Object, gets the property named
2796 by register property from the object, and puts the result
2797 in register dst. property is nominally converted to string
2798 but numbers are treated more efficiently.
2800 int dst = (++vPC)->u.operand;
2801 int base = (++vPC)->u.operand;
2802 int property = (++vPC)->u.operand;
2804 JSValue* baseValue = r[base].jsValue(exec);
2805 JSValue* subscript = r[property].jsValue(exec);
2810 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2811 if (LIKELY(isUInt32)) {
2812 if (isJSArray(baseValue)) {
2813 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2814 if (jsArray->canGetIndex(i))
2815 result = jsArray->getIndex(i);
2817 result = jsArray->JSArray::get(exec, i);
2818 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2819 result = static_cast<JSString*>(baseValue)->getIndex(&exec->globalData(), i);
2821 result = baseValue->get(exec, i);
2823 Identifier property(exec, subscript->toString(exec));
2824 result = baseValue->get(exec, property);
2827 VM_CHECK_EXCEPTION();
2832 BEGIN_OPCODE(op_put_by_val) {
2833 /* put_by_val base(r) property(r) value(r)
2835 Sets register value on register base as the property named
2836 by register property. Base is converted to object
2837 first. register property is nominally converted to string
2838 but numbers are treated more efficiently.
2840 Unlike many opcodes, this one does not write any output to
2843 int base = (++vPC)->u.operand;
2844 int property = (++vPC)->u.operand;
2845 int value = (++vPC)->u.operand;
2847 JSValue* baseValue = r[base].jsValue(exec);
2848 JSValue* subscript = r[property].jsValue(exec);
2852 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2853 if (LIKELY(isUInt32)) {
2854 if (isJSArray(baseValue)) {
2855 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2856 if (jsArray->canSetIndex(i))
2857 jsArray->setIndex(i, r[value].jsValue(exec));
2859 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2861 baseValue->put(exec, i, r[value].jsValue(exec));
2863 Identifier property(exec, subscript->toString(exec));
2864 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2865 PutPropertySlot slot;
2866 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2870 VM_CHECK_EXCEPTION();
2874 BEGIN_OPCODE(op_del_by_val) {
2875 /* del_by_val dst(r) base(r) property(r)
2877 Converts register base to Object, deletes the property
2878 named by register property from the object, and writes a
2879 boolean indicating success (if true) or failure (if false)
2882 int dst = (++vPC)->u.operand;
2883 int base = (++vPC)->u.operand;
2884 int property = (++vPC)->u.operand;
2886 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2888 JSValue* subscript = r[property].jsValue(exec);
2891 if (subscript->getUInt32(i))
2892 result = jsBoolean(baseObj->deleteProperty(exec, i));
2894 VM_CHECK_EXCEPTION();
2895 Identifier property(exec, subscript->toString(exec));
2896 VM_CHECK_EXCEPTION();
2897 result = jsBoolean(baseObj->deleteProperty(exec, property));
2900 VM_CHECK_EXCEPTION();
2905 BEGIN_OPCODE(op_put_by_index) {
2906 /* put_by_index base(r) property(n) value(r)
2908 Sets register value on register base as the property named
2909 by the immediate number property. Base is converted to
2912 Unlike many opcodes, this one does not write any output to
2915 This opcode is mainly used to initialize array literals.
2917 int base = (++vPC)->u.operand;
2918 unsigned property = (++vPC)->u.operand;
2919 int value = (++vPC)->u.operand;
2921 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2926 BEGIN_OPCODE(op_loop) {
2927 /* loop target(offset)
2929 Jumps unconditionally to offset target from the current
2932 Additionally this loop instruction may terminate JS execution is
2933 the JS timeout is reached.
2935 #if DUMP_OPCODE_STATS
2936 OpcodeStats::resetLastInstruction();
2938 int target = (++vPC)->u.operand;
2939 CHECK_FOR_TIMEOUT();
2943 BEGIN_OPCODE(op_jmp) {
2944 /* jmp target(offset)
2946 Jumps unconditionally to offset target from the current
2949 #if DUMP_OPCODE_STATS
2950 OpcodeStats::resetLastInstruction();
2952 int target = (++vPC)->u.operand;
2957 BEGIN_OPCODE(op_loop_if_true) {
2958 /* loop_if_true cond(r) target(offset)
2960 Jumps to offset target from the current instruction, if and
2961 only if register cond converts to boolean as true.
2963 Additionally this loop instruction may terminate JS execution is
2964 the JS timeout is reached.
2966 int cond = (++vPC)->u.operand;
2967 int target = (++vPC)->u.operand;
2968 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2970 CHECK_FOR_TIMEOUT();
2977 BEGIN_OPCODE(op_jtrue) {
2978 /* jtrue cond(r) target(offset)
2980 Jumps to offset target from the current instruction, if and
2981 only if register cond converts to boolean as true.
2983 int cond = (++vPC)->u.operand;
2984 int target = (++vPC)->u.operand;
2985 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2993 BEGIN_OPCODE(op_jfalse) {
2994 /* jfalse cond(r) target(offset)
2996 Jumps to offset target from the current instruction, if and
2997 only if register cond converts to boolean as false.
2999 int cond = (++vPC)->u.operand;
3000 int target = (++vPC)->u.operand;
3001 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
3009 BEGIN_OPCODE(op_loop_if_less) {
3010 /* loop_if_less src1(r) src2(r) target(offset)
3012 Checks whether register src1 is less than register src2, as
3013 with the ECMAScript '<' operator, and then jumps to offset
3014 target from the current instruction, if and only if the
3015 result of the comparison is true.
3017 Additionally this loop instruction may terminate JS execution is
3018 the JS timeout is reached.
3020 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3021 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3022 int target = (++vPC)->u.operand;
3024 bool result = jsLess(exec, src1, src2);
3025 VM_CHECK_EXCEPTION();
3029 CHECK_FOR_TIMEOUT();
3036 BEGIN_OPCODE(op_loop_if_lesseq) {
3037 /* loop_if_lesseq src1(r) src2(r) target(offset)
3039 Checks whether register src1 is less than or equal to register
3040 src2, as with the ECMAScript '<=' operator, and then jumps to
3041 offset target from the current instruction, if and only if the
3042 result of the comparison is true.
3044 Additionally this loop instruction may terminate JS execution is
3045 the JS timeout is reached.
3047 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3048 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3049 int target = (++vPC)->u.operand;
3051 bool result = jsLessEq(exec, src1, src2);
3052 VM_CHECK_EXCEPTION();
3056 CHECK_FOR_TIMEOUT();
3063 BEGIN_OPCODE(op_jnless) {
3064 /* jnless src1(r) src2(r) target(offset)
3066 Checks whether register src1 is less than register src2, as
3067 with the ECMAScript '<' operator, and then jumps to offset
3068 target from the current instruction, if and only if the
3069 result of the comparison is false.
3071 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3072 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3073 int target = (++vPC)->u.operand;
3075 bool result = jsLess(exec, src1, src2);
3076 VM_CHECK_EXCEPTION();
3086 BEGIN_OPCODE(op_switch_imm) {
3087 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3089 Performs a range checked switch on the scrutinee value, using
3090 the tableIndex-th immediate switch jump table. If the scrutinee value
3091 is an immediate number in the range covered by the referenced jump
3092 table, and the value at jumpTable[scrutinee value] is non-zero, then
3093 that value is used as the jump offset, otherwise defaultOffset is used.
3095 int tableIndex = (++vPC)->u.operand;
3096 int defaultOffset = (++vPC)->u.operand;
3097 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3098 if (!JSImmediate::isNumber(scrutinee))
3099 vPC += defaultOffset;
3101 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3102 vPC += codeBlock(r)->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
3106 BEGIN_OPCODE(op_switch_char) {
3107 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3109 Performs a range checked switch on the scrutinee value, using
3110 the tableIndex-th character switch jump table. If the scrutinee value
3111 is a single character string in the range covered by the referenced jump
3112 table, and the value at jumpTable[scrutinee value] is non-zero, then
3113 that value is used as the jump offset, otherwise defaultOffset is used.
3115 int tableIndex = (++vPC)->u.operand;
3116 int defaultOffset = (++vPC)->u.operand;
3117 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3118 if (!scrutinee->isString())
3119 vPC += defaultOffset;
3121 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
3122 if (value->size() != 1)
3123 vPC += defaultOffset;
3125 vPC += codeBlock(r)->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
3129 BEGIN_OPCODE(op_switch_string) {
3130 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3132 Performs a sparse hashmap based switch on the value in the scrutinee
3133 register, using the tableIndex-th string switch jump table. If the
3134 scrutinee value is a string that exists as a key in the referenced
3135 jump table, then the value associated with the string is used as the
3136 jump offset, otherwise defaultOffset is used.
3138 int tableIndex = (++vPC)->u.operand;
3139 int defaultOffset = (++vPC)->u.operand;
3140 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3141 if (!scrutinee->isString())
3142 vPC += defaultOffset;
3144 vPC += codeBlock(r)->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
3147 BEGIN_OPCODE(op_new_func) {
3148 /* new_func dst(r) func(f)
3150 Constructs a new Function instance from function func and
3151 the current scope chain using the original Function
3152 constructor, using the rules for function declarations, and
3153 puts the result in register dst.
3155 int dst = (++vPC)->u.operand;
3156 int func = (++vPC)->u.operand;
3158 r[dst] = codeBlock(r)->functions[func]->makeFunction(exec, scopeChain(r));
3163 BEGIN_OPCODE(op_new_func_exp) {
3164 /* new_func_exp dst(r) func(f)
3166 Constructs a new Function instance from function func and
3167 the current scope chain using the original Function
3168 constructor, using the rules for function expressions, and
3169 puts the result in register dst.
3171 int dst = (++vPC)->u.operand;
3172 int func = (++vPC)->u.operand;
3174 r[dst] = codeBlock(r)->functionExpressions[func]->makeFunction(exec, scopeChain(r));
3179 BEGIN_OPCODE(op_call_eval) {
3180 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3182 Call a function named "eval" with no explicit "this" value
3183 (which may therefore be the eval operator). If register
3184 thisVal is the global object, and register func contains
3185 that global object's original global eval function, then
3186 perform the eval operator in local scope (interpreting
3187 the argument registers as for the "call"
3188 opcode). Otherwise, act exactly as the "call" opcode would.
3191 int dst = (++vPC)->u.operand;
3192 int func = (++vPC)->u.operand;
3193 int thisVal = (++vPC)->u.operand;
3194 int firstArg = (++vPC)->u.operand;
3195 int argCount = (++vPC)->u.operand;
3196 ++vPC; // registerOffset
3198 JSValue* funcVal = r[func].jsValue(exec);
3199 JSValue* baseVal = r[thisVal].jsValue(exec);
3201 ScopeChainNode* scopeChain = this->scopeChain(r);
3202 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
3203 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock(r)->thisRegister].jsValue(exec));
3204 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
3214 // We didn't find the blessed version of eval, so reset vPC and process
3215 // this instruction as a normal function call, supplying the proper 'this'
3218 r[thisVal] = baseVal->toThisObject(exec);
3220 #if HAVE(COMPUTED_GOTO)
3221 // Hack around gcc performance quirk by performing an indirect goto
3222 // in order to set the vPC -- attempting to do so directly results in a
3223 // significant regression.
3224 goto *op_call_indirect; // indirect goto -> op_call
3226 // fall through to op_call
3228 BEGIN_OPCODE(op_call) {
3229 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n) registerOffset(n)
3231 Perform a function call. Specifically, call register func
3232 with a "this" value of register thisVal, and put the result
3235 The arguments start at register firstArg and go up to
3236 argCount, but the "this" value is considered an implicit
3237 first argument, so the argCount should be one greater than
3238 the number of explicit arguments passed, and the register
3239 after firstArg should contain the actual first
3240 argument. This opcode will copy from the thisVal register
3241 to the firstArg register, unless the register index of
3242 thisVal is the special missing this object marker, which is
3243 2^31-1; in that case, the global object will be used as the
3246 If func is a native code function, then this opcode calls
3247 it and returns the value immediately.
3249 But if it is a JS function, then the current scope chain
3250 and code block is set to the function's, and we slide the
3251 register window so that the arguments would form the first
3252 few local registers of the called function's register
3253 window. In addition, a call frame header is written
3254 immediately before the arguments; see the call frame
3255 documentation for an explanation of how many registers a
3256 call frame takes and what they contain. That many registers
3257 before the firstArg register will be overwritten by the
3258 call. In addition, any registers higher than firstArg +
3259 argCount may be overwritten. Once this setup is complete,
3260 execution continues from the called function's first
3261 argument, and does not return until a "ret" opcode is
3265 int dst = (++vPC)->u.operand;
3266 int func = (++vPC)->u.operand;
3267 int thisVal = (++vPC)->u.operand;
3268 int firstArg = (++vPC)->u.operand;
3269 int argCount = (++vPC)->u.operand;
3270 int registerOffset = (++vPC)->u.operand;
3272 JSValue* v = r[func].jsValue(exec);
3275 CallType callType = v->getCallData(callData);
3277 if (callType == CallTypeJS) {
3278 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3279 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3280 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3282 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3284 Register* savedR = r;
3286 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, r, registerOffset, argCount, exceptionValue);
3287 exec->m_callFrame = r;
3288 if (UNLIKELY(exceptionValue != 0))
3291 initializeCallFrame(r, newCodeBlock, vPC + 1, callDataScopeChain, savedR, dst, argCount, v);
3293 if (*enabledProfilerReference)
3294 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3296 vPC = newCodeBlock->instructions.begin();
3298 #if DUMP_OPCODE_STATS
3299 OpcodeStats::resetLastInstruction();
3305 if (callType == CallTypeHost) {
3306 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3307 ArgList args(r + firstArg + 1, argCount - 1);
3309 ScopeChainNode* scopeChain = this->scopeChain(r);
3310 initializeCallFrame(r + registerOffset, 0, vPC + 1, scopeChain, r, dst, argCount, v);
3311 exec->m_callFrame = r + registerOffset;
3313 if (*enabledProfilerReference)
3314 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3316 MACHINE_SAMPLING_callingHostFunction();
3318 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
3319 exec->m_callFrame = r;
3320 VM_CHECK_EXCEPTION();
3322 r[dst] = returnValue;
3324 if (*enabledProfilerReference)
3325 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3331 ASSERT(callType == CallTypeNone);
3333 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock(r));
3336 BEGIN_OPCODE(op_ret) {
3339 Return register result as the return value of the current
3340 function call, writing it into the caller's expected return
3341 value register. In addition, unwind one call frame and
3342 restore the scope chain, code block instruction pointer and
3343 register base to those of the calling function.
3346 int result = (++vPC)->u.operand;
3348 // If this call frame created an activation or an 'arguments' object, tear it off.
3349 if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
3350 ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
3351 ASSERT(activation->isObject(&JSActivation::info));
3352 activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
3353 } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
3354 ASSERT(arguments->isObject(&Arguments::info));
3355 arguments->copyRegisters();
3358 if (*enabledProfilerReference)
3359 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
3361 if (codeBlock(r)->needsFullScopeChain)
3362 scopeChain(r)->deref();
3364 JSValue* returnValue = r[result].jsValue(exec);
3366 vPC = r[RegisterFile::ReturnPC].vPC();
3367 int dst = r[RegisterFile::ReturnValueRegister].i();
3368 r = r[RegisterFile::CallerRegisters].r();
3369 exec->m_callFrame = r;
3371 if (isHostCallFrame(r))
3374 r[dst] = returnValue;
3378 BEGIN_OPCODE(op_enter) {
3380 CodeBlock* codeBlock = this->codeBlock(r);
3382 for (size_t count = codeBlock->numVars; i < count; ++i)
3383 r[i] = jsUndefined();
3385 for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
3386 r[i] = codeBlock->constantRegisters[j];
3391 BEGIN_OPCODE(op_enter_with_activation) {
3393 CodeBlock* codeBlock = this->codeBlock(r);
3395 for (size_t count = codeBlock->numVars; i < count; ++i)
3396 r[i] = jsUndefined();
3398 for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
3399 r[i] = codeBlock->constantRegisters[j];
3401 JSActivation* activation = new (exec) JSActivation(exec, static_cast<FunctionBodyNode*>(codeBlock->ownerNode), r);
3402 r[RegisterFile::OptionalCalleeActivation] = activation;
3403 r[RegisterFile::ScopeChain] = scopeChain(r)->copy()->push(activation);
3408 BEGIN_OPCODE(op_convert_this) {
3409 int thisRegister = (++vPC)->u.operand;
3410 JSValue* thisVal = r[thisRegister].getJSValue();
3411 if (thisVal->needsThisConversion())
3412 r[thisRegister] = thisVal->toThisObject(exec);
3417 BEGIN_OPCODE(op_init_arguments) {
3418 JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
3419 Arguments* arguments;
3421 ASSERT(activation->isObject(&JSActivation::info));
3422 arguments = new (exec) Arguments(exec, static_cast<JSActivation*>(activation));
3424 arguments = new (exec) Arguments(exec, r);
3425 r[RegisterFile::OptionalCalleeArguments] = arguments;
3426 r[RegisterFile::ArgumentsRegister] = arguments;
3431 BEGIN_OPCODE(op_construct) {
3432 /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n) registerOffset(n)
3434 Invoke register "constr" as a constructor. For JS
3435 functions, the calling convention is exactly as for the
3436 "call" opcode, except that the "this" value is a newly
3437 created Object. For native constructors, a null "this"
3438 value is passed. In either case, the firstArg and argCount
3439 registers are interpreted as for the "call" opcode.
3441 Register constrProto must contain the prototype property of
3442 register constsr. This is to enable polymorphic inline
3443 caching of this lookup.
3446 int dst = (++vPC)->u.operand;
3447 int constr = (++vPC)->u.operand;
3448 int constrProto = (++vPC)->u.operand;
3449 int firstArg = (++vPC)->u.operand;
3450 int argCount = (++vPC)->u.operand;
3451 int registerOffset = (++vPC)->u.operand;
3453 JSValue* v = r[constr].jsValue(exec);
3455 ConstructData constructData;
3456 ConstructType constructType = v->getConstructData(constructData);
3458 if (constructType == ConstructTypeJS) {
3459 if (*enabledProfilerReference)
3460 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3462 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3463 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3464 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3466 StructureID* structure;
3467 JSValue* prototype = r[constrProto].jsValue(exec);
3468 if (prototype->isObject())
3469 structure = static_cast<JSObject*>(prototype)->inheritorID();
3471 structure = callDataScopeChain->globalObject()->emptyObjectStructure();
3472 JSObject* newObject = new (exec) JSObject(structure);
3474 r[firstArg] = newObject; // "this" value
3476 Register* savedR = r;
3478 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, r, registerOffset, argCount, exceptionValue);
3479 exec->m_callFrame = r;
3480 if (UNLIKELY(exceptionValue != 0))
3483 initializeCallFrame(r, newCodeBlock, vPC + 1, callDataScopeChain, savedR, dst, argCount, v);
3485 if (*enabledProfilerReference)
3486 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3488 vPC = newCodeBlock->instructions.begin();
3490 #if DUMP_OPCODE_STATS
3491 OpcodeStats::resetLastInstruction();
3497 if (constructType == ConstructTypeHost) {
3498 ArgList args(r + firstArg + 1, argCount - 1);
3500 ScopeChainNode* scopeChain = this->scopeChain(r);
3501 initializeCallFrame(r + registerOffset, 0, vPC + 1, scopeChain, r, dst, argCount, v);
3502 exec->m_callFrame = r + registerOffset;
3504 if (*enabledProfilerReference)
3505 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3507 MACHINE_SAMPLING_callingHostFunction();
3509 JSValue* returnValue = constructData.native.function(exec, static_cast<JSObject*>(v), args);
3510 exec->m_callFrame = r;
3512 VM_CHECK_EXCEPTION();
3513 r[dst] = returnValue;