2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "BatchedTransitionOptimizer.h"
34 #include "CodeBlock.h"
35 #include "DebuggerCallFrame.h"
36 #include "ExceptionHelpers.h"
37 #include "ExecState.h"
38 #include "GlobalEvalFunction.h"
39 #include "JSActivation.h"
41 #include "JSFunction.h"
42 #include "JSNotAnObject.h"
43 #include "JSPropertyNameIterator.h"
44 #include "JSStaticScopeObject.h"
46 #include "ObjectPrototype.h"
49 #include "RegExpObject.h"
50 #include "RegExpPrototype.h"
52 #include "collector.h"
54 #include "operations.h"
55 #include "SamplingTool.h"
59 #include <mach/mach.h>
78 // Preferred number of milliseconds between each timeout check
79 static const int preferredScriptCheckTimeInterval = 1000;
81 #if HAVE(COMPUTED_GOTO)
82 static void* op_throw_end_indirect;
83 static void* op_call_indirect;
86 // Returns the depth of the scope chain within a given call frame.
87 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
89 if (!codeBlock->needsFullScopeChain)
92 ScopeChainIterator iter = sc.begin();
93 ScopeChainIterator end = sc.end();
94 while (!(*iter)->isActivationObject()) {
103 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
104 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
105 static bool fastIsNumber(JSValue* value, double& arg)
107 if (JSImmediate::isNumber(value))
108 arg = JSImmediate::getTruncatedInt32(value);
109 else if (Heap::isNumber(static_cast<JSCell*>(value)))
110 arg = static_cast<JSNumberCell*>(value)->value();
116 // FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
117 static bool fastToInt32(JSValue* value, int32_t& arg)
119 if (JSImmediate::isNumber(value))
120 arg = JSImmediate::getTruncatedInt32(value);
121 else if (Heap::isNumber(static_cast<JSCell*>(value)))
122 arg = static_cast<JSNumberCell*>(value)->toInt32();
128 static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
130 if (JSImmediate::isNumber(value)) {
131 if (JSImmediate::getTruncatedUInt32(value, arg))
134 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
136 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
137 arg = static_cast<JSNumberCell*>(value)->toUInt32();
143 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
145 if (JSImmediate::areBothImmediateNumbers(v1, v2))
146 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
150 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
155 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
156 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
158 if (wasNotString1 | wasNotString2)
161 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
164 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
166 if (JSImmediate::areBothImmediateNumbers(v1, v2))
167 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
171 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
176 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
177 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
179 if (wasNotString1 | wasNotString2)
182 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
185 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
187 // exception for the Date exception in defaultValue()
188 JSValue* p1 = v1->toPrimitive(exec);
189 JSValue* p2 = v2->toPrimitive(exec);
191 if (p1->isString() || p2->isString()) {
192 RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
194 return throwOutOfMemoryError(exec);
195 return jsString(exec, value.release());
198 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
201 // Fast-path choices here are based on frequency data from SunSpider:
202 // <times> Add case: <t1> <t2>
203 // ---------------------------
204 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
205 // 247412 Add case: 5 5
206 // 20900 Add case: 5 6
207 // 13962 Add case: 5 3
208 // 4000 Add case: 3 5
210 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
214 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
215 return jsNumber(exec, left + right);
217 if (v1->isString() && v2->isString()) {
218 RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
220 return throwOutOfMemoryError(exec);
221 return jsString(exec, value.release());
224 // All other cases are pretty uncommon
225 return jsAddSlowCase(exec, v1, v2);
228 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
230 if (v->isUndefined())
231 return jsNontrivialString(exec, "undefined");
233 return jsNontrivialString(exec, "boolean");
235 return jsNontrivialString(exec, "number");
237 return jsNontrivialString(exec, "string");
239 // Return "undefined" for objects that should be treated
240 // as null when doing comparisons.
241 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
242 return jsNontrivialString(exec, "undefined");
244 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
245 return jsNontrivialString(exec, "function");
247 return jsNontrivialString(exec, "object");
250 static bool jsIsObjectType(JSValue* v)
252 if (JSImmediate::isImmediate(v))
255 JSType type = static_cast<JSCell*>(v)->structureID()->type();
256 if (type == NumberType || type == StringType)
258 if (type == ObjectType) {
259 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
262 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
268 static bool jsIsFunctionType(JSValue* v)
272 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
278 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
280 int dst = (vPC + 1)->u.operand;
281 int property = (vPC + 2)->u.operand;
283 ScopeChainIterator iter = scopeChain->begin();
284 ScopeChainIterator end = scopeChain->end();
287 Identifier& ident = codeBlock->identifiers[property];
290 PropertySlot slot(o);
291 if (o->getPropertySlot(exec, ident, slot)) {
292 JSValue* result = slot.getValue(exec, ident);
293 exceptionValue = exec->exception();
299 } while (++iter != end);
300 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
304 static bool NEVER_INLINE resolveSkip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
306 int dst = (vPC + 1)->u.operand;
307 int property = (vPC + 2)->u.operand;
308 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
310 ScopeChainIterator iter = scopeChain->begin();
311 ScopeChainIterator end = scopeChain->end();
317 Identifier& ident = codeBlock->identifiers[property];
320 PropertySlot slot(o);
321 if (o->getPropertySlot(exec, ident, slot)) {
322 JSValue* result = slot.getValue(exec, ident);
323 exceptionValue = exec->exception();
329 } while (++iter != end);
330 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
334 static bool NEVER_INLINE resolveGlobal(ExecState* exec, Instruction* vPC, Register* r, CodeBlock* codeBlock, JSValue*& exceptionValue)
336 int dst = (vPC + 1)->u.operand;
337 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
338 ASSERT(globalObject->isGlobalObject());
339 int property = (vPC + 3)->u.operand;
340 StructureID* structureID = (vPC + 4)->u.structureID;
341 int offset = (vPC + 5)->u.operand;
343 if (structureID == globalObject->structureID()) {
344 r[dst] = globalObject->getDirectOffset(offset);
348 Identifier& ident = codeBlock->identifiers[property];
349 PropertySlot slot(globalObject);
350 if (globalObject->getPropertySlot(exec, ident, slot)) {
351 JSValue* result = slot.getValue(exec, ident);
352 if (slot.isCacheable()) {
353 if (vPC[4].u.structureID)
354 vPC[4].u.structureID->deref();
355 globalObject->structureID()->ref();
356 vPC[4] = globalObject->structureID();
357 vPC[5] = slot.cachedOffset();
362 exceptionValue = exec->exception();
369 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
373 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
375 ScopeChainIterator iter = scopeChain->begin();
376 ScopeChainIterator next = iter;
378 ScopeChainIterator end = scopeChain->end();
385 if (next == end || base->getPropertySlot(exec, property, slot))
392 ASSERT_NOT_REACHED();
396 NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
398 int dst = (vPC + 1)->u.operand;
399 int property = (vPC + 2)->u.operand;
400 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
403 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
405 int baseDst = (vPC + 1)->u.operand;
406 int propDst = (vPC + 2)->u.operand;
407 int property = (vPC + 3)->u.operand;
409 ScopeChainIterator iter = scopeChain->begin();
410 ScopeChainIterator end = scopeChain->end();
412 // FIXME: add scopeDepthIsZero optimization
416 Identifier& ident = codeBlock->identifiers[property];
420 PropertySlot slot(base);
421 if (base->getPropertySlot(exec, ident, slot)) {
422 JSValue* result = slot.getValue(exec, ident);
423 exceptionValue = exec->exception();
431 } while (iter != end);
433 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
437 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
439 int baseDst = (vPC + 1)->u.operand;
440 int funcDst = (vPC + 2)->u.operand;
441 int property = (vPC + 3)->u.operand;
443 ScopeChainIterator iter = scopeChain->begin();
444 ScopeChainIterator end = scopeChain->end();
446 // FIXME: add scopeDepthIsZero optimization
450 Identifier& ident = codeBlock->identifiers[property];
454 PropertySlot slot(base);
455 if (base->getPropertySlot(exec, ident, slot)) {
456 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
457 // However, section 10.2.3 says that in the case where the value provided
458 // by the caller is null, the global object should be used. It also says
459 // that the section does not apply to internal functions, but for simplicity
460 // of implementation we use the global object anyway here. This guarantees
461 // that in host objects you always get a valid object for this.
462 // We also handle wrapper substitution for the global object at the same time.
463 JSObject* thisObj = base->toThisObject(exec);
464 JSValue* result = slot.getValue(exec, ident);
465 exceptionValue = exec->exception();
469 r[baseDst] = thisObj;
474 } while (iter != end);
476 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
480 ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, JSValue* function)
482 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
483 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
484 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
485 callFrame[RegisterFile::CallerRegisters] = r;
486 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
487 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
488 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
489 callFrame[RegisterFile::Callee] = function;
490 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
493 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
495 size_t registerOffset = argv + newCodeBlock->numLocals;
496 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
498 if (argc == newCodeBlock->numParameters) { // correct number of arguments
499 if (!registerFile->grow(size)) {
500 exceptionValue = createStackOverflowError(exec);
504 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
505 if (!registerFile->grow(size)) {
506 exceptionValue = createStackOverflowError(exec);
511 int omittedArgCount = newCodeBlock->numParameters - argc;
512 Register* endOfParams = r - newCodeBlock->numVars;
513 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
514 (*it) = jsUndefined();
515 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
516 int shift = argc + RegisterFile::CallFrameHeaderSize;
517 registerOffset += shift;
520 if (!registerFile->grow(size)) {
521 exceptionValue = createStackOverflowError(exec);
526 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
527 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
528 for ( ; it != end; ++it)
532 // initialize local variable slots
533 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
534 (*it) = jsUndefined();
536 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
537 r[i] = newCodeBlock->constantRegisters[i];
542 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
544 if (newCodeBlock->needsFullScopeChain) {
545 JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
546 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
548 return callDataScopeChain->copy()->push(activation);
551 return callDataScopeChain;
554 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
556 if (value->isObject())
558 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
562 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
565 return jsUndefined();
567 JSValue* program = r[argv + 1].jsValue(exec);
569 if (!program->isString())
572 Profiler** profiler = Profiler::enabledProfilerReference();
574 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
576 UString programSource = static_cast<JSString*>(program)->value();
578 RefPtr<EvalNode> evalNode = callingCodeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
582 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
585 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
593 , m_ctiArrayLengthTrampoline(0)
594 , m_ctiStringLengthTrampoline(0)
595 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
599 , m_timeAtLastCheckTimeout(0)
601 , m_timeoutCheckCount(0)
602 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
604 privateExecute(InitializeAndReturn);
606 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
607 void* storage = fastMalloc(sizeof(CollectorBlock));
609 JSArray* jsArray = new (storage) JSArray(StructureID::create(jsNull()));
610 m_jsArrayVptr = jsArray->vptr();
611 static_cast<JSCell*>(jsArray)->~JSCell();
613 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
614 m_jsStringVptr = jsString->vptr();
615 static_cast<JSCell*>(jsString)->~JSCell();
617 JSFunction* jsFunction = new (storage) JSFunction(StructureID::create(jsNull()));
618 m_jsFunctionVptr = jsFunction->vptr();
619 static_cast<JSCell*>(jsFunction)->~JSCell();
627 if (m_ctiArrayLengthTrampoline)
628 fastFree(m_ctiArrayLengthTrampoline);
629 if (m_ctiStringLengthTrampoline)
630 fastFree(m_ctiStringLengthTrampoline);
636 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
638 ScopeChain sc(scopeChain);
639 JSGlobalObject* globalObject = sc.globalObject();
640 codeBlock->dump(globalObject->globalExec());
641 dumpRegisters(codeBlock, registerFile, r);
644 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
646 printf("Register frame: \n\n");
647 printf("----------------------------------------------------\n");
648 printf(" use | address | value \n");
649 printf("----------------------------------------------------\n");
654 if (codeBlock->codeType == GlobalCode) {
655 it = registerFile->lastGlobal();
656 end = it + registerFile->numGlobals();
658 printf("[global var] | %10p | %10p \n", it, (*it).v());
661 printf("----------------------------------------------------\n");
664 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
665 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
666 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
667 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
668 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
669 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
670 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
671 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
672 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
673 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
674 printf("----------------------------------------------------\n");
676 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
677 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
680 printf("[param] | %10p | %10p \n", it, (*it).v());
684 printf("----------------------------------------------------\n");
686 if (codeBlock->codeType != GlobalCode) {
687 end = it + codeBlock->numVars;
690 printf("[var] | %10p | %10p \n", it, (*it).v());
693 printf("----------------------------------------------------\n");
697 end = it + codeBlock->numTemporaries;
700 printf("[temp] | %10p | %10p \n", it, (*it).v());
708 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
710 bool Machine::isOpcode(Opcode opcode)
712 #if HAVE(COMPUTED_GOTO)
713 return opcode != HashTraits<Opcode>::emptyValue()
714 && !HashTraits<Opcode>::isDeletedValue(opcode)
715 && m_opcodeIDTable.contains(opcode);
717 return opcode >= 0 && opcode <= op_end;
723 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
725 CodeBlock* oldCodeBlock = codeBlock;
726 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
728 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
729 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
730 if (callFrame[RegisterFile::Callee].jsValue(exec))
731 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
733 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
736 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
737 if (callFrame[RegisterFile::Callee].jsValue(exec))
738 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
740 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
743 if (oldCodeBlock->needsFullScopeChain)
746 // If this call frame created an activation, tear it off.
747 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
748 ASSERT(activation->isActivationObject());
749 activation->copyRegisters();
752 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
756 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
757 r = callFrame[RegisterFile::CallerRegisters].r();
758 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
759 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
764 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
766 // Set up the exception object
768 if (exceptionValue->isObject()) {
769 JSObject* exception = static_cast<JSObject*>(exceptionValue);
770 if (exception->isNotAnObjectErrorStub()) {
771 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
772 exceptionValue = exception;
774 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
775 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
776 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
777 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
778 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
779 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
784 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
785 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
787 // We only hit this path for error messages and throw statements, which don't have a specific failure position
788 // So we just give the full range of the error/throw statement.
789 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
790 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
792 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
793 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
794 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
797 if (exception->isWatchdogException()) {
798 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
799 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
806 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
807 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
808 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
811 // Calculate an exception handler vPC, unwinding call frames as necessary.
814 Instruction* handlerVPC;
816 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
817 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
821 // Now unwind the scope chain within the exception handler's call frame.
823 ScopeChain sc(scopeChain);
824 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
825 ASSERT(scopeDelta >= 0);
828 setScopeChain(exec, scopeChain, sc.node());
833 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
835 if (m_reentryDepth >= MaxReentryDepth) {
836 *exception = createStackOverflowError(exec);
840 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
842 size_t oldSize = m_registerFile.size();
843 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
844 if (!m_registerFile.grow(newSize)) {
845 *exception = createStackOverflowError(exec);
849 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
850 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
851 globalObject->copyGlobalsTo(m_registerFile);
853 Register* callFrame = m_registerFile.base() + oldSize;
855 // a 0 codeBlock indicates a built-in caller
856 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
858 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
859 r[codeBlock->thisRegister] = thisObj;
861 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
862 r[i] = codeBlock->constantRegisters[i];
864 if (codeBlock->needsFullScopeChain)
865 scopeChain = scopeChain->copy();
867 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
869 Profiler** profiler = Profiler::enabledProfilerReference();
871 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
875 if (!codeBlock->ctiCode)
876 CTI::compile(this, exec, codeBlock);
877 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
879 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
883 MACHINE_SAMPLING_privateExecuteReturned();
886 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
888 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
889 lastGlobalObject->copyGlobalsTo(m_registerFile);
891 m_registerFile.shrink(oldSize);
895 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
897 if (m_reentryDepth >= MaxReentryDepth) {
898 *exception = createStackOverflowError(exec);
902 int argv = RegisterFile::CallFrameHeaderSize;
903 int argc = args.size() + 1; // implicit "this" parameter
905 size_t oldSize = m_registerFile.size();
906 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
907 *exception = createStackOverflowError(exec);
911 Register* callFrame = m_registerFile.base() + oldSize;
913 // put args in place, including "this"
914 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
917 ArgList::const_iterator end = args.end();
918 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
921 // a 0 codeBlock indicates a built-in caller
922 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, function);
924 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
925 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
927 m_registerFile.shrink(oldSize);
931 scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r);
933 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
935 Profiler** profiler = Profiler::enabledProfilerReference();
937 (*profiler)->willExecute(exec, function);
941 if (!newCodeBlock->ctiCode)
942 CTI::compile(this, exec, newCodeBlock);
943 JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
945 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
949 MACHINE_SAMPLING_privateExecuteReturned();
951 m_registerFile.shrink(oldSize);
955 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
957 if (m_reentryDepth >= MaxReentryDepth) {
958 *exception = createStackOverflowError(exec);
962 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
964 JSVariableObject* variableObject;
965 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
967 if (node->object->isVariableObject()) {
968 variableObject = static_cast<JSVariableObject*>(node->object);
973 { // Scope for BatchedTransitionOptimizer
975 BatchedTransitionOptimizer optimizer(variableObject);
977 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
978 Node::VarStack::const_iterator varStackEnd = varStack.end();
979 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
980 const Identifier& ident = (*it).first;
981 if (!variableObject->hasProperty(exec, ident)) {
982 PutPropertySlot slot;
983 variableObject->put(exec, ident, jsUndefined(), slot);
987 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
988 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
989 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
990 PutPropertySlot slot;
991 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
996 size_t oldSize = m_registerFile.size();
997 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
998 if (!m_registerFile.grow(newSize)) {
999 *exception = createStackOverflowError(exec);
1003 Register* callFrame = m_registerFile.base() + registerOffset;
1005 // a 0 codeBlock indicates a built-in caller
1006 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
1008 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
1009 r[codeBlock->thisRegister] = thisObj;
1011 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
1012 r[i] = codeBlock->constantRegisters[i];
1014 if (codeBlock->needsFullScopeChain)
1015 scopeChain = scopeChain->copy();
1017 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
1019 Profiler** profiler = Profiler::enabledProfilerReference();
1021 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1025 if (!codeBlock->ctiCode)
1026 CTI::compile(this, exec, codeBlock);
1027 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
1029 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
1033 MACHINE_SAMPLING_privateExecuteReturned();
1036 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1038 m_registerFile.shrink(oldSize);
1042 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
1044 scopeChain = newScopeChain;
1045 exec->m_scopeChain = newScopeChain;
1048 NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
1050 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
1054 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
1056 switch (debugHookID) {
1057 case DidEnterCallFrame:
1058 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1060 case WillLeaveCallFrame:
1061 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1063 case WillExecuteStatement:
1064 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1066 case WillExecuteProgram:
1067 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1069 case DidExecuteProgram:
1070 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1072 case DidReachBreakpoint:
1073 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1078 void Machine::resetTimeoutCheck()
1080 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1081 m_timeAtLastCheckTimeout = 0;
1082 m_timeExecuting = 0;
1085 // Returns the time the current thread has spent executing, in milliseconds.
1086 static inline unsigned getCPUTime()
1088 #if PLATFORM(DARWIN)
1089 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1090 thread_basic_info_data_t info;
1092 // Get thread information
1093 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1095 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1096 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1099 #elif HAVE(SYS_TIME_H)
1100 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1102 gettimeofday(&tv, 0);
1103 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1105 QDateTime t = QDateTime::currentDateTime();
1106 return t.toTime_t() * 1000 + t.time().msec();
1107 #elif PLATFORM(WIN_OS)
1110 unsigned long long fileTimeAsLong;
1111 } userTime, kernelTime;
1113 // GetThreadTimes won't accept NULL arguments so we pass these even though
1114 // they're not used.
1115 FILETIME creationTime, exitTime;
1117 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1119 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1121 #error Platform does not have getCurrentTime function
1125 // We have to return a JSValue here, gcc seems to produce worse code if
1126 // we attempt to return a bool
1127 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1129 unsigned currentTime = getCPUTime();
1131 if (!m_timeAtLastCheckTimeout) {
1132 // Suspicious amount of looping in a script -- start timing it
1133 m_timeAtLastCheckTimeout = currentTime;
1137 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1142 m_timeExecuting += timeDiff;
1143 m_timeAtLastCheckTimeout = currentTime;
1145 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1146 // preferredScriptCheckTimeInterval
1147 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1148 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1149 // preferred script check time interval.
1150 if (m_ticksUntilNextTimeoutCheck == 0)
1151 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1153 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1154 if (globalObject->shouldInterruptScript())
1155 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1157 resetTimeoutCheck();
1163 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1165 int dst = (++vPC)->u.operand;
1166 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1167 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1168 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1170 return scopeChain->push(scope);
1173 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1175 JSValue* prototype = structureID->prototypeForLookup(exec);
1176 if (JSImmediate::isImmediate(prototype))
1178 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(prototype)->structureID());
1179 structureID->setCachedPrototypeChain(chain.release());
1180 return structureID->cachedPrototypeChain();
1183 NEVER_INLINE void Machine::tryCachePutByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1185 // Recursive invocation may already have specialized this instruction.
1186 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1189 if (JSImmediate::isImmediate(baseValue))
1192 // Uncacheable: give up.
1193 if (!slot.isCacheable()) {
1194 vPC[0] = getOpcode(op_put_by_id_generic);
1198 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1199 StructureID* structureID = baseCell->structureID();
1201 if (structureID->isDictionary()) {
1202 vPC[0] = getOpcode(op_put_by_id_generic);
1206 // Cache miss: record StructureID to compare against next time.
1207 StructureID* lastStructureID = vPC[4].u.structureID;
1208 if (structureID != lastStructureID) {
1209 // First miss: record StructureID to compare against next time.
1210 if (!lastStructureID) {
1211 vPC[4] = structureID;
1215 // Second miss: give up.
1216 vPC[0] = getOpcode(op_put_by_id_generic);
1220 // Cache hit: Specialize instruction and ref StructureIDs.
1222 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1223 if (baseCell != slot.base()) {
1224 vPC[0] = getOpcode(op_put_by_id_generic);
1228 // StructureID transition, cache transition info
1229 if (slot.type() == PutPropertySlot::NewProperty) {
1230 vPC[0] = getOpcode(op_put_by_id_transition);
1231 vPC[4] = structureID->previousID();
1232 vPC[5] = structureID;
1233 StructureIDChain* chain = structureID->cachedPrototypeChain();
1235 chain = cachePrototypeChain(exec, structureID);
1237 // This happens if someone has manually inserted null into the prototype chain
1238 vPC[0] = getOpcode(op_put_by_id_generic);
1243 vPC[7] = slot.cachedOffset();
1244 codeBlock->refStructureIDs(vPC);
1248 vPC[0] = getOpcode(op_put_by_id_replace);
1249 vPC[5] = slot.cachedOffset();
1250 codeBlock->refStructureIDs(vPC);
1253 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1255 codeBlock->derefStructureIDs(vPC);
1256 vPC[0] = getOpcode(op_put_by_id);
1260 NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1262 // Recursive invocation may already have specialized this instruction.
1263 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1266 // FIXME: Cache property access for immediates.
1267 if (JSImmediate::isImmediate(baseValue)) {
1268 vPC[0] = getOpcode(op_get_by_id_generic);
1272 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1273 vPC[0] = getOpcode(op_get_array_length);
1277 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1278 vPC[0] = getOpcode(op_get_string_length);
1282 // Uncacheable: give up.
1283 if (!slot.isCacheable()) {
1284 vPC[0] = getOpcode(op_get_by_id_generic);
1288 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1290 if (structureID->isDictionary()) {
1291 vPC[0] = getOpcode(op_get_by_id_generic);
1296 StructureID* lastStructureID = vPC[4].u.structureID;
1297 if (structureID != lastStructureID) {
1298 // First miss: record StructureID to compare against next time.
1299 if (!lastStructureID) {
1300 vPC[4] = structureID;
1304 // Second miss: give up.
1305 vPC[0] = getOpcode(op_get_by_id_generic);
1309 // Cache hit: Specialize instruction and ref StructureIDs.
1311 if (slot.slotBase() == baseValue) {
1312 vPC[0] = getOpcode(op_get_by_id_self);
1313 vPC[5] = slot.cachedOffset();
1315 codeBlock->refStructureIDs(vPC);
1319 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1320 ASSERT(slot.slotBase()->isObject());
1322 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1324 // Heavy access to a prototype is a good indication that it's not being
1325 // used as a dictionary.
1326 if (baseObject->structureID()->isDictionary()) {
1327 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1328 baseObject->setStructureID(transition.release());
1329 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1332 vPC[0] = getOpcode(op_get_by_id_proto);
1333 vPC[5] = baseObject->structureID();
1334 vPC[6] = slot.cachedOffset();
1336 codeBlock->refStructureIDs(vPC);
1341 JSObject* o = static_cast<JSObject*>(baseValue);
1342 while (slot.slotBase() != o) {
1343 JSValue* v = o->structureID()->prototypeForLookup(exec);
1345 // If we didn't find base in baseValue's prototype chain, then baseValue
1346 // must be a proxy for another object.
1348 vPC[0] = getOpcode(op_get_by_id_generic);
1352 o = static_cast<JSObject*>(v);
1354 // Heavy access to a prototype is a good indication that it's not being
1355 // used as a dictionary.
1356 if (o->structureID()->isDictionary()) {
1357 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1358 o->setStructureID(transition.release());
1359 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1365 StructureIDChain* chain = structureID->cachedPrototypeChain();
1367 chain = cachePrototypeChain(exec, structureID);
1370 vPC[0] = getOpcode(op_get_by_id_chain);
1371 vPC[4] = structureID;
1374 vPC[7] = slot.cachedOffset();
1375 codeBlock->refStructureIDs(vPC);
1378 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1380 codeBlock->derefStructureIDs(vPC);
1381 vPC[0] = getOpcode(op_get_by_id);
1385 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1387 // One-time initialization of our address tables. We have to put this code
1388 // here because our labels are only in scope inside this function.
1389 if (flag == InitializeAndReturn) {
1390 #if HAVE(COMPUTED_GOTO)
1391 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1392 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1395 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1396 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1397 #undef ADD_OPCODE_ID
1398 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1399 op_throw_end_indirect = &&op_throw_end;
1400 op_call_indirect = &&op_call;
1401 #endif // HAVE(COMPUTED_GOTO)
1406 // Currently with CTI enabled we never interpret functions
1407 ASSERT_NOT_REACHED();
1410 JSValue* exceptionValue = 0;
1411 Instruction* handlerVPC = 0;
1413 Register* registerBase = registerFile->base();
1414 Instruction* vPC = codeBlock->instructions.begin();
1415 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1416 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1418 #define VM_CHECK_EXCEPTION() \
1420 if (UNLIKELY(exec->hadException())) { \
1421 exceptionValue = exec->exception(); \
1426 #if DUMP_OPCODE_STATS
1427 OpcodeStats::resetLastInstruction();
1430 #define CHECK_FOR_TIMEOUT() \
1431 if (!--tickCount) { \
1432 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1434 tickCount = m_ticksUntilNextTimeoutCheck; \
1437 #if HAVE(COMPUTED_GOTO)
1438 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1439 #if DUMP_OPCODE_STATS
1440 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1442 #define BEGIN_OPCODE(opcode) opcode:
1446 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1447 #if DUMP_OPCODE_STATS
1448 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1450 #define BEGIN_OPCODE(opcode) case opcode:
1452 while (1) // iterator loop begins
1453 switch (vPC->u.opcode)
1456 BEGIN_OPCODE(op_new_object) {
1457 /* new_object dst(r)
1459 Constructs a new empty Object instance using the original
1460 constructor, and puts the result in register dst.
1462 int dst = (++vPC)->u.operand;
1463 r[dst] = constructEmptyObject(exec);
1468 BEGIN_OPCODE(op_new_array) {
1469 /* new_array dst(r) firstArg(r) argCount(n)
1471 Constructs a new Array instance using the original
1472 constructor, and puts the result in register dst.
1473 The array will contain argCount elements with values
1474 taken from registers starting at register firstArg.
1476 int dst = (++vPC)->u.operand;
1477 int firstArg = (++vPC)->u.operand;
1478 int argCount = (++vPC)->u.operand;
1479 ArgList args(r + firstArg, argCount);
1480 r[dst] = constructArray(exec, args);
1485 BEGIN_OPCODE(op_new_regexp) {
1486 /* new_regexp dst(r) regExp(re)
1488 Constructs a new RegExp instance using the original
1489 constructor from regexp regExp, and puts the result in
1492 int dst = (++vPC)->u.operand;
1493 int regExp = (++vPC)->u.operand;
1494 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1499 BEGIN_OPCODE(op_mov) {
1500 /* mov dst(r) src(r)
1502 Copies register src to register dst.
1504 int dst = (++vPC)->u.operand;
1505 int src = (++vPC)->u.operand;
1511 BEGIN_OPCODE(op_eq) {
1512 /* eq dst(r) src1(r) src2(r)
1514 Checks whether register src1 and register src2 are equal,
1515 as with the ECMAScript '==' operator, and puts the result
1516 as a boolean in register dst.
1518 int dst = (++vPC)->u.operand;
1519 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1520 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1521 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1522 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1524 JSValue* result = jsBoolean(equal(exec, src1, src2));
1525 VM_CHECK_EXCEPTION();
1532 BEGIN_OPCODE(op_eq_null) {
1533 /* neq dst(r) src(r)
1535 Checks whether register src is null, as with the ECMAScript '!='
1536 operator, and puts the result as a boolean in register dst.
1538 int dst = (++vPC)->u.operand;
1539 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1541 if (src->isUndefinedOrNull()) {
1542 r[dst] = jsBoolean(true);
1547 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined());
1551 BEGIN_OPCODE(op_neq) {
1552 /* neq dst(r) src1(r) src2(r)
1554 Checks whether register src1 and register src2 are not
1555 equal, as with the ECMAScript '!=' operator, and puts the
1556 result as a boolean in register dst.
1558 int dst = (++vPC)->u.operand;
1559 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1560 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1561 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1562 r[dst] = jsBoolean(src1 != src2);
1564 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1565 VM_CHECK_EXCEPTION();
1572 BEGIN_OPCODE(op_neq_null) {
1573 /* neq dst(r) src(r)
1575 Checks whether register src is not null, as with the ECMAScript '!='
1576 operator, and puts the result as a boolean in register dst.
1578 int dst = (++vPC)->u.operand;
1579 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1581 if (src->isUndefinedOrNull()) {
1582 r[dst] = jsBoolean(false);
1587 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined());
1591 BEGIN_OPCODE(op_stricteq) {
1592 /* stricteq dst(r) src1(r) src2(r)
1594 Checks whether register src1 and register src2 are strictly
1595 equal, as with the ECMAScript '===' operator, and puts the
1596 result as a boolean in register dst.
1598 int dst = (++vPC)->u.operand;
1599 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1600 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1601 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1602 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1604 r[dst] = jsBoolean(strictEqual(src1, src2));
1609 BEGIN_OPCODE(op_nstricteq) {
1610 /* nstricteq dst(r) src1(r) src2(r)
1612 Checks whether register src1 and register src2 are not
1613 strictly equal, as with the ECMAScript '!==' operator, and
1614 puts the result as a boolean in register dst.
1616 int dst = (++vPC)->u.operand;
1617 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1618 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1619 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1620 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1622 r[dst] = jsBoolean(!strictEqual(src1, src2));
1627 BEGIN_OPCODE(op_less) {
1628 /* less dst(r) src1(r) src2(r)
1630 Checks whether register src1 is less than register src2, as
1631 with the ECMAScript '<' operator, and puts the result as
1632 a boolean in register dst.
1634 int dst = (++vPC)->u.operand;
1635 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1636 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1637 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1638 VM_CHECK_EXCEPTION();
1644 BEGIN_OPCODE(op_lesseq) {
1645 /* lesseq dst(r) src1(r) src2(r)
1647 Checks whether register src1 is less than or equal to
1648 register src2, as with the ECMAScript '<=' operator, and
1649 puts the result as a boolean in register dst.
1651 int dst = (++vPC)->u.operand;
1652 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1653 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1654 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1655 VM_CHECK_EXCEPTION();
1661 BEGIN_OPCODE(op_pre_inc) {
1662 /* pre_inc srcDst(r)
1664 Converts register srcDst to number, adds one, and puts the result
1665 back in register srcDst.
1667 int srcDst = (++vPC)->u.operand;
1668 JSValue* v = r[srcDst].jsValue(exec);
1669 if (JSImmediate::canDoFastAdditiveOperations(v))
1670 r[srcDst] = JSImmediate::incImmediateNumber(v);
1672 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1673 VM_CHECK_EXCEPTION();
1680 BEGIN_OPCODE(op_pre_dec) {
1681 /* pre_dec srcDst(r)
1683 Converts register srcDst to number, subtracts one, and puts the result
1684 back in register srcDst.
1686 int srcDst = (++vPC)->u.operand;
1687 JSValue* v = r[srcDst].jsValue(exec);
1688 if (JSImmediate::canDoFastAdditiveOperations(v))
1689 r[srcDst] = JSImmediate::decImmediateNumber(v);
1691 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1692 VM_CHECK_EXCEPTION();
1699 BEGIN_OPCODE(op_post_inc) {
1700 /* post_inc dst(r) srcDst(r)
1702 Converts register srcDst to number. The number itself is
1703 written to register dst, and the number plus one is written
1704 back to register srcDst.
1706 int dst = (++vPC)->u.operand;
1707 int srcDst = (++vPC)->u.operand;
1708 JSValue* v = r[srcDst].jsValue(exec);
1709 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1711 r[srcDst] = JSImmediate::incImmediateNumber(v);
1713 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1714 VM_CHECK_EXCEPTION();
1716 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1722 BEGIN_OPCODE(op_post_dec) {
1723 /* post_dec dst(r) srcDst(r)
1725 Converts register srcDst to number. The number itself is
1726 written to register dst, and the number minus one is written
1727 back to register srcDst.
1729 int dst = (++vPC)->u.operand;
1730 int srcDst = (++vPC)->u.operand;
1731 JSValue* v = r[srcDst].jsValue(exec);
1732 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1734 r[srcDst] = JSImmediate::decImmediateNumber(v);
1736 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1737 VM_CHECK_EXCEPTION();
1739 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1745 BEGIN_OPCODE(op_to_jsnumber) {
1746 /* to_jsnumber dst(r) src(r)
1748 Converts register src to number, and puts the result
1751 int dst = (++vPC)->u.operand;
1752 int src = (++vPC)->u.operand;
1753 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1754 VM_CHECK_EXCEPTION();
1761 BEGIN_OPCODE(op_negate) {
1762 /* negate dst(r) src(r)
1764 Converts register src to number, negates it, and puts the
1765 result in register dst.
1767 int dst = (++vPC)->u.operand;
1768 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1770 if (fastIsNumber(src, v))
1771 r[dst] = jsNumber(exec, -v);
1773 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1774 VM_CHECK_EXCEPTION();
1781 BEGIN_OPCODE(op_add) {
1782 /* add dst(r) src1(r) src2(r)
1784 Adds register src1 and register src2, and puts the result
1785 in register dst. (JS add may be string concatenation or
1786 numeric add, depending on the types of the operands.)
1788 int dst = (++vPC)->u.operand;
1789 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1790 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1791 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1792 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1794 JSValue* result = jsAdd(exec, src1, src2);
1795 VM_CHECK_EXCEPTION();
1801 BEGIN_OPCODE(op_mul) {
1802 /* mul dst(r) src1(r) src2(r)
1804 Multiplies register src1 and register src2 (converted to
1805 numbers), and puts the product in register dst.
1807 int dst = (++vPC)->u.operand;
1808 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1809 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1812 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1813 r[dst] = jsNumber(exec, left * right);
1815 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1816 VM_CHECK_EXCEPTION();
1823 BEGIN_OPCODE(op_div) {
1824 /* div dst(r) dividend(r) divisor(r)
1826 Divides register dividend (converted to number) by the
1827 register divisor (converted to number), and puts the
1828 quotient in register dst.
1830 int dst = (++vPC)->u.operand;
1831 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1832 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1835 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1836 r[dst] = jsNumber(exec, left / right);
1838 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1839 VM_CHECK_EXCEPTION();
1845 BEGIN_OPCODE(op_mod) {
1846 /* mod dst(r) dividend(r) divisor(r)
1848 Divides register dividend (converted to number) by
1849 register divisor (converted to number), and puts the
1850 remainder in register dst.
1852 int dst = (++vPC)->u.operand;
1853 int dividend = (++vPC)->u.operand;
1854 int divisor = (++vPC)->u.operand;
1856 JSValue* dividendValue = r[dividend].jsValue(exec);
1857 JSValue* divisorValue = r[divisor].jsValue(exec);
1859 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1860 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1865 double d = dividendValue->toNumber(exec);
1866 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1867 VM_CHECK_EXCEPTION();
1872 BEGIN_OPCODE(op_sub) {
1873 /* sub dst(r) src1(r) src2(r)
1875 Subtracts register src2 (converted to number) from register
1876 src1 (converted to number), and puts the difference in
1879 int dst = (++vPC)->u.operand;
1880 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1881 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1884 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1885 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1886 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1887 r[dst] = jsNumber(exec, left - right);
1889 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1890 VM_CHECK_EXCEPTION();
1896 BEGIN_OPCODE(op_lshift) {
1897 /* lshift dst(r) val(r) shift(r)
1899 Performs left shift of register val (converted to int32) by
1900 register shift (converted to uint32), and puts the result
1903 int dst = (++vPC)->u.operand;
1904 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1905 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1908 if (JSImmediate::areBothImmediateNumbers(val, shift))
1909 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1910 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1911 r[dst] = jsNumber(exec, left << (right & 0x1f));
1913 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1914 VM_CHECK_EXCEPTION();
1921 BEGIN_OPCODE(op_rshift) {
1922 /* rshift dst(r) val(r) shift(r)
1924 Performs arithmetic right shift of register val (converted
1925 to int32) by register shift (converted to
1926 uint32), and puts the result in register dst.
1928 int dst = (++vPC)->u.operand;
1929 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1930 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1933 if (JSImmediate::areBothImmediateNumbers(val, shift))
1934 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1935 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1936 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1938 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1939 VM_CHECK_EXCEPTION();
1946 BEGIN_OPCODE(op_urshift) {
1947 /* rshift dst(r) val(r) shift(r)
1949 Performs logical right shift of register val (converted
1950 to uint32) by register shift (converted to
1951 uint32), and puts the result in register dst.
1953 int dst = (++vPC)->u.operand;
1954 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1955 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1956 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1957 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1959 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1960 VM_CHECK_EXCEPTION();
1967 BEGIN_OPCODE(op_bitand) {
1968 /* bitand dst(r) src1(r) src2(r)
1970 Computes bitwise AND of register src1 (converted to int32)
1971 and register src2 (converted to int32), and puts the result
1974 int dst = (++vPC)->u.operand;
1975 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1976 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1979 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1980 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1981 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1982 r[dst] = jsNumber(exec, left & right);
1984 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
1985 VM_CHECK_EXCEPTION();
1992 BEGIN_OPCODE(op_bitxor) {
1993 /* bitxor dst(r) src1(r) src2(r)
1995 Computes bitwise XOR of register src1 (converted to int32)
1996 and register src2 (converted to int32), and puts the result
1999 int dst = (++vPC)->u.operand;
2000 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2001 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2004 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2005 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
2006 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2007 r[dst] = jsNumber(exec, left ^ right);
2009 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
2010 VM_CHECK_EXCEPTION();
2017 BEGIN_OPCODE(op_bitor) {
2018 /* bitor dst(r) src1(r) src2(r)
2020 Computes bitwise OR of register src1 (converted to int32)
2021 and register src2 (converted to int32), and puts the
2022 result in register dst.
2024 int dst = (++vPC)->u.operand;
2025 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2026 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2029 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2030 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
2031 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2032 r[dst] = jsNumber(exec, left | right);
2034 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
2035 VM_CHECK_EXCEPTION();
2042 BEGIN_OPCODE(op_bitnot) {
2043 /* bitnot dst(r) src(r)
2045 Computes bitwise NOT of register src1 (converted to int32),
2046 and puts the result in register dst.
2048 int dst = (++vPC)->u.operand;
2049 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
2051 if (fastToInt32(src, value))
2052 r[dst] = jsNumber(exec, ~value);
2054 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
2055 VM_CHECK_EXCEPTION();
2061 BEGIN_OPCODE(op_not) {
2062 /* not dst(r) src(r)
2064 Computes logical NOT of register src (converted to
2065 boolean), and puts the result in register dst.
2067 int dst = (++vPC)->u.operand;
2068 int src = (++vPC)->u.operand;
2069 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
2070 VM_CHECK_EXCEPTION();
2076 BEGIN_OPCODE(op_instanceof) {
2077 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2079 Tests whether register value is an instance of register
2080 constructor, and puts the boolean result in register
2081 dst. Register constructorProto must contain the "prototype"
2082 property (not the actual prototype) of the object in
2083 register constructor. This lookup is separated so that
2084 polymorphic inline caching can apply.
2086 Raises an exception if register constructor is not an
2089 int dst = (++vPC)->u.operand;
2090 int value = (++vPC)->u.operand;
2091 int base = (++vPC)->u.operand;
2092 int baseProto = (++vPC)->u.operand;
2094 JSValue* baseVal = r[base].jsValue(exec);
2096 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
2099 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2100 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec), r[baseProto].jsValue(exec)) : false);
2105 BEGIN_OPCODE(op_typeof) {
2106 /* typeof dst(r) src(r)
2108 Determines the type string for src according to ECMAScript
2109 rules, and puts the result in register dst.
2111 int dst = (++vPC)->u.operand;
2112 int src = (++vPC)->u.operand;
2113 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2118 BEGIN_OPCODE(op_is_undefined) {
2119 /* is_undefined dst(r) src(r)
2121 Determines whether the type string for src according to
2122 the ECMAScript rules is "undefined", and puts the result
2125 int dst = (++vPC)->u.operand;
2126 int src = (++vPC)->u.operand;
2127 JSValue* v = r[src].jsValue(exec);
2128 r[dst] = jsBoolean(v->isUndefined() || (v->isObject() && static_cast<JSObject*>(v)->masqueradeAsUndefined()));
2133 BEGIN_OPCODE(op_is_boolean) {
2134 /* is_boolean dst(r) src(r)
2136 Determines whether the type string for src according to
2137 the ECMAScript rules is "boolean", and puts the result
2140 int dst = (++vPC)->u.operand;
2141 int src = (++vPC)->u.operand;
2142 r[dst] = jsBoolean(r[src].jsValue(exec)->isBoolean());
2147 BEGIN_OPCODE(op_is_number) {
2148 /* is_number dst(r) src(r)
2150 Determines whether the type string for src according to
2151 the ECMAScript rules is "number", and puts the result
2154 int dst = (++vPC)->u.operand;
2155 int src = (++vPC)->u.operand;
2156 r[dst] = jsBoolean(r[src].jsValue(exec)->isNumber());
2161 BEGIN_OPCODE(op_is_string) {
2162 /* is_string dst(r) src(r)
2164 Determines whether the type string for src according to
2165 the ECMAScript rules is "string", and puts the result
2168 int dst = (++vPC)->u.operand;
2169 int src = (++vPC)->u.operand;
2170 r[dst] = jsBoolean(r[src].jsValue(exec)->isString());
2175 BEGIN_OPCODE(op_is_object) {
2176 /* is_object dst(r) src(r)
2178 Determines whether the type string for src according to
2179 the ECMAScript rules is "object", and puts the result
2182 int dst = (++vPC)->u.operand;
2183 int src = (++vPC)->u.operand;
2184 r[dst] = jsBoolean(jsIsObjectType(r[src].jsValue(exec)));
2189 BEGIN_OPCODE(op_is_function) {
2190 /* is_function dst(r) src(r)
2192 Determines whether the type string for src according to
2193 the ECMAScript rules is "function", and puts the result
2196 int dst = (++vPC)->u.operand;
2197 int src = (++vPC)->u.operand;
2198 r[dst] = jsBoolean(jsIsFunctionType(r[src].jsValue(exec)));
2203 BEGIN_OPCODE(op_in) {
2204 /* in dst(r) property(r) base(r)
2206 Tests whether register base has a property named register
2207 property, and puts the boolean result in register dst.
2209 Raises an exception if register constructor is not an
2212 int dst = (++vPC)->u.operand;
2213 int property = (++vPC)->u.operand;
2214 int base = (++vPC)->u.operand;
2216 JSValue* baseVal = r[base].jsValue(exec);
2217 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
2220 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2222 JSValue* propName = r[property].jsValue(exec);
2225 if (propName->getUInt32(i))
2226 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2228 Identifier property(exec, propName->toString(exec));
2229 VM_CHECK_EXCEPTION();
2230 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2236 BEGIN_OPCODE(op_resolve) {
2237 /* resolve dst(r) property(id)
2239 Looks up the property named by identifier property in the
2240 scope chain, and writes the resulting value to register
2241 dst. If the property is not found, raises an exception.
2243 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2249 BEGIN_OPCODE(op_resolve_skip) {
2250 /* resolve_skip dst(r) property(id) skip(n)
2252 Looks up the property named by identifier property in the
2253 scope chain skipping the top 'skip' levels, and writes the resulting
2254 value to register dst. If the property is not found, raises an exception.
2256 if (UNLIKELY(!resolveSkip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2263 BEGIN_OPCODE(op_resolve_global) {
2264 /* resolve_skip dst(r) globalObject(c) property(id) structureID(sID) offset(n)
2266 Performs a dynamic property lookup for the given property, on the provided
2267 global object. If structureID matches the StructureID of the global then perform
2268 a fast lookup using the case offset, otherwise fall back to a full resolve and
2269 cache the new structureID and offset
2271 if (UNLIKELY(!resolveGlobal(exec, vPC, r, codeBlock, exceptionValue)))
2278 BEGIN_OPCODE(op_get_global_var) {
2279 /* get_global_var dst(r) globalObject(c) index(n)
2281 Gets the global var at global slot index and places it in register dst.
2283 int dst = (++vPC)->u.operand;
2284 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2285 ASSERT(scope->isGlobalObject());
2286 int index = (++vPC)->u.operand;
2288 r[dst] = scope->registerAt(index);
2292 BEGIN_OPCODE(op_put_global_var) {
2293 /* put_global_var globalObject(c) index(n) value(r)
2295 Puts value into global slot index.
2297 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2298 ASSERT(scope->isGlobalObject());
2299 int index = (++vPC)->u.operand;
2300 int value = (++vPC)->u.operand;
2302 scope->registerAt(index) = r[value].jsValue(exec);
2306 BEGIN_OPCODE(op_get_scoped_var) {
2307 /* get_scoped_var dst(r) index(n) skip(n)
2309 Loads the contents of the index-th local from the scope skip nodes from
2310 the top of the scope chain, and places it in register dst
2312 int dst = (++vPC)->u.operand;
2313 int index = (++vPC)->u.operand;
2314 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2316 ScopeChainIterator iter = scopeChain->begin();
2317 ScopeChainIterator end = scopeChain->end();
2318 ASSERT(iter != end);
2321 ASSERT(iter != end);
2324 ASSERT((*iter)->isVariableObject());
2325 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2326 r[dst] = scope->registerAt(index);
2330 BEGIN_OPCODE(op_put_scoped_var) {
2331 /* put_scoped_var index(n) skip(n) value(r)
2334 int index = (++vPC)->u.operand;
2335 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2336 int value = (++vPC)->u.operand;
2338 ScopeChainIterator iter = scopeChain->begin();
2339 ScopeChainIterator end = scopeChain->end();
2340 ASSERT(iter != end);
2343 ASSERT(iter != end);
2346 ASSERT((*iter)->isVariableObject());
2347 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2348 scope->registerAt(index) = r[value].jsValue(exec);
2352 BEGIN_OPCODE(op_resolve_base) {
2353 /* resolve_base dst(r) property(id)
2355 Searches the scope chain for an object containing
2356 identifier property, and if one is found, writes it to
2357 register dst. If none is found, the outermost scope (which
2358 will be the global object) is stored in register dst.
2360 resolveBase(exec, vPC, r, scopeChain, codeBlock);
2365 BEGIN_OPCODE(op_resolve_with_base) {
2366 /* resolve_with_base baseDst(r) propDst(r) property(id)
2368 Searches the scope chain for an object containing
2369 identifier property, and if one is found, writes it to
2370 register srcDst, and the retrieved property value to register
2371 propDst. If the property is not found, raises an exception.
2373 This is more efficient than doing resolve_base followed by
2374 resolve, or resolve_base followed by get_by_id, as it
2375 avoids duplicate hash lookups.
2377 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2383 BEGIN_OPCODE(op_resolve_func) {
2384 /* resolve_func baseDst(r) funcDst(r) property(id)
2386 Searches the scope chain for an object containing
2387 identifier property, and if one is found, writes the
2388 appropriate object to use as "this" when calling its
2389 properties to register baseDst; and the retrieved property
2390 value to register propDst. If the property is not found,
2391 raises an exception.
2393 This differs from resolve_with_base, because the
2394 global this value will be substituted for activations or
2395 the global object, which is the right behavior for function
2396 calls but not for other property lookup.
2398 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2404 BEGIN_OPCODE(op_get_by_id) {
2405 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2407 Generic property access: Gets the property named by identifier
2408 property from the value base, and puts the result in register dst.
2410 int dst = vPC[1].u.operand;
2411 int base = vPC[2].u.operand;
2412 int property = vPC[3].u.operand;
2414 Identifier& ident = codeBlock->identifiers[property];
2415 JSValue* baseValue = r[base].jsValue(exec);
2416 PropertySlot slot(baseValue);
2417 JSValue* result = baseValue->get(exec, ident, slot);
2418 VM_CHECK_EXCEPTION();
2420 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2426 BEGIN_OPCODE(op_get_by_id_self) {
2427 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2429 Cached property access: Attempts to get a cached property from the
2430 value base. If the cache misses, op_get_by_id_self reverts to
2433 int base = vPC[2].u.operand;
2434 JSValue* baseValue = r[base].jsValue(exec);
2436 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2437 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2438 StructureID* structureID = vPC[4].u.structureID;
2440 if (LIKELY(baseCell->structureID() == structureID)) {
2441 ASSERT(baseCell->isObject());
2442 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2443 int dst = vPC[1].u.operand;
2444 int offset = vPC[5].u.operand;
2446 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2447 r[dst] = baseObject->getDirectOffset(offset);
2454 uncacheGetByID(codeBlock, vPC);
2457 BEGIN_OPCODE(op_get_by_id_proto) {
2458 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2460 Cached property access: Attempts to get a cached property from the
2461 value base's prototype. If the cache misses, op_get_by_id_proto
2462 reverts to op_get_by_id.
2464 int base = vPC[2].u.operand;
2465 JSValue* baseValue = r[base].jsValue(exec);
2467 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2468 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2469 StructureID* structureID = vPC[4].u.structureID;
2471 if (LIKELY(baseCell->structureID() == structureID)) {
2472 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2473 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2474 StructureID* protoStructureID = vPC[5].u.structureID;
2476 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2477 int dst = vPC[1].u.operand;
2478 int offset = vPC[6].u.operand;
2480 ASSERT(protoObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2481 r[dst] = protoObject->getDirectOffset(offset);
2489 uncacheGetByID(codeBlock, vPC);
2492 BEGIN_OPCODE(op_get_by_id_chain) {
2493 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2495 Cached property access: Attempts to get a cached property from the
2496 value base's prototype chain. If the cache misses, op_get_by_id_chain
2497 reverts to op_get_by_id.
2499 int base = vPC[2].u.operand;
2500 JSValue* baseValue = r[base].jsValue(exec);
2502 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2503 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2504 StructureID* structureID = vPC[4].u.structureID;
2506 if (LIKELY(baseCell->structureID() == structureID)) {
2507 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2508 size_t count = vPC[6].u.operand;
2509 RefPtr<StructureID>* end = it + count;
2511 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2513 baseObject = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2514 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2518 int dst = vPC[1].u.operand;
2519 int offset = vPC[7].u.operand;
2521 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2522 r[dst] = baseObject->getDirectOffset(offset);
2531 uncacheGetByID(codeBlock, vPC);
2534 BEGIN_OPCODE(op_get_by_id_generic) {
2535 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2537 Generic property access: Gets the property named by identifier
2538 property from the value base, and puts the result in register dst.
2540 int dst = vPC[1].u.operand;
2541 int base = vPC[2].u.operand;
2542 int property = vPC[3].u.operand;
2544 Identifier& ident = codeBlock->identifiers[property];
2546 JSValue* baseValue = r[base].jsValue(exec);
2547 PropertySlot slot(baseValue);
2548 JSValue* result = baseValue->get(exec, ident, slot);
2549 VM_CHECK_EXCEPTION();
2555 BEGIN_OPCODE(op_get_array_length) {
2556 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2558 Cached property access: Gets the length of the array in register base,
2559 and puts the result in register dst. If register base does not hold
2560 an array, op_get_array_length reverts to op_get_by_id.
2563 int base = vPC[2].u.operand;
2564 JSValue* baseValue = r[base].jsValue(exec);
2565 if (LIKELY(isJSArray(baseValue))) {
2566 int dst = vPC[1].u.operand;
2567 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2572 uncacheGetByID(codeBlock, vPC);
2575 BEGIN_OPCODE(op_get_string_length) {
2576 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2578 Cached property access: Gets the length of the string in register base,
2579 and puts the result in register dst. If register base does not hold
2580 a string, op_get_string_length reverts to op_get_by_id.
2583 int base = vPC[2].u.operand;
2584 JSValue* baseValue = r[base].jsValue(exec);
2585 if (LIKELY(isJSString(baseValue))) {
2586 int dst = vPC[1].u.operand;
2587 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2592 uncacheGetByID(codeBlock, vPC);
2595 BEGIN_OPCODE(op_put_by_id) {
2596 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2598 Generic property access: Sets the property named by identifier
2599 property, belonging to register base, to register value.
2601 Unlike many opcodes, this one does not write any output to
2605 int base = vPC[1].u.operand;
2606 int property = vPC[2].u.operand;
2607 int value = vPC[3].u.operand;
2609 JSValue* baseValue = r[base].jsValue(exec);
2611 PutPropertySlot slot;
2612 Identifier& ident = codeBlock->identifiers[property];
2613 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2614 VM_CHECK_EXCEPTION();
2616 tryCachePutByID(exec, codeBlock, vPC, baseValue, slot);
2621 BEGIN_OPCODE(op_put_by_id_transition) {
2622 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2624 Cached property access: Attempts to set a new property with a cached transition
2625 property named by identifier property, belonging to register base,
2626 to register value. If the cache misses, op_put_by_id_transition
2627 reverts to op_put_by_id_generic.
2629 Unlike many opcodes, this one does not write any output to
2632 int base = vPC[1].u.operand;
2633 JSValue* baseValue = r[base].jsValue(exec);
2635 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2636 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2637 StructureID* oldStructureID = vPC[4].u.structureID;
2638 StructureID* newStructureID = vPC[5].u.structureID;
2640 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2641 ASSERT(baseCell->isObject());
2642 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2644 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2646 JSObject* proto = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2647 while (!proto->isNull()) {
2648 if (UNLIKELY(proto->structureID() != (*it).get())) {
2649 uncachePutByID(codeBlock, vPC);
2653 proto = static_cast<JSObject*>(proto->structureID()->prototypeForLookup(exec));
2656 baseObject->transitionTo(newStructureID);
2657 if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
2658 baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
2660 int value = vPC[3].u.operand;
2661 unsigned offset = vPC[7].u.operand;
2662 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2663 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2670 uncachePutByID(codeBlock, vPC);
2673 BEGIN_OPCODE(op_put_by_id_replace) {
2674 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2676 Cached property access: Attempts to set a pre-existing, cached
2677 property named by identifier property, belonging to register base,
2678 to register value. If the cache misses, op_put_by_id_replace
2679 reverts to op_put_by_id.
2681 Unlike many opcodes, this one does not write any output to
2684 int base = vPC[1].u.operand;
2685 JSValue* baseValue = r[base].jsValue(exec);
2687 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2688 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2689 StructureID* structureID = vPC[4].u.structureID;
2691 if (LIKELY(baseCell->structureID() == structureID)) {
2692 ASSERT(baseCell->isObject());
2693 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2694 int value = vPC[3].u.operand;
2695 unsigned offset = vPC[5].u.operand;
2697 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2698 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2705 uncachePutByID(codeBlock, vPC);
2708 BEGIN_OPCODE(op_put_by_id_generic) {
2709 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2711 Generic property access: Sets the property named by identifier
2712 property, belonging to register base, to register value.
2714 Unlike many opcodes, this one does not write any output to
2717 int base = vPC[1].u.operand;
2718 int property = vPC[2].u.operand;
2719 int value = vPC[3].u.operand;
2721 JSValue* baseValue = r[base].jsValue(exec);
2723 PutPropertySlot slot;
2724 Identifier& ident = codeBlock->identifiers[property];
2725 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2726 VM_CHECK_EXCEPTION();
2731 BEGIN_OPCODE(op_del_by_id) {
2732 /* del_by_id dst(r) base(r) property(id)
2734 Converts register base to Object, deletes the property
2735 named by identifier property from the object, and writes a
2736 boolean indicating success (if true) or failure (if false)
2739 int dst = (++vPC)->u.operand;
2740 int base = (++vPC)->u.operand;
2741 int property = (++vPC)->u.operand;
2743 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2745 Identifier& ident = codeBlock->identifiers[property];
2746 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2747 VM_CHECK_EXCEPTION();
2752 BEGIN_OPCODE(op_get_by_val) {
2753 /* get_by_val dst(r) base(r) property(r)
2755 Converts register base to Object, gets the property named
2756 by register property from the object, and puts the result
2757 in register dst. property is nominally converted to string
2758 but numbers are treated more efficiently.
2760 int dst = (++vPC)->u.operand;
2761 int base = (++vPC)->u.operand;
2762 int property = (++vPC)->u.operand;
2764 JSValue* baseValue = r[base].jsValue(exec);
2765 JSValue* subscript = r[property].jsValue(exec);
2770 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2771 if (LIKELY(isUInt32)) {
2772 if (isJSArray(baseValue)) {
2773 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2774 if (jsArray->canGetIndex(i))
2775 result = jsArray->getIndex(i);
2777 result = jsArray->JSArray::get(exec, i);
2778 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2779 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2781 result = baseValue->get(exec, i);
2783 Identifier property(exec, subscript->toString(exec));
2784 result = baseValue->get(exec, property);
2787 VM_CHECK_EXCEPTION();
2792 BEGIN_OPCODE(op_put_by_val) {
2793 /* put_by_val base(r) property(r) value(r)
2795 Sets register value on register base as the property named
2796 by register property. Base is converted to object
2797 first. register property is nominally converted to string
2798 but numbers are treated more efficiently.
2800 Unlike many opcodes, this one does not write any output to
2803 int base = (++vPC)->u.operand;
2804 int property = (++vPC)->u.operand;
2805 int value = (++vPC)->u.operand;
2807 JSValue* baseValue = r[base].jsValue(exec);
2808 JSValue* subscript = r[property].jsValue(exec);
2812 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2813 if (LIKELY(isUInt32)) {
2814 if (isJSArray(baseValue)) {
2815 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2816 if (jsArray->canSetIndex(i))
2817 jsArray->setIndex(i, r[value].jsValue(exec));
2819 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2821 baseValue->put(exec, i, r[value].jsValue(exec));
2823 Identifier property(exec, subscript->toString(exec));
2824 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2825 PutPropertySlot slot;
2826 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2830 VM_CHECK_EXCEPTION();
2834 BEGIN_OPCODE(op_del_by_val) {
2835 /* del_by_val dst(r) base(r) property(r)
2837 Converts register base to Object, deletes the property
2838 named by register property from the object, and writes a
2839 boolean indicating success (if true) or failure (if false)
2842 int dst = (++vPC)->u.operand;
2843 int base = (++vPC)->u.operand;
2844 int property = (++vPC)->u.operand;
2846 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2848 JSValue* subscript = r[property].jsValue(exec);
2851 if (subscript->getUInt32(i))
2852 result = jsBoolean(baseObj->deleteProperty(exec, i));
2854 VM_CHECK_EXCEPTION();
2855 Identifier property(exec, subscript->toString(exec));
2856 VM_CHECK_EXCEPTION();
2857 result = jsBoolean(baseObj->deleteProperty(exec, property));
2860 VM_CHECK_EXCEPTION();
2865 BEGIN_OPCODE(op_put_by_index) {
2866 /* put_by_index base(r) property(n) value(r)
2868 Sets register value on register base as the property named
2869 by the immediate number property. Base is converted to
2872 Unlike many opcodes, this one does not write any output to
2875 This opcode is mainly used to initialize array literals.
2877 int base = (++vPC)->u.operand;
2878 unsigned property = (++vPC)->u.operand;
2879 int value = (++vPC)->u.operand;
2881 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2886 BEGIN_OPCODE(op_loop) {
2887 /* loop target(offset)
2889 Jumps unconditionally to offset target from the current
2892 Additionally this loop instruction may terminate JS execution is
2893 the JS timeout is reached.
2895 #if DUMP_OPCODE_STATS
2896 OpcodeStats::resetLastInstruction();
2898 int target = (++vPC)->u.operand;
2899 CHECK_FOR_TIMEOUT();
2903 BEGIN_OPCODE(op_jmp) {
2904 /* jmp target(offset)
2906 Jumps unconditionally to offset target from the current
2909 #if DUMP_OPCODE_STATS
2910 OpcodeStats::resetLastInstruction();
2912 int target = (++vPC)->u.operand;
2917 BEGIN_OPCODE(op_loop_if_true) {
2918 /* loop_if_true cond(r) target(offset)
2920 Jumps to offset target from the current instruction, if and
2921 only if register cond converts to boolean as true.
2923 Additionally this loop instruction may terminate JS execution is
2924 the JS timeout is reached.
2926 int cond = (++vPC)->u.operand;
2927 int target = (++vPC)->u.operand;
2928 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2930 CHECK_FOR_TIMEOUT();
2937 BEGIN_OPCODE(op_jtrue) {
2938 /* jtrue cond(r) target(offset)
2940 Jumps to offset target from the current instruction, if and
2941 only if register cond converts to boolean as true.
2943 int cond = (++vPC)->u.operand;
2944 int target = (++vPC)->u.operand;
2945 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2953 BEGIN_OPCODE(op_jfalse) {
2954 /* jfalse cond(r) target(offset)
2956 Jumps to offset target from the current instruction, if and
2957 only if register cond converts to boolean as false.
2959 int cond = (++vPC)->u.operand;
2960 int target = (++vPC)->u.operand;
2961 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2969 BEGIN_OPCODE(op_loop_if_less) {
2970 /* loop_if_less src1(r) src2(r) target(offset)
2972 Checks whether register src1 is less than register src2, as
2973 with the ECMAScript '<' operator, and then jumps to offset
2974 target from the current instruction, if and only if the
2975 result of the comparison is true.
2977 Additionally this loop instruction may terminate JS execution is
2978 the JS timeout is reached.
2980 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2981 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2982 int target = (++vPC)->u.operand;
2984 bool result = jsLess(exec, src1, src2);
2985 VM_CHECK_EXCEPTION();
2989 CHECK_FOR_TIMEOUT();
2996 BEGIN_OPCODE(op_loop_if_lesseq) {
2997 /* loop_if_lesseq src1(r) src2(r) target(offset)
2999 Checks whether register src1 is less than or equal to register
3000 src2, as with the ECMAScript '<=' operator, and then jumps to
3001 offset target from the current instruction, if and only if the
3002 result of the comparison is true.
3004 Additionally this loop instruction may terminate JS execution is
3005 the JS timeout is reached.
3007 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3008 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3009 int target = (++vPC)->u.operand;
3011 bool result = jsLessEq(exec, src1, src2);
3012 VM_CHECK_EXCEPTION();
3016 CHECK_FOR_TIMEOUT();
3023 BEGIN_OPCODE(op_jnless) {
3024 /* jnless src1(r) src2(r) target(offset)
3026 Checks whether register src1 is less than register src2, as
3027 with the ECMAScript '<' operator, and then jumps to offset
3028 target from the current instruction, if and only if the
3029 result of the comparison is false.
3031 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3032 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3033 int target = (++vPC)->u.operand;
3035 bool result = jsLess(exec, src1, src2);
3036 VM_CHECK_EXCEPTION();
3046 BEGIN_OPCODE(op_switch_imm) {
3047 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3049 Performs a range checked switch on the scrutinee value, using
3050 the tableIndex-th immediate switch jump table. If the scrutinee value
3051 is an immediate number in the range covered by the referenced jump
3052 table, and the value at jumpTable[scrutinee value] is non-zero, then
3053 that value is used as the jump offset, otherwise defaultOffset is used.
3055 int tableIndex = (++vPC)->u.operand;
3056 int defaultOffset = (++vPC)->u.operand;
3057 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3058 if (!JSImmediate::isNumber(scrutinee))
3059 vPC += defaultOffset;
3061 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3062 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
3066 BEGIN_OPCODE(op_switch_char) {
3067 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3069 Performs a range checked switch on the scrutinee value, using
3070 the tableIndex-th character switch jump table. If the scrutinee value
3071 is a single character string in the range covered by the referenced jump
3072 table, and the value at jumpTable[scrutinee value] is non-zero, then
3073 that value is used as the jump offset, otherwise defaultOffset is used.
3075 int tableIndex = (++vPC)->u.operand;
3076 int defaultOffset = (++vPC)->u.operand;
3077 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3078 if (!scrutinee->isString())
3079 vPC += defaultOffset;
3081 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
3082 if (value->size() != 1)
3083 vPC += defaultOffset;
3085 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
3089 BEGIN_OPCODE(op_switch_string) {
3090 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3092 Performs a sparse hashmap based switch on the value in the scrutinee
3093 register, using the tableIndex-th string switch jump table. If the
3094 scrutinee value is a string that exists as a key in the referenced
3095 jump table, then the value associated with the string is used as the
3096 jump offset, otherwise defaultOffset is used.
3098 int tableIndex = (++vPC)->u.operand;
3099 int defaultOffset = (++vPC)->u.operand;
3100 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3101 if (!scrutinee->isString())
3102 vPC += defaultOffset;
3104 vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
3107 BEGIN_OPCODE(op_new_func) {
3108 /* new_func dst(r) func(f)
3110 Constructs a new Function instance from function func and
3111 the current scope chain using the original Function
3112 constructor, using the rules for function declarations, and
3113 puts the result in register dst.
3115 int dst = (++vPC)->u.operand;
3116 int func = (++vPC)->u.operand;
3118 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
3123 BEGIN_OPCODE(op_new_func_exp) {
3124 /* new_func_exp dst(r) func(f)
3126 Constructs a new Function instance from function func and
3127 the current scope chain using the original Function
3128 constructor, using the rules for function expressions, and
3129 puts the result in register dst.
3131 int dst = (++vPC)->u.operand;
3132 int func = (++vPC)->u.operand;
3134 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
3139 BEGIN_OPCODE(op_call_eval) {
3140 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3142 Call a function named "eval" with no explicit "this" value
3143 (which may therefore be the eval operator). If register
3144 thisVal is the global object, and register func contains
3145 that global object's original global eval function, then
3146 perform the eval operator in local scope (interpreting
3147 the argument registers as for the "call"
3148 opcode). Otherwise, act exactly as the "call" opcode would.
3151 int dst = (++vPC)->u.operand;
3152 int func = (++vPC)->u.operand;
3153 int thisVal = (++vPC)->u.operand;
3154 int firstArg = (++vPC)->u.operand;
3155 int argCount = (++vPC)->u.operand;
3157 JSValue* funcVal = r[func].jsValue(exec);
3158 JSValue* baseVal = r[thisVal].jsValue(exec);
3160 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
3161 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
3162 JSValue* result = callEval(exec, codeBlock, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
3172 // We didn't find the blessed version of eval, so reset vPC and process
3173 // this instruction as a normal function call, supplying the proper 'this'
3176 r[thisVal] = baseVal->toThisObject(exec);
3178 #if HAVE(COMPUTED_GOTO)
3179 // Hack around gcc performance quirk by performing an indirect goto
3180 // in order to set the vPC -- attempting to do so directly results in a
3181 // significant regression.
3182 goto *op_call_indirect; // indirect goto -> op_call
3184 // fall through to op_call
3186 BEGIN_OPCODE(op_call) {
3187 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3189 Perform a function call. Specifically, call register func
3190 with a "this" value of register thisVal, and put the result
3193 The arguments start at register firstArg and go up to
3194 argCount, but the "this" value is considered an implicit
3195 first argument, so the argCount should be one greater than
3196 the number of explicit arguments passed, and the register
3197 after firstArg should contain the actual first
3198 argument. This opcode will copy from the thisVal register
3199 to the firstArg register, unless the register index of
3200 thisVal is the special missing this object marker, which is
3201 2^31-1; in that case, the global object will be used as the
3204 If func is a native code function, then this opcode calls
3205 it and returns the value immediately.
3207 But if it is a JS function, then the current scope chain
3208 and code block is set to the function's, and we slide the
3209 register window so that the arguments would form the first
3210 few local registers of the called function's register
3211 window. In addition, a call frame header is written
3212 immediately before the arguments; see the call frame
3213 documentation for an explanation of how many registers a
3214 call frame takes and what they contain. That many registers
3215 before the firstArg register will be overwritten by the
3216 call. In addition, any registers higher than firstArg +
3217 argCount may be overwritten. Once this setup is complete,
3218 execution continues from the called function's first
3219 argument, and does not return until a "ret" opcode is
3223 int dst = (++vPC)->u.operand;
3224 int func = (++vPC)->u.operand;
3225 int thisVal = (++vPC)->u.operand;
3226 int firstArg = (++vPC)->u.operand;
3227 int argCount = (++vPC)->u.operand;
3229 JSValue* v = r[func].jsValue(exec);
3232 CallType callType = v->getCallData(callData);
3234 if (*enabledProfilerReference)
3235 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3237 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3238 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, v);
3239 exec->m_callFrame = callFrame;
3241 if (callType == CallTypeJS) {
3243 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3244 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3245 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3247 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3249 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3250 if (UNLIKELY(exceptionValue != 0))
3253 codeBlock = newCodeBlock;
3254 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3255 vPC = codeBlock->instructions.begin();
3257 #if DUMP_OPCODE_STATS
3258 OpcodeStats::resetLastInstruction();
3264 if (callType == CallTypeHost) {
3265 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3266 ArgList args(r + firstArg + 1, argCount - 1);
3268 MACHINE_SAMPLING_callingHostFunction();
3270 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
3271 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3272 VM_CHECK_EXCEPTION();
3274 r[dst] = returnValue;
3276 if (*enabledProfilerReference)
3277 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3283 ASSERT(callType == CallTypeNone);
3285 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
3286 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3289 BEGIN_OPCODE(op_ret) {
3292 Return register result as the return value of the current
3293 function call, writing it into the caller's expected return
3294 value register. In addition, unwind one call frame and
3295 restore the scope chain, code block instruction pointer and
3296 register base to those of the calling function.
3299 int result = (++vPC)->u.operand;
3301 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3302 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
3303 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
3304 ASSERT(activation->isActivationObject());
3305 activation->copyRegisters();
3308 if (*enabledProfilerReference)
3309 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
3311 if (codeBlock->needsFullScopeChain)
3312 scopeChain->deref();
3314 JSValue* returnValue = r[result].jsValue(exec);
3316 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3320 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3321 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
3322 r = callFrame[RegisterFile::CallerRegisters].r();
3323 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3324 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
3325 r[dst] = returnValue;
3329 BEGIN_OPCODE(op_construct) {
3330 /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n)
3332 Invoke register "constr" as a constructor. For JS
3333 functions, the calling convention is exactly as for the
3334 "call" opcode, except that the "this" value is a newly
3335 created Object. For native constructors, a null "this"
3336 value is passed. In either case, the firstArg and argCount
3337 registers are interpreted as for the "call" opcode.
3339 Register constrProto must contain the prototype property of
3340 register constsr. This is to enable polymorphic inline
3341 caching of this lookup.
3344 int dst = (++vPC)->u.operand;
3345 int constr = (++vPC)->u.operand;
3346 int constrProto = (++vPC)->u.operand;
3347 int firstArg = (++vPC)->u.operand;
3348 int argCount = (++vPC)->u.operand;
3350 JSValue* constrVal = r[constr].jsValue(exec);
3352 ConstructData constructData;
3353 ConstructType constructType = constrVal->getConstructData(constructData);
3355 // Removing this line of code causes a measurable regression on squirrelfish.
3356 JSObject* constructor = static_cast<JSObject*>(constrVal);
3358 if (constructType == ConstructTypeJS) {
3359 if (*enabledProfilerReference)
3360 (*enabledProfilerReference)->willExecute(exec, constructor);
3362 JSObject* prototype;
3363 JSValue* p = r[constrProto].jsValue(exec);
3365 prototype = static_cast<JSObject*>(p);
3367 prototype = scopeChain->globalObject()->objectPrototype();
3368 JSObject* newObject = new (exec) JSObject(prototype);
3370 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3371 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3372 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3374 r[firstArg] = newObject; // "this" value
3376 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3377 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, constructor);
3378 exec->m_callFrame = callFrame;
3380 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3384 codeBlock = newCodeBlock;
3385 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3386 vPC = codeBlock->instructions.begin();
3391 if (constructType == ConstructTypeHost) {
3392 if (*enabledProfilerReference)
3393 (*enabledProfilerReference)->willExecute(exec, constructor);
3395 ArgList args(r + firstArg + 1, argCount - 1);
3397 MACHINE_SAMPLING_callingHostFunction();
3399 JSValue* returnValue = constructData.native.function(exec, constructor, args);
3401 VM_CHECK_EXCEPTION();
3402 r[dst] = returnValue;
3404 if (*enabledProfilerReference)
3405 (*enabledProfilerReference)->didExecute(exec, constructor);
3411 ASSERT(constructType == ConstructTypeNone);
3413 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
3416 BEGIN_OPCODE(op_construct_verify) {
3417 /* construct_verify dst(r) override(r)
3419 Verifies that register dst holds an object. If not, moves
3420 the object in register override to register dst.
3423 int dst = vPC[1].u.operand;;
3424 if (LIKELY(r[dst].jsValue(exec)->isObject())) {
3429 int override = vPC[2].u.operand;
3430 r[dst] = r[override];
3435 BEGIN_OPCODE(op_push_scope) {
3436 /* push_scope scope(r)
3438 Converts register scope to object, and pushes it onto the top
3439 of the current scope chain.
3441 int scope = (++vPC)->u.operand;