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))
153 Machine* machine = exec->machine();
154 if (machine->isJSString(v1) && machine->isJSString(v2))
155 return static_cast<const JSString*>(v1)->value() < static_cast<const JSString*>(v2)->value();
159 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
160 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
162 if (wasNotString1 | wasNotString2)
165 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
168 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
170 if (JSImmediate::areBothImmediateNumbers(v1, v2))
171 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
175 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
178 Machine* machine = exec->machine();
179 if (machine->isJSString(v1) && machine->isJSString(v2))
180 return !(static_cast<const JSString*>(v2)->value() < static_cast<const JSString*>(v1)->value());
184 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
185 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
187 if (wasNotString1 | wasNotString2)
190 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
193 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
195 // exception for the Date exception in defaultValue()
196 JSValue* p1 = v1->toPrimitive(exec);
197 JSValue* p2 = v2->toPrimitive(exec);
199 if (p1->isString() || p2->isString()) {
200 RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
202 return throwOutOfMemoryError(exec);
203 return jsString(exec, value.release());
206 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
209 // Fast-path choices here are based on frequency data from SunSpider:
210 // <times> Add case: <t1> <t2>
211 // ---------------------------
212 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
213 // 247412 Add case: 5 5
214 // 20900 Add case: 5 6
215 // 13962 Add case: 5 3
216 // 4000 Add case: 3 5
218 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
222 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
223 return jsNumber(exec, left + right);
225 if (v1->isString() && v2->isString()) {
226 RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
228 return throwOutOfMemoryError(exec);
229 return jsString(exec, value.release());
232 // All other cases are pretty uncommon
233 return jsAddSlowCase(exec, v1, v2);
236 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
238 if (v->isUndefined())
239 return jsNontrivialString(exec, "undefined");
241 return jsNontrivialString(exec, "boolean");
243 return jsNontrivialString(exec, "number");
245 return jsNontrivialString(exec, "string");
247 // Return "undefined" for objects that should be treated
248 // as null when doing comparisons.
249 if (static_cast<JSObject*>(v)->structureID()->typeInfo().masqueradesAsUndefined())
250 return jsNontrivialString(exec, "undefined");
252 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
253 return jsNontrivialString(exec, "function");
255 return jsNontrivialString(exec, "object");
258 static bool jsIsObjectType(JSValue* v)
260 if (JSImmediate::isImmediate(v))
263 JSType type = static_cast<JSCell*>(v)->structureID()->typeInfo().type();
264 if (type == NumberType || type == StringType)
266 if (type == ObjectType) {
267 if (static_cast<JSObject*>(v)->structureID()->typeInfo().masqueradesAsUndefined())
270 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
276 static bool jsIsFunctionType(JSValue* v)
280 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
286 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
288 int dst = (vPC + 1)->u.operand;
289 int property = (vPC + 2)->u.operand;
291 ScopeChainIterator iter = scopeChain->begin();
292 ScopeChainIterator end = scopeChain->end();
295 Identifier& ident = codeBlock->identifiers[property];
298 PropertySlot slot(o);
299 if (o->getPropertySlot(exec, ident, slot)) {
300 JSValue* result = slot.getValue(exec, ident);
301 exceptionValue = exec->exception();
307 } while (++iter != end);
308 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
312 static bool NEVER_INLINE resolveSkip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
314 int dst = (vPC + 1)->u.operand;
315 int property = (vPC + 2)->u.operand;
316 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
318 ScopeChainIterator iter = scopeChain->begin();
319 ScopeChainIterator end = scopeChain->end();
325 Identifier& ident = codeBlock->identifiers[property];
328 PropertySlot slot(o);
329 if (o->getPropertySlot(exec, ident, slot)) {
330 JSValue* result = slot.getValue(exec, ident);
331 exceptionValue = exec->exception();
337 } while (++iter != end);
338 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
342 static bool NEVER_INLINE resolveGlobal(ExecState* exec, Instruction* vPC, Register* r, CodeBlock* codeBlock, JSValue*& exceptionValue)
344 int dst = (vPC + 1)->u.operand;
345 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
346 ASSERT(globalObject->isGlobalObject());
347 int property = (vPC + 3)->u.operand;
348 StructureID* structureID = (vPC + 4)->u.structureID;
349 int offset = (vPC + 5)->u.operand;
351 if (structureID == globalObject->structureID()) {
352 r[dst] = globalObject->getDirectOffset(offset);
356 Identifier& ident = codeBlock->identifiers[property];
357 PropertySlot slot(globalObject);
358 if (globalObject->getPropertySlot(exec, ident, slot)) {
359 JSValue* result = slot.getValue(exec, ident);
360 if (slot.isCacheable()) {
361 if (vPC[4].u.structureID)
362 vPC[4].u.structureID->deref();
363 globalObject->structureID()->ref();
364 vPC[4] = globalObject->structureID();
365 vPC[5] = slot.cachedOffset();
370 exceptionValue = exec->exception();
377 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
381 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
383 ScopeChainIterator iter = scopeChain->begin();
384 ScopeChainIterator next = iter;
386 ScopeChainIterator end = scopeChain->end();
393 if (next == end || base->getPropertySlot(exec, property, slot))
400 ASSERT_NOT_REACHED();
404 NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
406 int dst = (vPC + 1)->u.operand;
407 int property = (vPC + 2)->u.operand;
408 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
411 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
413 int baseDst = (vPC + 1)->u.operand;
414 int propDst = (vPC + 2)->u.operand;
415 int property = (vPC + 3)->u.operand;
417 ScopeChainIterator iter = scopeChain->begin();
418 ScopeChainIterator end = scopeChain->end();
420 // FIXME: add scopeDepthIsZero optimization
424 Identifier& ident = codeBlock->identifiers[property];
428 PropertySlot slot(base);
429 if (base->getPropertySlot(exec, ident, slot)) {
430 JSValue* result = slot.getValue(exec, ident);
431 exceptionValue = exec->exception();
439 } while (iter != end);
441 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
445 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
447 int baseDst = (vPC + 1)->u.operand;
448 int funcDst = (vPC + 2)->u.operand;
449 int property = (vPC + 3)->u.operand;
451 ScopeChainIterator iter = scopeChain->begin();
452 ScopeChainIterator end = scopeChain->end();
454 // FIXME: add scopeDepthIsZero optimization
458 Identifier& ident = codeBlock->identifiers[property];
462 PropertySlot slot(base);
463 if (base->getPropertySlot(exec, ident, slot)) {
464 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
465 // However, section 10.2.3 says that in the case where the value provided
466 // by the caller is null, the global object should be used. It also says
467 // that the section does not apply to internal functions, but for simplicity
468 // of implementation we use the global object anyway here. This guarantees
469 // that in host objects you always get a valid object for this.
470 // We also handle wrapper substitution for the global object at the same time.
471 JSObject* thisObj = base->toThisObject(exec);
472 JSValue* result = slot.getValue(exec, ident);
473 exceptionValue = exec->exception();
477 r[baseDst] = thisObj;
482 } while (iter != end);
484 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
488 #if HAVE(COMPUTED_GOTO)
489 Opcode Machine::s_opcodeTable[numOpcodeIDs];
492 Opcode Machine::getOpcode(OpcodeID id)
494 #if HAVE(COMPUTED_GOTO)
495 return s_opcodeTable[id];
501 ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, JSValue* function)
503 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
504 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
505 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
506 callFrame[RegisterFile::CallerRegisters] = r;
507 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
508 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
509 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
510 callFrame[RegisterFile::Callee] = function;
511 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
514 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
516 size_t registerOffset = argv + newCodeBlock->numLocals;
517 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
519 if (argc == newCodeBlock->numParameters) { // correct number of arguments
520 if (!registerFile->grow(size)) {
521 exceptionValue = createStackOverflowError(exec);
525 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
526 if (!registerFile->grow(size)) {
527 exceptionValue = createStackOverflowError(exec);
532 int omittedArgCount = newCodeBlock->numParameters - argc;
533 Register* endOfParams = r - newCodeBlock->numVars;
534 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
535 (*it) = jsUndefined();
536 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
537 int shift = argc + RegisterFile::CallFrameHeaderSize;
538 registerOffset += shift;
541 if (!registerFile->grow(size)) {
542 exceptionValue = createStackOverflowError(exec);
547 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
548 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
549 for ( ; it != end; ++it)
553 // initialize local variable slots
555 if (!newCodeBlock->ctiCode)
564 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
566 if (newCodeBlock->needsFullScopeChain) {
567 JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
568 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
570 return callDataScopeChain->copy()->push(activation);
573 return callDataScopeChain;
576 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
578 if (value->isObject())
580 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
584 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
587 return jsUndefined();
589 JSValue* program = r[argv + 1].jsValue(exec);
591 if (!program->isString())
594 Profiler** profiler = Profiler::enabledProfilerReference();
596 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
598 UString programSource = static_cast<JSString*>(program)->value();
600 RefPtr<EvalNode> evalNode = callingCodeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
604 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
607 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
615 , m_ctiArrayLengthTrampoline(0)
616 , m_ctiStringLengthTrampoline(0)
617 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
621 , m_timeAtLastCheckTimeout(0)
623 , m_timeoutCheckCount(0)
624 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
626 privateExecute(InitializeAndReturn);
628 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
629 void* storage = fastMalloc(sizeof(CollectorBlock));
631 JSArray* jsArray = new (storage) JSArray(JSArray::createStructureID(jsNull()));
632 m_jsArrayVptr = jsArray->vptr();
633 static_cast<JSCell*>(jsArray)->~JSCell();
635 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
636 m_jsStringVptr = jsString->vptr();
637 static_cast<JSCell*>(jsString)->~JSCell();
639 JSFunction* jsFunction = new (storage) JSFunction(JSFunction::createStructureID(jsNull()));
640 m_jsFunctionVptr = jsFunction->vptr();
641 static_cast<JSCell*>(jsFunction)->~JSCell();
649 if (m_ctiArrayLengthTrampoline)
650 fastFree(m_ctiArrayLengthTrampoline);
651 if (m_ctiStringLengthTrampoline)
652 fastFree(m_ctiStringLengthTrampoline);
658 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
660 ScopeChain sc(scopeChain);
661 JSGlobalObject* globalObject = sc.globalObject();
662 codeBlock->dump(globalObject->globalExec());
663 dumpRegisters(codeBlock, registerFile, r);
666 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
668 printf("Register frame: \n\n");
669 printf("----------------------------------------------------\n");
670 printf(" use | address | value \n");
671 printf("----------------------------------------------------\n");
676 if (codeBlock->codeType == GlobalCode) {
677 it = registerFile->lastGlobal();
678 end = it + registerFile->numGlobals();
680 printf("[global var] | %10p | %10p \n", it, (*it).v());
683 printf("----------------------------------------------------\n");
686 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
687 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
688 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
689 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
690 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
691 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
692 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
693 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
694 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
695 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
696 printf("----------------------------------------------------\n");
698 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
699 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
702 printf("[param] | %10p | %10p \n", it, (*it).v());
706 printf("----------------------------------------------------\n");
708 if (codeBlock->codeType != GlobalCode) {
709 end = it + codeBlock->numVars;
712 printf("[var] | %10p | %10p \n", it, (*it).v());
715 printf("----------------------------------------------------\n");
719 end = it + codeBlock->numTemporaries;
722 printf("[temp] | %10p | %10p \n", it, (*it).v());
730 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
732 bool Machine::isOpcode(Opcode opcode)
734 #if HAVE(COMPUTED_GOTO)
735 return opcode != HashTraits<Opcode>::emptyValue()
736 && !HashTraits<Opcode>::isDeletedValue(opcode)
737 && m_opcodeIDTable.contains(opcode);
739 return opcode >= 0 && opcode <= op_end;
745 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
747 CodeBlock* oldCodeBlock = codeBlock;
748 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
750 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
751 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
752 if (callFrame[RegisterFile::Callee].jsValue(exec))
753 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
755 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
758 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
759 if (callFrame[RegisterFile::Callee].jsValue(exec))
760 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
762 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
765 if (oldCodeBlock->needsFullScopeChain)
768 // If this call frame created an activation, tear it off.
769 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
770 ASSERT(activation->isActivationObject());
771 activation->copyRegisters();
774 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
778 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
779 r = callFrame[RegisterFile::CallerRegisters].r();
780 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
781 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
786 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
788 // Set up the exception object
790 if (exceptionValue->isObject()) {
791 JSObject* exception = static_cast<JSObject*>(exceptionValue);
792 if (exception->isNotAnObjectErrorStub()) {
793 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
794 exceptionValue = exception;
796 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
797 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
798 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
799 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
800 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
801 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
806 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
807 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
809 // We only hit this path for error messages and throw statements, which don't have a specific failure position
810 // So we just give the full range of the error/throw statement.
811 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
812 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
814 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
815 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
816 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
819 if (exception->isWatchdogException()) {
820 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
821 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
828 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
829 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
830 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
833 // Calculate an exception handler vPC, unwinding call frames as necessary.
836 Instruction* handlerVPC;
838 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
839 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
843 // Now unwind the scope chain within the exception handler's call frame.
845 ScopeChain sc(scopeChain);
846 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
847 ASSERT(scopeDelta >= 0);
850 setScopeChain(exec, scopeChain, sc.node());
855 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
857 if (m_reentryDepth >= MaxReentryDepth) {
858 *exception = createStackOverflowError(exec);
862 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
864 size_t oldSize = m_registerFile.size();
865 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
866 if (!m_registerFile.grow(newSize)) {
867 *exception = createStackOverflowError(exec);
871 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
872 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
873 globalObject->copyGlobalsTo(m_registerFile);
875 Register* callFrame = m_registerFile.base() + oldSize;
877 // a 0 codeBlock indicates a built-in caller
878 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
880 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
881 r[codeBlock->thisRegister] = thisObj;
883 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
884 r[i] = codeBlock->constantRegisters[i];
886 if (codeBlock->needsFullScopeChain)
887 scopeChain = scopeChain->copy();
889 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
891 Profiler** profiler = Profiler::enabledProfilerReference();
893 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
897 if (!codeBlock->ctiCode)
898 CTI::compile(this, exec, codeBlock);
899 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
901 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
905 MACHINE_SAMPLING_privateExecuteReturned();
908 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
910 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
911 lastGlobalObject->copyGlobalsTo(m_registerFile);
913 m_registerFile.shrink(oldSize);
917 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
919 if (m_reentryDepth >= MaxReentryDepth) {
920 *exception = createStackOverflowError(exec);
924 int argv = RegisterFile::CallFrameHeaderSize;
925 int argc = args.size() + 1; // implicit "this" parameter
927 size_t oldSize = m_registerFile.size();
928 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
929 *exception = createStackOverflowError(exec);
933 Register* callFrame = m_registerFile.base() + oldSize;
935 // put args in place, including "this"
936 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
939 ArgList::const_iterator end = args.end();
940 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
943 // a 0 codeBlock indicates a built-in caller
944 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, function);
946 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
947 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
949 m_registerFile.shrink(oldSize);
953 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
955 Profiler** profiler = Profiler::enabledProfilerReference();
957 (*profiler)->willExecute(exec, function);
961 if (!newCodeBlock->ctiCode)
962 CTI::compile(this, exec, newCodeBlock);
963 JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
965 setScopeChain(&newExec, scopeChain, scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r));
966 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
970 MACHINE_SAMPLING_privateExecuteReturned();
972 m_registerFile.shrink(oldSize);
976 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
978 if (m_reentryDepth >= MaxReentryDepth) {
979 *exception = createStackOverflowError(exec);
983 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
985 JSVariableObject* variableObject;
986 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
988 if (node->object->isVariableObject()) {
989 variableObject = static_cast<JSVariableObject*>(node->object);
994 { // Scope for BatchedTransitionOptimizer
996 BatchedTransitionOptimizer optimizer(variableObject);
998 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
999 Node::VarStack::const_iterator varStackEnd = varStack.end();
1000 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
1001 const Identifier& ident = (*it).first;
1002 if (!variableObject->hasProperty(exec, ident)) {
1003 PutPropertySlot slot;
1004 variableObject->put(exec, ident, jsUndefined(), slot);
1008 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
1009 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
1010 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
1011 PutPropertySlot slot;
1012 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
1017 size_t oldSize = m_registerFile.size();
1018 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
1019 if (!m_registerFile.grow(newSize)) {
1020 *exception = createStackOverflowError(exec);
1024 Register* callFrame = m_registerFile.base() + registerOffset;
1026 // a 0 codeBlock indicates a built-in caller
1027 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
1029 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
1030 r[codeBlock->thisRegister] = thisObj;
1032 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
1033 r[i] = codeBlock->constantRegisters[i];
1035 if (codeBlock->needsFullScopeChain)
1036 scopeChain = scopeChain->copy();
1038 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
1040 Profiler** profiler = Profiler::enabledProfilerReference();
1042 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1046 if (!codeBlock->ctiCode)
1047 CTI::compile(this, exec, codeBlock);
1048 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
1050 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
1054 MACHINE_SAMPLING_privateExecuteReturned();
1057 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1059 m_registerFile.shrink(oldSize);
1063 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
1065 scopeChain = newScopeChain;
1066 exec->m_scopeChain = newScopeChain;
1069 NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
1071 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
1075 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
1077 switch (debugHookID) {
1078 case DidEnterCallFrame:
1079 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1081 case WillLeaveCallFrame:
1082 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1084 case WillExecuteStatement:
1085 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1087 case WillExecuteProgram:
1088 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1090 case DidExecuteProgram:
1091 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1093 case DidReachBreakpoint:
1094 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1099 void Machine::resetTimeoutCheck()
1101 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1102 m_timeAtLastCheckTimeout = 0;
1103 m_timeExecuting = 0;
1106 // Returns the time the current thread has spent executing, in milliseconds.
1107 static inline unsigned getCPUTime()
1109 #if PLATFORM(DARWIN)
1110 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1111 thread_basic_info_data_t info;
1113 // Get thread information
1114 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1116 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1117 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1120 #elif HAVE(SYS_TIME_H)
1121 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1123 gettimeofday(&tv, 0);
1124 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1126 QDateTime t = QDateTime::currentDateTime();
1127 return t.toTime_t() * 1000 + t.time().msec();
1128 #elif PLATFORM(WIN_OS)
1131 unsigned long long fileTimeAsLong;
1132 } userTime, kernelTime;
1134 // GetThreadTimes won't accept NULL arguments so we pass these even though
1135 // they're not used.
1136 FILETIME creationTime, exitTime;
1138 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1140 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1142 #error Platform does not have getCurrentTime function
1146 // We have to return a JSValue here, gcc seems to produce worse code if
1147 // we attempt to return a bool
1148 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1150 unsigned currentTime = getCPUTime();
1152 if (!m_timeAtLastCheckTimeout) {
1153 // Suspicious amount of looping in a script -- start timing it
1154 m_timeAtLastCheckTimeout = currentTime;
1158 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1163 m_timeExecuting += timeDiff;
1164 m_timeAtLastCheckTimeout = currentTime;
1166 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1167 // preferredScriptCheckTimeInterval
1168 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1169 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1170 // preferred script check time interval.
1171 if (m_ticksUntilNextTimeoutCheck == 0)
1172 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1174 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1175 if (globalObject->shouldInterruptScript())
1176 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1178 resetTimeoutCheck();
1184 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1186 int dst = (++vPC)->u.operand;
1187 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1188 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1189 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1191 return scopeChain->push(scope);
1194 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1196 JSValue* prototype = structureID->prototypeForLookup(exec);
1197 if (JSImmediate::isImmediate(prototype))
1199 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(prototype)->structureID());
1200 structureID->setCachedPrototypeChain(chain.release());
1201 return structureID->cachedPrototypeChain();
1204 NEVER_INLINE void Machine::tryCachePutByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1206 // Recursive invocation may already have specialized this instruction.
1207 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1210 if (JSImmediate::isImmediate(baseValue))
1213 // Uncacheable: give up.
1214 if (!slot.isCacheable()) {
1215 vPC[0] = getOpcode(op_put_by_id_generic);
1219 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1220 StructureID* structureID = baseCell->structureID();
1222 if (structureID->isDictionary()) {
1223 vPC[0] = getOpcode(op_put_by_id_generic);
1227 // Cache miss: record StructureID to compare against next time.
1228 StructureID* lastStructureID = vPC[4].u.structureID;
1229 if (structureID != lastStructureID) {
1230 // First miss: record StructureID to compare against next time.
1231 if (!lastStructureID) {
1232 vPC[4] = structureID;
1236 // Second miss: give up.
1237 vPC[0] = getOpcode(op_put_by_id_generic);
1241 // Cache hit: Specialize instruction and ref StructureIDs.
1243 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1244 if (baseCell != slot.base()) {
1245 vPC[0] = getOpcode(op_put_by_id_generic);
1249 // StructureID transition, cache transition info
1250 if (slot.type() == PutPropertySlot::NewProperty) {
1251 vPC[0] = getOpcode(op_put_by_id_transition);
1252 vPC[4] = structureID->previousID();
1253 vPC[5] = structureID;
1254 StructureIDChain* chain = structureID->cachedPrototypeChain();
1256 chain = cachePrototypeChain(exec, structureID);
1258 // This happens if someone has manually inserted null into the prototype chain
1259 vPC[0] = getOpcode(op_put_by_id_generic);
1264 vPC[7] = slot.cachedOffset();
1265 codeBlock->refStructureIDs(vPC);
1269 vPC[0] = getOpcode(op_put_by_id_replace);
1270 vPC[5] = slot.cachedOffset();
1271 codeBlock->refStructureIDs(vPC);
1274 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1276 codeBlock->derefStructureIDs(vPC);
1277 vPC[0] = getOpcode(op_put_by_id);
1281 NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1283 // Recursive invocation may already have specialized this instruction.
1284 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1287 // FIXME: Cache property access for immediates.
1288 if (JSImmediate::isImmediate(baseValue)) {
1289 vPC[0] = getOpcode(op_get_by_id_generic);
1293 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1294 vPC[0] = getOpcode(op_get_array_length);
1298 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1299 vPC[0] = getOpcode(op_get_string_length);
1303 // Uncacheable: give up.
1304 if (!slot.isCacheable()) {
1305 vPC[0] = getOpcode(op_get_by_id_generic);
1309 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1311 if (structureID->isDictionary()) {
1312 vPC[0] = getOpcode(op_get_by_id_generic);
1317 StructureID* lastStructureID = vPC[4].u.structureID;
1318 if (structureID != lastStructureID) {
1319 // First miss: record StructureID to compare against next time.
1320 if (!lastStructureID) {
1321 vPC[4] = structureID;
1325 // Second miss: give up.
1326 vPC[0] = getOpcode(op_get_by_id_generic);
1330 // Cache hit: Specialize instruction and ref StructureIDs.
1332 if (slot.slotBase() == baseValue) {
1333 vPC[0] = getOpcode(op_get_by_id_self);
1334 vPC[5] = slot.cachedOffset();
1336 codeBlock->refStructureIDs(vPC);
1340 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1341 ASSERT(slot.slotBase()->isObject());
1343 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1345 // Heavy access to a prototype is a good indication that it's not being
1346 // used as a dictionary.
1347 if (baseObject->structureID()->isDictionary()) {
1348 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1349 baseObject->setStructureID(transition.release());
1350 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1353 vPC[0] = getOpcode(op_get_by_id_proto);
1354 vPC[5] = baseObject->structureID();
1355 vPC[6] = slot.cachedOffset();
1357 codeBlock->refStructureIDs(vPC);
1362 JSObject* o = static_cast<JSObject*>(baseValue);
1363 while (slot.slotBase() != o) {
1364 JSValue* v = o->structureID()->prototypeForLookup(exec);
1366 // If we didn't find base in baseValue's prototype chain, then baseValue
1367 // must be a proxy for another object.
1369 vPC[0] = getOpcode(op_get_by_id_generic);
1373 o = static_cast<JSObject*>(v);
1375 // Heavy access to a prototype is a good indication that it's not being
1376 // used as a dictionary.
1377 if (o->structureID()->isDictionary()) {
1378 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1379 o->setStructureID(transition.release());
1380 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1386 StructureIDChain* chain = structureID->cachedPrototypeChain();
1388 chain = cachePrototypeChain(exec, structureID);
1391 vPC[0] = getOpcode(op_get_by_id_chain);
1392 vPC[4] = structureID;
1395 vPC[7] = slot.cachedOffset();
1396 codeBlock->refStructureIDs(vPC);
1399 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1401 codeBlock->derefStructureIDs(vPC);
1402 vPC[0] = getOpcode(op_get_by_id);
1406 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1408 // One-time initialization of our address tables. We have to put this code
1409 // here because our labels are only in scope inside this function.
1410 if (flag == InitializeAndReturn) {
1411 #if HAVE(COMPUTED_GOTO)
1412 #define ADD_OPCODE(id) s_opcodeTable[id] = &&id;
1413 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1416 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1417 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1418 #undef ADD_OPCODE_ID
1419 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1420 op_throw_end_indirect = &&op_throw_end;
1421 op_call_indirect = &&op_call;
1422 #endif // HAVE(COMPUTED_GOTO)
1427 // Currently with CTI enabled we never interpret functions
1428 ASSERT_NOT_REACHED();
1431 JSValue* exceptionValue = 0;
1432 Instruction* handlerVPC = 0;
1434 Register* registerBase = registerFile->base();
1435 Instruction* vPC = codeBlock->instructions.begin();
1436 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1437 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1439 #define VM_CHECK_EXCEPTION() \
1441 if (UNLIKELY(exec->hadException())) { \
1442 exceptionValue = exec->exception(); \
1447 #if DUMP_OPCODE_STATS
1448 OpcodeStats::resetLastInstruction();
1451 #define CHECK_FOR_TIMEOUT() \
1452 if (!--tickCount) { \
1453 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1455 tickCount = m_ticksUntilNextTimeoutCheck; \
1458 #if HAVE(COMPUTED_GOTO)
1459 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1460 #if DUMP_OPCODE_STATS
1461 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1463 #define BEGIN_OPCODE(opcode) opcode:
1467 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1468 #if DUMP_OPCODE_STATS
1469 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1471 #define BEGIN_OPCODE(opcode) case opcode:
1473 while (1) // iterator loop begins
1474 switch (vPC->u.opcode)
1477 BEGIN_OPCODE(op_new_object) {
1478 /* new_object dst(r)
1480 Constructs a new empty Object instance using the original
1481 constructor, and puts the result in register dst.
1483 int dst = (++vPC)->u.operand;
1484 r[dst] = constructEmptyObject(exec);
1489 BEGIN_OPCODE(op_new_array) {
1490 /* new_array dst(r) firstArg(r) argCount(n)
1492 Constructs a new Array instance using the original
1493 constructor, and puts the result in register dst.
1494 The array will contain argCount elements with values
1495 taken from registers starting at register firstArg.
1497 int dst = (++vPC)->u.operand;
1498 int firstArg = (++vPC)->u.operand;
1499 int argCount = (++vPC)->u.operand;
1500 ArgList args(r + firstArg, argCount);
1501 r[dst] = constructArray(exec, args);
1506 BEGIN_OPCODE(op_new_regexp) {
1507 /* new_regexp dst(r) regExp(re)
1509 Constructs a new RegExp instance using the original
1510 constructor from regexp regExp, and puts the result in
1513 int dst = (++vPC)->u.operand;
1514 int regExp = (++vPC)->u.operand;
1515 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpStructure(), codeBlock->regexps[regExp]);
1520 BEGIN_OPCODE(op_mov) {
1521 /* mov dst(r) src(r)
1523 Copies register src to register dst.
1525 int dst = (++vPC)->u.operand;
1526 int src = (++vPC)->u.operand;
1532 BEGIN_OPCODE(op_eq) {
1533 /* eq dst(r) src1(r) src2(r)
1535 Checks whether register src1 and register src2 are equal,
1536 as with the ECMAScript '==' operator, and puts the result
1537 as a boolean in register dst.
1539 int dst = (++vPC)->u.operand;
1540 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1541 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1542 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1543 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1545 JSValue* result = jsBoolean(equal(exec, src1, src2));
1546 VM_CHECK_EXCEPTION();
1553 BEGIN_OPCODE(op_eq_null) {
1554 /* neq dst(r) src(r)
1556 Checks whether register src is null, as with the ECMAScript '!='
1557 operator, and puts the result as a boolean in register dst.
1559 int dst = (++vPC)->u.operand;
1560 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1562 if (src->isUndefinedOrNull()) {
1563 r[dst] = jsBoolean(true);
1568 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && src->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
1572 BEGIN_OPCODE(op_neq) {
1573 /* neq dst(r) src1(r) src2(r)
1575 Checks whether register src1 and register src2 are not
1576 equal, as with the ECMAScript '!=' operator, and puts the
1577 result as a boolean in register dst.
1579 int dst = (++vPC)->u.operand;
1580 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1581 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1582 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1583 r[dst] = jsBoolean(src1 != src2);
1585 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1586 VM_CHECK_EXCEPTION();
1593 BEGIN_OPCODE(op_neq_null) {
1594 /* neq dst(r) src(r)
1596 Checks whether register src is not null, as with the ECMAScript '!='
1597 operator, and puts the result as a boolean in register dst.
1599 int dst = (++vPC)->u.operand;
1600 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1602 if (src->isUndefinedOrNull()) {
1603 r[dst] = jsBoolean(false);
1608 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
1612 BEGIN_OPCODE(op_stricteq) {
1613 /* stricteq dst(r) src1(r) src2(r)
1615 Checks whether register src1 and register src2 are strictly
1616 equal, as with the ECMAScript '===' operator, and puts the
1617 result as a boolean in register dst.
1619 int dst = (++vPC)->u.operand;
1620 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1621 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1622 if (JSImmediate::areBothImmediate(src1, src2))
1623 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1624 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1625 r[dst] = jsBoolean(false);
1627 r[dst] = jsBoolean(strictEqualSlowCase(src1, src2));
1632 BEGIN_OPCODE(op_nstricteq) {
1633 /* nstricteq dst(r) src1(r) src2(r)
1635 Checks whether register src1 and register src2 are not
1636 strictly equal, as with the ECMAScript '!==' operator, and
1637 puts the result as a boolean in register dst.
1639 int dst = (++vPC)->u.operand;
1640 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1641 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1643 if (JSImmediate::areBothImmediate(src1, src2))
1644 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1645 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1646 r[dst] = jsBoolean(true);
1648 r[dst] = jsBoolean(!strictEqualSlowCase(src1, src2));
1653 BEGIN_OPCODE(op_less) {
1654 /* less dst(r) src1(r) src2(r)
1656 Checks whether register src1 is less than register src2, as
1657 with the ECMAScript '<' operator, and puts the result as
1658 a boolean in register dst.
1660 int dst = (++vPC)->u.operand;
1661 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1662 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1663 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1664 VM_CHECK_EXCEPTION();
1670 BEGIN_OPCODE(op_lesseq) {
1671 /* lesseq dst(r) src1(r) src2(r)
1673 Checks whether register src1 is less than or equal to
1674 register src2, as with the ECMAScript '<=' operator, and
1675 puts the result as a boolean in register dst.
1677 int dst = (++vPC)->u.operand;
1678 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1679 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1680 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1681 VM_CHECK_EXCEPTION();
1687 BEGIN_OPCODE(op_pre_inc) {
1688 /* pre_inc srcDst(r)
1690 Converts register srcDst to number, adds one, and puts the result
1691 back in register srcDst.
1693 int srcDst = (++vPC)->u.operand;
1694 JSValue* v = r[srcDst].jsValue(exec);
1695 if (JSImmediate::canDoFastAdditiveOperations(v))
1696 r[srcDst] = JSImmediate::incImmediateNumber(v);
1698 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1699 VM_CHECK_EXCEPTION();
1706 BEGIN_OPCODE(op_pre_dec) {
1707 /* pre_dec srcDst(r)
1709 Converts register srcDst to number, subtracts one, and puts the result
1710 back in register srcDst.
1712 int srcDst = (++vPC)->u.operand;
1713 JSValue* v = r[srcDst].jsValue(exec);
1714 if (JSImmediate::canDoFastAdditiveOperations(v))
1715 r[srcDst] = JSImmediate::decImmediateNumber(v);
1717 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1718 VM_CHECK_EXCEPTION();
1725 BEGIN_OPCODE(op_post_inc) {
1726 /* post_inc dst(r) srcDst(r)
1728 Converts register srcDst to number. The number itself is
1729 written to register dst, and the number plus one is written
1730 back to register srcDst.
1732 int dst = (++vPC)->u.operand;
1733 int srcDst = (++vPC)->u.operand;
1734 JSValue* v = r[srcDst].jsValue(exec);
1735 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1737 r[srcDst] = JSImmediate::incImmediateNumber(v);
1739 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1740 VM_CHECK_EXCEPTION();
1742 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1748 BEGIN_OPCODE(op_post_dec) {
1749 /* post_dec dst(r) srcDst(r)
1751 Converts register srcDst to number. The number itself is
1752 written to register dst, and the number minus one is written
1753 back to register srcDst.
1755 int dst = (++vPC)->u.operand;
1756 int srcDst = (++vPC)->u.operand;
1757 JSValue* v = r[srcDst].jsValue(exec);
1758 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1760 r[srcDst] = JSImmediate::decImmediateNumber(v);
1762 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1763 VM_CHECK_EXCEPTION();
1765 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1771 BEGIN_OPCODE(op_to_jsnumber) {
1772 /* to_jsnumber dst(r) src(r)
1774 Converts register src to number, and puts the result
1777 int dst = (++vPC)->u.operand;
1778 int src = (++vPC)->u.operand;
1779 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1780 VM_CHECK_EXCEPTION();
1787 BEGIN_OPCODE(op_negate) {
1788 /* negate dst(r) src(r)
1790 Converts register src to number, negates it, and puts the
1791 result in register dst.
1793 int dst = (++vPC)->u.operand;
1794 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1796 if (fastIsNumber(src, v))
1797 r[dst] = jsNumber(exec, -v);
1799 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1800 VM_CHECK_EXCEPTION();
1807 BEGIN_OPCODE(op_add) {
1808 /* add dst(r) src1(r) src2(r)
1810 Adds register src1 and register src2, and puts the result
1811 in register dst. (JS add may be string concatenation or
1812 numeric add, depending on the types of the operands.)
1814 int dst = (++vPC)->u.operand;
1815 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1816 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1817 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1818 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1820 JSValue* result = jsAdd(exec, src1, src2);
1821 VM_CHECK_EXCEPTION();
1827 BEGIN_OPCODE(op_mul) {
1828 /* mul dst(r) src1(r) src2(r)
1830 Multiplies register src1 and register src2 (converted to
1831 numbers), and puts the product in register dst.
1833 int dst = (++vPC)->u.operand;
1834 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1835 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1838 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1839 r[dst] = jsNumber(exec, left * right);
1841 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1842 VM_CHECK_EXCEPTION();
1849 BEGIN_OPCODE(op_div) {
1850 /* div dst(r) dividend(r) divisor(r)
1852 Divides register dividend (converted to number) by the
1853 register divisor (converted to number), and puts the
1854 quotient in register dst.
1856 int dst = (++vPC)->u.operand;
1857 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1858 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1861 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1862 r[dst] = jsNumber(exec, left / right);
1864 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1865 VM_CHECK_EXCEPTION();
1871 BEGIN_OPCODE(op_mod) {
1872 /* mod dst(r) dividend(r) divisor(r)
1874 Divides register dividend (converted to number) by
1875 register divisor (converted to number), and puts the
1876 remainder in register dst.
1878 int dst = (++vPC)->u.operand;
1879 int dividend = (++vPC)->u.operand;
1880 int divisor = (++vPC)->u.operand;
1882 JSValue* dividendValue = r[dividend].jsValue(exec);
1883 JSValue* divisorValue = r[divisor].jsValue(exec);
1885 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1886 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1891 double d = dividendValue->toNumber(exec);
1892 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1893 VM_CHECK_EXCEPTION();
1898 BEGIN_OPCODE(op_sub) {
1899 /* sub dst(r) src1(r) src2(r)
1901 Subtracts register src2 (converted to number) from register
1902 src1 (converted to number), and puts the difference in
1905 int dst = (++vPC)->u.operand;
1906 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1907 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1910 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1911 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1912 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1913 r[dst] = jsNumber(exec, left - right);
1915 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1916 VM_CHECK_EXCEPTION();
1922 BEGIN_OPCODE(op_lshift) {
1923 /* lshift dst(r) val(r) shift(r)
1925 Performs left shift of register val (converted to int32) by
1926 register shift (converted to uint32), and puts the result
1929 int dst = (++vPC)->u.operand;
1930 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1931 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1934 if (JSImmediate::areBothImmediateNumbers(val, shift))
1935 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1936 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1937 r[dst] = jsNumber(exec, left << (right & 0x1f));
1939 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1940 VM_CHECK_EXCEPTION();
1947 BEGIN_OPCODE(op_rshift) {
1948 /* rshift dst(r) val(r) shift(r)
1950 Performs arithmetic right shift of register val (converted
1951 to int32) by register shift (converted to
1952 uint32), and puts the result in register dst.
1954 int dst = (++vPC)->u.operand;
1955 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1956 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1959 if (JSImmediate::areBothImmediateNumbers(val, shift))
1960 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1961 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1962 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1964 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1965 VM_CHECK_EXCEPTION();
1972 BEGIN_OPCODE(op_urshift) {
1973 /* rshift dst(r) val(r) shift(r)
1975 Performs logical right shift of register val (converted
1976 to uint32) by register shift (converted to
1977 uint32), and puts the result in register dst.
1979 int dst = (++vPC)->u.operand;
1980 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1981 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1982 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1983 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1985 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1986 VM_CHECK_EXCEPTION();
1993 BEGIN_OPCODE(op_bitand) {
1994 /* bitand dst(r) src1(r) src2(r)
1996 Computes bitwise AND of register src1 (converted to int32)
1997 and register src2 (converted to int32), and puts the result
2000 int dst = (++vPC)->u.operand;
2001 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2002 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2005 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2006 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
2007 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2008 r[dst] = jsNumber(exec, left & right);
2010 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
2011 VM_CHECK_EXCEPTION();
2018 BEGIN_OPCODE(op_bitxor) {
2019 /* bitxor dst(r) src1(r) src2(r)
2021 Computes bitwise XOR of register src1 (converted to int32)
2022 and register src2 (converted to int32), and puts the result
2025 int dst = (++vPC)->u.operand;
2026 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2027 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2030 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2031 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
2032 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2033 r[dst] = jsNumber(exec, left ^ right);
2035 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
2036 VM_CHECK_EXCEPTION();
2043 BEGIN_OPCODE(op_bitor) {
2044 /* bitor dst(r) src1(r) src2(r)
2046 Computes bitwise OR of register src1 (converted to int32)
2047 and register src2 (converted to int32), and puts the
2048 result in register dst.
2050 int dst = (++vPC)->u.operand;
2051 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2052 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2055 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2056 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
2057 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2058 r[dst] = jsNumber(exec, left | right);
2060 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
2061 VM_CHECK_EXCEPTION();
2068 BEGIN_OPCODE(op_bitnot) {
2069 /* bitnot dst(r) src(r)
2071 Computes bitwise NOT of register src1 (converted to int32),
2072 and puts the result in register dst.
2074 int dst = (++vPC)->u.operand;
2075 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
2077 if (fastToInt32(src, value))
2078 r[dst] = jsNumber(exec, ~value);
2080 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
2081 VM_CHECK_EXCEPTION();
2087 BEGIN_OPCODE(op_not) {
2088 /* not dst(r) src(r)
2090 Computes logical NOT of register src (converted to
2091 boolean), and puts the result in register dst.
2093 int dst = (++vPC)->u.operand;
2094 int src = (++vPC)->u.operand;
2095 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
2096 VM_CHECK_EXCEPTION();
2102 BEGIN_OPCODE(op_instanceof) {
2103 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2105 Tests whether register value is an instance of register
2106 constructor, and puts the boolean result in register
2107 dst. Register constructorProto must contain the "prototype"
2108 property (not the actual prototype) of the object in
2109 register constructor. This lookup is separated so that
2110 polymorphic inline caching can apply.
2112 Raises an exception if register constructor is not an
2115 int dst = (++vPC)->u.operand;
2116 int value = (++vPC)->u.operand;
2117 int base = (++vPC)->u.operand;
2118 int baseProto = (++vPC)->u.operand;
2120 JSValue* baseVal = r[base].jsValue(exec);
2122 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
2125 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2126 r[dst] = jsBoolean(baseObj->structureID()->typeInfo().implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec), r[baseProto].jsValue(exec)) : false);
2131 BEGIN_OPCODE(op_typeof) {
2132 /* typeof dst(r) src(r)
2134 Determines the type string for src according to ECMAScript
2135 rules, and puts the result in register dst.
2137 int dst = (++vPC)->u.operand;
2138 int src = (++vPC)->u.operand;
2139 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2144 BEGIN_OPCODE(op_is_undefined) {
2145 /* is_undefined dst(r) src(r)
2147 Determines whether the type string for src according to
2148 the ECMAScript rules is "undefined", and puts the result
2151 int dst = (++vPC)->u.operand;
2152 int src = (++vPC)->u.operand;
2153 JSValue* v = r[src].jsValue(exec);
2154 r[dst] = jsBoolean(JSImmediate::isImmediate(v) ? v->isUndefined() : v->asCell()->structureID()->typeInfo().masqueradesAsUndefined());
2159 BEGIN_OPCODE(op_is_boolean) {
2160 /* is_boolean dst(r) src(r)
2162 Determines whether the type string for src according to
2163 the ECMAScript rules is "boolean", and puts the result
2166 int dst = (++vPC)->u.operand;
2167 int src = (++vPC)->u.operand;
2168 r[dst] = jsBoolean(r[src].jsValue(exec)->isBoolean());
2173 BEGIN_OPCODE(op_is_number) {
2174 /* is_number dst(r) src(r)
2176 Determines whether the type string for src according to
2177 the ECMAScript rules is "number", and puts the result
2180 int dst = (++vPC)->u.operand;
2181 int src = (++vPC)->u.operand;
2182 r[dst] = jsBoolean(r[src].jsValue(exec)->isNumber());
2187 BEGIN_OPCODE(op_is_string) {
2188 /* is_string dst(r) src(r)
2190 Determines whether the type string for src according to
2191 the ECMAScript rules is "string", and puts the result
2194 int dst = (++vPC)->u.operand;
2195 int src = (++vPC)->u.operand;
2196 r[dst] = jsBoolean(r[src].jsValue(exec)->isString());
2201 BEGIN_OPCODE(op_is_object) {
2202 /* is_object dst(r) src(r)
2204 Determines whether the type string for src according to
2205 the ECMAScript rules is "object", and puts the result
2208 int dst = (++vPC)->u.operand;
2209 int src = (++vPC)->u.operand;
2210 r[dst] = jsBoolean(jsIsObjectType(r[src].jsValue(exec)));
2215 BEGIN_OPCODE(op_is_function) {
2216 /* is_function dst(r) src(r)
2218 Determines whether the type string for src according to
2219 the ECMAScript rules is "function", and puts the result
2222 int dst = (++vPC)->u.operand;
2223 int src = (++vPC)->u.operand;
2224 r[dst] = jsBoolean(jsIsFunctionType(r[src].jsValue(exec)));
2229 BEGIN_OPCODE(op_in) {
2230 /* in dst(r) property(r) base(r)
2232 Tests whether register base has a property named register
2233 property, and puts the boolean result in register dst.
2235 Raises an exception if register constructor is not an
2238 int dst = (++vPC)->u.operand;
2239 int property = (++vPC)->u.operand;
2240 int base = (++vPC)->u.operand;
2242 JSValue* baseVal = r[base].jsValue(exec);
2243 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
2246 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2248 JSValue* propName = r[property].jsValue(exec);
2251 if (propName->getUInt32(i))
2252 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2254 Identifier property(exec, propName->toString(exec));
2255 VM_CHECK_EXCEPTION();
2256 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2262 BEGIN_OPCODE(op_resolve) {
2263 /* resolve dst(r) property(id)
2265 Looks up the property named by identifier property in the
2266 scope chain, and writes the resulting value to register
2267 dst. If the property is not found, raises an exception.
2269 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2275 BEGIN_OPCODE(op_resolve_skip) {
2276 /* resolve_skip dst(r) property(id) skip(n)
2278 Looks up the property named by identifier property in the
2279 scope chain skipping the top 'skip' levels, and writes the resulting
2280 value to register dst. If the property is not found, raises an exception.
2282 if (UNLIKELY(!resolveSkip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2289 BEGIN_OPCODE(op_resolve_global) {
2290 /* resolve_skip dst(r) globalObject(c) property(id) structureID(sID) offset(n)
2292 Performs a dynamic property lookup for the given property, on the provided
2293 global object. If structureID matches the StructureID of the global then perform
2294 a fast lookup using the case offset, otherwise fall back to a full resolve and
2295 cache the new structureID and offset
2297 if (UNLIKELY(!resolveGlobal(exec, vPC, r, codeBlock, exceptionValue)))
2304 BEGIN_OPCODE(op_get_global_var) {
2305 /* get_global_var dst(r) globalObject(c) index(n)
2307 Gets the global var at global slot index and places it in register dst.
2309 int dst = (++vPC)->u.operand;
2310 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2311 ASSERT(scope->isGlobalObject());
2312 int index = (++vPC)->u.operand;
2314 r[dst] = scope->registerAt(index);
2318 BEGIN_OPCODE(op_put_global_var) {
2319 /* put_global_var globalObject(c) index(n) value(r)
2321 Puts value into global slot index.
2323 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2324 ASSERT(scope->isGlobalObject());
2325 int index = (++vPC)->u.operand;
2326 int value = (++vPC)->u.operand;
2328 scope->registerAt(index) = r[value].jsValue(exec);
2332 BEGIN_OPCODE(op_get_scoped_var) {
2333 /* get_scoped_var dst(r) index(n) skip(n)
2335 Loads the contents of the index-th local from the scope skip nodes from
2336 the top of the scope chain, and places it in register dst
2338 int dst = (++vPC)->u.operand;
2339 int index = (++vPC)->u.operand;
2340 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2342 ScopeChainIterator iter = scopeChain->begin();
2343 ScopeChainIterator end = scopeChain->end();
2344 ASSERT(iter != end);
2347 ASSERT(iter != end);
2350 ASSERT((*iter)->isVariableObject());
2351 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2352 r[dst] = scope->registerAt(index);
2356 BEGIN_OPCODE(op_put_scoped_var) {
2357 /* put_scoped_var index(n) skip(n) value(r)
2360 int index = (++vPC)->u.operand;
2361 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2362 int value = (++vPC)->u.operand;
2364 ScopeChainIterator iter = scopeChain->begin();
2365 ScopeChainIterator end = scopeChain->end();
2366 ASSERT(iter != end);
2369 ASSERT(iter != end);
2372 ASSERT((*iter)->isVariableObject());
2373 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2374 scope->registerAt(index) = r[value].jsValue(exec);
2378 BEGIN_OPCODE(op_resolve_base) {
2379 /* resolve_base dst(r) property(id)
2381 Searches the scope chain for an object containing
2382 identifier property, and if one is found, writes it to
2383 register dst. If none is found, the outermost scope (which
2384 will be the global object) is stored in register dst.
2386 resolveBase(exec, vPC, r, scopeChain, codeBlock);
2391 BEGIN_OPCODE(op_resolve_with_base) {
2392 /* resolve_with_base baseDst(r) propDst(r) property(id)
2394 Searches the scope chain for an object containing
2395 identifier property, and if one is found, writes it to
2396 register srcDst, and the retrieved property value to register
2397 propDst. If the property is not found, raises an exception.
2399 This is more efficient than doing resolve_base followed by
2400 resolve, or resolve_base followed by get_by_id, as it
2401 avoids duplicate hash lookups.
2403 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2409 BEGIN_OPCODE(op_resolve_func) {
2410 /* resolve_func baseDst(r) funcDst(r) property(id)
2412 Searches the scope chain for an object containing
2413 identifier property, and if one is found, writes the
2414 appropriate object to use as "this" when calling its
2415 properties to register baseDst; and the retrieved property
2416 value to register propDst. If the property is not found,
2417 raises an exception.
2419 This differs from resolve_with_base, because the
2420 global this value will be substituted for activations or
2421 the global object, which is the right behavior for function
2422 calls but not for other property lookup.
2424 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2430 BEGIN_OPCODE(op_get_by_id) {
2431 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2433 Generic property access: Gets the property named by identifier
2434 property from the value base, and puts the result in register dst.
2436 int dst = vPC[1].u.operand;
2437 int base = vPC[2].u.operand;
2438 int property = vPC[3].u.operand;
2440 Identifier& ident = codeBlock->identifiers[property];
2441 JSValue* baseValue = r[base].jsValue(exec);
2442 PropertySlot slot(baseValue);
2443 JSValue* result = baseValue->get(exec, ident, slot);
2444 VM_CHECK_EXCEPTION();
2446 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2452 BEGIN_OPCODE(op_get_by_id_self) {
2453 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2455 Cached property access: Attempts to get a cached property from the
2456 value base. If the cache misses, op_get_by_id_self reverts to
2459 int base = vPC[2].u.operand;
2460 JSValue* baseValue = r[base].jsValue(exec);
2462 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2463 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2464 StructureID* structureID = vPC[4].u.structureID;
2466 if (LIKELY(baseCell->structureID() == structureID)) {
2467 ASSERT(baseCell->isObject());
2468 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2469 int dst = vPC[1].u.operand;
2470 int offset = vPC[5].u.operand;
2472 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2473 r[dst] = baseObject->getDirectOffset(offset);
2480 uncacheGetByID(codeBlock, vPC);
2483 BEGIN_OPCODE(op_get_by_id_proto) {
2484 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2486 Cached property access: Attempts to get a cached property from the
2487 value base's prototype. If the cache misses, op_get_by_id_proto
2488 reverts to op_get_by_id.
2490 int base = vPC[2].u.operand;
2491 JSValue* baseValue = r[base].jsValue(exec);
2493 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2494 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2495 StructureID* structureID = vPC[4].u.structureID;
2497 if (LIKELY(baseCell->structureID() == structureID)) {
2498 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2499 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2500 StructureID* protoStructureID = vPC[5].u.structureID;
2502 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2503 int dst = vPC[1].u.operand;
2504 int offset = vPC[6].u.operand;
2506 ASSERT(protoObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2507 r[dst] = protoObject->getDirectOffset(offset);
2515 uncacheGetByID(codeBlock, vPC);
2518 BEGIN_OPCODE(op_get_by_id_chain) {
2519 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2521 Cached property access: Attempts to get a cached property from the
2522 value base's prototype chain. If the cache misses, op_get_by_id_chain
2523 reverts to op_get_by_id.
2525 int base = vPC[2].u.operand;
2526 JSValue* baseValue = r[base].jsValue(exec);
2528 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2529 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2530 StructureID* structureID = vPC[4].u.structureID;
2532 if (LIKELY(baseCell->structureID() == structureID)) {
2533 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2534 size_t count = vPC[6].u.operand;
2535 RefPtr<StructureID>* end = it + count;
2537 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2539 baseObject = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2540 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2544 int dst = vPC[1].u.operand;
2545 int offset = vPC[7].u.operand;
2547 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2548 r[dst] = baseObject->getDirectOffset(offset);
2557 uncacheGetByID(codeBlock, vPC);
2560 BEGIN_OPCODE(op_get_by_id_generic) {
2561 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2563 Generic property access: Gets the property named by identifier
2564 property from the value base, and puts the result in register dst.
2566 int dst = vPC[1].u.operand;
2567 int base = vPC[2].u.operand;
2568 int property = vPC[3].u.operand;
2570 Identifier& ident = codeBlock->identifiers[property];
2572 JSValue* baseValue = r[base].jsValue(exec);
2573 PropertySlot slot(baseValue);
2574 JSValue* result = baseValue->get(exec, ident, slot);
2575 VM_CHECK_EXCEPTION();
2581 BEGIN_OPCODE(op_get_array_length) {
2582 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2584 Cached property access: Gets the length of the array in register base,
2585 and puts the result in register dst. If register base does not hold
2586 an array, op_get_array_length reverts to op_get_by_id.
2589 int base = vPC[2].u.operand;
2590 JSValue* baseValue = r[base].jsValue(exec);
2591 if (LIKELY(isJSArray(baseValue))) {
2592 int dst = vPC[1].u.operand;
2593 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2598 uncacheGetByID(codeBlock, vPC);
2601 BEGIN_OPCODE(op_get_string_length) {
2602 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2604 Cached property access: Gets the length of the string in register base,
2605 and puts the result in register dst. If register base does not hold
2606 a string, op_get_string_length reverts to op_get_by_id.
2609 int base = vPC[2].u.operand;
2610 JSValue* baseValue = r[base].jsValue(exec);
2611 if (LIKELY(isJSString(baseValue))) {
2612 int dst = vPC[1].u.operand;
2613 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2618 uncacheGetByID(codeBlock, vPC);
2621 BEGIN_OPCODE(op_put_by_id) {
2622 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2624 Generic property access: Sets the property named by identifier
2625 property, belonging to register base, to register value.
2627 Unlike many opcodes, this one does not write any output to
2631 int base = vPC[1].u.operand;
2632 int property = vPC[2].u.operand;
2633 int value = vPC[3].u.operand;
2635 JSValue* baseValue = r[base].jsValue(exec);
2637 PutPropertySlot slot;
2638 Identifier& ident = codeBlock->identifiers[property];
2639 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2640 VM_CHECK_EXCEPTION();
2642 tryCachePutByID(exec, codeBlock, vPC, baseValue, slot);
2647 BEGIN_OPCODE(op_put_by_id_transition) {
2648 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2650 Cached property access: Attempts to set a new property with a cached transition
2651 property named by identifier property, belonging to register base,
2652 to register value. If the cache misses, op_put_by_id_transition
2653 reverts to op_put_by_id_generic.
2655 Unlike many opcodes, this one does not write any output to
2658 int base = vPC[1].u.operand;
2659 JSValue* baseValue = r[base].jsValue(exec);
2661 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2662 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2663 StructureID* oldStructureID = vPC[4].u.structureID;
2664 StructureID* newStructureID = vPC[5].u.structureID;
2666 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2667 ASSERT(baseCell->isObject());
2668 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2670 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2672 JSObject* proto = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2673 while (!proto->isNull()) {
2674 if (UNLIKELY(proto->structureID() != (*it).get())) {
2675 uncachePutByID(codeBlock, vPC);
2679 proto = static_cast<JSObject*>(proto->structureID()->prototypeForLookup(exec));
2682 baseObject->transitionTo(newStructureID);
2683 if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
2684 baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
2686 int value = vPC[3].u.operand;
2687 unsigned offset = vPC[7].u.operand;
2688 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2689 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2696 uncachePutByID(codeBlock, vPC);
2699 BEGIN_OPCODE(op_put_by_id_replace) {
2700 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2702 Cached property access: Attempts to set a pre-existing, cached
2703 property named by identifier property, belonging to register base,
2704 to register value. If the cache misses, op_put_by_id_replace
2705 reverts to op_put_by_id.
2707 Unlike many opcodes, this one does not write any output to
2710 int base = vPC[1].u.operand;
2711 JSValue* baseValue = r[base].jsValue(exec);
2713 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2714 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2715 StructureID* structureID = vPC[4].u.structureID;
2717 if (LIKELY(baseCell->structureID() == structureID)) {
2718 ASSERT(baseCell->isObject());
2719 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2720 int value = vPC[3].u.operand;
2721 unsigned offset = vPC[5].u.operand;
2723 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2724 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2731 uncachePutByID(codeBlock, vPC);
2734 BEGIN_OPCODE(op_put_by_id_generic) {
2735 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2737 Generic property access: Sets the property named by identifier
2738 property, belonging to register base, to register value.
2740 Unlike many opcodes, this one does not write any output to
2743 int base = vPC[1].u.operand;
2744 int property = vPC[2].u.operand;
2745 int value = vPC[3].u.operand;
2747 JSValue* baseValue = r[base].jsValue(exec);
2749 PutPropertySlot slot;
2750 Identifier& ident = codeBlock->identifiers[property];
2751 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2752 VM_CHECK_EXCEPTION();
2757 BEGIN_OPCODE(op_del_by_id) {
2758 /* del_by_id dst(r) base(r) property(id)
2760 Converts register base to Object, deletes the property
2761 named by identifier property from the object, and writes a
2762 boolean indicating success (if true) or failure (if false)
2765 int dst = (++vPC)->u.operand;
2766 int base = (++vPC)->u.operand;
2767 int property = (++vPC)->u.operand;
2769 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2771 Identifier& ident = codeBlock->identifiers[property];
2772 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2773 VM_CHECK_EXCEPTION();
2778 BEGIN_OPCODE(op_get_by_val) {
2779 /* get_by_val dst(r) base(r) property(r)
2781 Converts register base to Object, gets the property named
2782 by register property from the object, and puts the result
2783 in register dst. property is nominally converted to string
2784 but numbers are treated more efficiently.
2786 int dst = (++vPC)->u.operand;
2787 int base = (++vPC)->u.operand;
2788 int property = (++vPC)->u.operand;
2790 JSValue* baseValue = r[base].jsValue(exec);
2791 JSValue* subscript = r[property].jsValue(exec);
2796 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2797 if (LIKELY(isUInt32)) {
2798 if (isJSArray(baseValue)) {
2799 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2800 if (jsArray->canGetIndex(i))
2801 result = jsArray->getIndex(i);
2803 result = jsArray->JSArray::get(exec, i);
2804 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2805 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2807 result = baseValue->get(exec, i);
2809 Identifier property(exec, subscript->toString(exec));
2810 result = baseValue->get(exec, property);
2813 VM_CHECK_EXCEPTION();
2818 BEGIN_OPCODE(op_put_by_val) {
2819 /* put_by_val base(r) property(r) value(r)
2821 Sets register value on register base as the property named
2822 by register property. Base is converted to object
2823 first. register property is nominally converted to string
2824 but numbers are treated more efficiently.
2826 Unlike many opcodes, this one does not write any output to
2829 int base = (++vPC)->u.operand;
2830 int property = (++vPC)->u.operand;
2831 int value = (++vPC)->u.operand;
2833 JSValue* baseValue = r[base].jsValue(exec);
2834 JSValue* subscript = r[property].jsValue(exec);
2838 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2839 if (LIKELY(isUInt32)) {
2840 if (isJSArray(baseValue)) {
2841 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2842 if (jsArray->canSetIndex(i))
2843 jsArray->setIndex(i, r[value].jsValue(exec));
2845 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2847 baseValue->put(exec, i, r[value].jsValue(exec));
2849 Identifier property(exec, subscript->toString(exec));
2850 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2851 PutPropertySlot slot;
2852 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2856 VM_CHECK_EXCEPTION();
2860 BEGIN_OPCODE(op_del_by_val) {
2861 /* del_by_val dst(r) base(r) property(r)
2863 Converts register base to Object, deletes the property
2864 named by register property from the object, and writes a
2865 boolean indicating success (if true) or failure (if false)
2868 int dst = (++vPC)->u.operand;
2869 int base = (++vPC)->u.operand;
2870 int property = (++vPC)->u.operand;
2872 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2874 JSValue* subscript = r[property].jsValue(exec);
2877 if (subscript->getUInt32(i))
2878 result = jsBoolean(baseObj->deleteProperty(exec, i));
2880 VM_CHECK_EXCEPTION();
2881 Identifier property(exec, subscript->toString(exec));
2882 VM_CHECK_EXCEPTION();
2883 result = jsBoolean(baseObj->deleteProperty(exec, property));
2886 VM_CHECK_EXCEPTION();
2891 BEGIN_OPCODE(op_put_by_index) {
2892 /* put_by_index base(r) property(n) value(r)
2894 Sets register value on register base as the property named
2895 by the immediate number property. Base is converted to
2898 Unlike many opcodes, this one does not write any output to
2901 This opcode is mainly used to initialize array literals.
2903 int base = (++vPC)->u.operand;
2904 unsigned property = (++vPC)->u.operand;
2905 int value = (++vPC)->u.operand;
2907 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2912 BEGIN_OPCODE(op_loop) {
2913 /* loop target(offset)
2915 Jumps unconditionally to offset target from the current
2918 Additionally this loop instruction may terminate JS execution is
2919 the JS timeout is reached.
2921 #if DUMP_OPCODE_STATS
2922 OpcodeStats::resetLastInstruction();
2924 int target = (++vPC)->u.operand;
2925 CHECK_FOR_TIMEOUT();
2929 BEGIN_OPCODE(op_jmp) {
2930 /* jmp target(offset)
2932 Jumps unconditionally to offset target from the current
2935 #if DUMP_OPCODE_STATS
2936 OpcodeStats::resetLastInstruction();
2938 int target = (++vPC)->u.operand;
2943 BEGIN_OPCODE(op_loop_if_true) {
2944 /* loop_if_true cond(r) target(offset)
2946 Jumps to offset target from the current instruction, if and
2947 only if register cond converts to boolean as true.
2949 Additionally this loop instruction may terminate JS execution is
2950 the JS timeout is reached.
2952 int cond = (++vPC)->u.operand;
2953 int target = (++vPC)->u.operand;
2954 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2956 CHECK_FOR_TIMEOUT();
2963 BEGIN_OPCODE(op_jtrue) {
2964 /* jtrue cond(r) target(offset)
2966 Jumps to offset target from the current instruction, if and
2967 only if register cond converts to boolean as true.
2969 int cond = (++vPC)->u.operand;
2970 int target = (++vPC)->u.operand;
2971 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2979 BEGIN_OPCODE(op_jfalse) {
2980 /* jfalse cond(r) target(offset)
2982 Jumps to offset target from the current instruction, if and
2983 only if register cond converts to boolean as false.
2985 int cond = (++vPC)->u.operand;
2986 int target = (++vPC)->u.operand;
2987 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2995 BEGIN_OPCODE(op_loop_if_less) {
2996 /* loop_if_less src1(r) src2(r) target(offset)
2998 Checks whether register src1 is less than register src2, as
2999 with the ECMAScript '<' operator, and then jumps to offset
3000 target from the current instruction, if and only if the
3001 result of the comparison is true.
3003 Additionally this loop instruction may terminate JS execution is
3004 the JS timeout is reached.
3006 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3007 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3008 int target = (++vPC)->u.operand;
3010 bool result = jsLess(exec, src1, src2);
3011 VM_CHECK_EXCEPTION();
3015 CHECK_FOR_TIMEOUT();
3022 BEGIN_OPCODE(op_loop_if_lesseq) {
3023 /* loop_if_lesseq src1(r) src2(r) target(offset)
3025 Checks whether register src1 is less than or equal to register
3026 src2, as with the ECMAScript '<=' operator, and then jumps to
3027 offset target from the current instruction, if and only if the
3028 result of the comparison is true.
3030 Additionally this loop instruction may terminate JS execution is
3031 the JS timeout is reached.
3033 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3034 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3035 int target = (++vPC)->u.operand;
3037 bool result = jsLessEq(exec, src1, src2);
3038 VM_CHECK_EXCEPTION();
3042 CHECK_FOR_TIMEOUT();
3049 BEGIN_OPCODE(op_jnless) {
3050 /* jnless src1(r) src2(r) target(offset)
3052 Checks whether register src1 is less than register src2, as
3053 with the ECMAScript '<' operator, and then jumps to offset
3054 target from the current instruction, if and only if the
3055 result of the comparison is false.
3057 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3058 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3059 int target = (++vPC)->u.operand;
3061 bool result = jsLess(exec, src1, src2);
3062 VM_CHECK_EXCEPTION();
3072 BEGIN_OPCODE(op_switch_imm) {
3073 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3075 Performs a range checked switch on the scrutinee value, using
3076 the tableIndex-th immediate switch jump table. If the scrutinee value
3077 is an immediate number in the range covered by the referenced jump
3078 table, and the value at jumpTable[scrutinee value] is non-zero, then
3079 that value is used as the jump offset, otherwise defaultOffset is used.
3081 int tableIndex = (++vPC)->u.operand;
3082 int defaultOffset = (++vPC)->u.operand;
3083 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3084 if (!JSImmediate::isNumber(scrutinee))
3085 vPC += defaultOffset;
3087 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3088 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
3092 BEGIN_OPCODE(op_switch_char) {
3093 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3095 Performs a range checked switch on the scrutinee value, using
3096 the tableIndex-th character switch jump table. If the scrutinee value
3097 is a single character string in the range covered by the referenced jump
3098 table, and the value at jumpTable[scrutinee value] is non-zero, then
3099 that value is used as the jump offset, otherwise defaultOffset is used.
3101 int tableIndex = (++vPC)->u.operand;
3102 int defaultOffset = (++vPC)->u.operand;
3103 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3104 if (!scrutinee->isString())
3105 vPC += defaultOffset;
3107 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
3108 if (value->size() != 1)
3109 vPC += defaultOffset;
3111 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
3115 BEGIN_OPCODE(op_switch_string) {
3116 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3118 Performs a sparse hashmap based switch on the value in the scrutinee
3119 register, using the tableIndex-th string switch jump table. If the
3120 scrutinee value is a string that exists as a key in the referenced
3121 jump table, then the value associated with the string is used as the
3122 jump offset, otherwise defaultOffset is used.
3124 int tableIndex = (++vPC)->u.operand;
3125 int defaultOffset = (++vPC)->u.operand;
3126 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3127 if (!scrutinee->isString())
3128 vPC += defaultOffset;
3130 vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
3133 BEGIN_OPCODE(op_new_func) {
3134 /* new_func dst(r) func(f)
3136 Constructs a new Function instance from function func and
3137 the current scope chain using the original Function
3138 constructor, using the rules for function declarations, and
3139 puts the result in register dst.
3141 int dst = (++vPC)->u.operand;
3142 int func = (++vPC)->u.operand;
3144 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
3149 BEGIN_OPCODE(op_new_func_exp) {
3150 /* new_func_exp dst(r) func(f)
3152 Constructs a new Function instance from function func and
3153 the current scope chain using the original Function
3154 constructor, using the rules for function expressions, and
3155 puts the result in register dst.
3157 int dst = (++vPC)->u.operand;
3158 int func = (++vPC)->u.operand;
3160 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
3165 BEGIN_OPCODE(op_call_eval) {
3166 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3168 Call a function named "eval" with no explicit "this" value
3169 (which may therefore be the eval operator). If register
3170 thisVal is the global object, and register func contains
3171 that global object's original global eval function, then
3172 perform the eval operator in local scope (interpreting
3173 the argument registers as for the "call"
3174 opcode). Otherwise, act exactly as the "call" opcode would.
3177 int dst = (++vPC)->u.operand;
3178 int func = (++vPC)->u.operand;
3179 int thisVal = (++vPC)->u.operand;
3180 int firstArg = (++vPC)->u.operand;
3181 int argCount = (++vPC)->u.operand;
3183 JSValue* funcVal = r[func].jsValue(exec);
3184 JSValue* baseVal = r[thisVal].jsValue(exec);
3186 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
3187 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
3188 JSValue* result = callEval(exec, codeBlock, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
3198 // We didn't find the blessed version of eval, so reset vPC and process
3199 // this instruction as a normal function call, supplying the proper 'this'
3202 r[thisVal] = baseVal->toThisObject(exec);
3204 #if HAVE(COMPUTED_GOTO)
3205 // Hack around gcc performance quirk by performing an indirect goto
3206 // in order to set the vPC -- attempting to do so directly results in a
3207 // significant regression.
3208 goto *op_call_indirect; // indirect goto -> op_call
3210 // fall through to op_call
3212 BEGIN_OPCODE(op_call) {
3213 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3215 Perform a function call. Specifically, call register func
3216 with a "this" value of register thisVal, and put the result
3219 The arguments start at register firstArg and go up to
3220 argCount, but the "this" value is considered an implicit
3221 first argument, so the argCount should be one greater than
3222 the number of explicit arguments passed, and the register
3223 after firstArg should contain the actual first
3224 argument. This opcode will copy from the thisVal register
3225 to the firstArg register, unless the register index of
3226 thisVal is the special missing this object marker, which is
3227 2^31-1; in that case, the global object will be used as the
3230 If func is a native code function, then this opcode calls
3231 it and returns the value immediately.
3233 But if it is a JS function, then the current scope chain
3234 and code block is set to the function's, and we slide the
3235 register window so that the arguments would form the first
3236 few local registers of the called function's register
3237 window. In addition, a call frame header is written
3238 immediately before the arguments; see the call frame
3239 documentation for an explanation of how many registers a
3240 call frame takes and what they contain. That many registers
3241 before the firstArg register will be overwritten by the
3242 call. In addition, any registers higher than firstArg +
3243 argCount may be overwritten. Once this setup is complete,
3244 execution continues from the called function's first
3245 argument, and does not return until a "ret" opcode is
3249 int dst = (++vPC)->u.operand;
3250 int func = (++vPC)->u.operand;
3251 int thisVal = (++vPC)->u.operand;
3252 int firstArg = (++vPC)->u.operand;
3253 int argCount = (++vPC)->u.operand;
3255 JSValue* v = r[func].jsValue(exec);
3258 CallType callType = v->getCallData(callData);
3260 if (*enabledProfilerReference)
3261 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3263 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3264 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, v);
3265 exec->m_callFrame = callFrame;
3267 if (callType == CallTypeJS) {
3269 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3270 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3271 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3273 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3275 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3276 if (UNLIKELY(exceptionValue != 0))
3279 codeBlock = newCodeBlock;
3280 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3281 vPC = codeBlock->instructions.begin();
3283 #if DUMP_OPCODE_STATS
3284 OpcodeStats::resetLastInstruction();
3290 if (callType == CallTypeHost) {
3291 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3292 ArgList args(r + firstArg + 1, argCount - 1);
3294 MACHINE_SAMPLING_callingHostFunction();
3296 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
3297 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3298 VM_CHECK_EXCEPTION();
3300 r[dst] = returnValue;
3302 if (*enabledProfilerReference)
3303 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3309 ASSERT(callType == CallTypeNone);
3311 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
3312 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3315 BEGIN_OPCODE(op_ret) {
3318 Return register result as the return value of the current
3319 function call, writing it into the caller's expected return
3320 value register. In addition, unwind one call frame and
3321 restore the scope chain, code block instruction pointer and
3322 register base to those of the calling function.
3325 int result = (++vPC)->u.operand;
3327 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3328 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
3329 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
3330 ASSERT(activation->isActivationObject());
3331 activation->copyRegisters();
3334 if (*enabledProfilerReference)
3335 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
3337 if (codeBlock->needsFullScopeChain)
3338 scopeChain->deref();
3340 JSValue* returnValue = r[result].jsValue(exec);
3342 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3346 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3347 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
3348 r = callFrame[RegisterFile::CallerRegisters].r();
3349 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3350 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
3351 r[dst] = returnValue;
3355 BEGIN_OPCODE(op_initialise_locals) {
3356 for (Register* it = r - codeBlock->numVars + (codeBlock->codeType == EvalCode); it < r; ++it)
3357 (*it) = jsUndefined();
3358 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
3359 r[i] = codeBlock->constantRegisters[i];
3363 BEGIN_OPCODE(op_construct) {
3364 /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n)
3366 Invoke register "constr" as a constructor. For JS
3367 functions, the calling convention is exactly as for the
3368 "call" opcode, except that the "this" value is a newly
3369 created Object. For native constructors, a null "this"
3370 value is passed. In either case, the firstArg and argCount
3371 registers are interpreted as for the "call" opcode.
3373 Register constrProto must contain the prototype property of
3374 register constsr. This is to enable polymorphic inline
3375 caching of this lookup.
3378 int dst = (++vPC)->u.operand;
3379 int constr = (++vPC)->u.operand;
3380 int constrProto = (++vPC)->u.operand;
3381 int firstArg = (++vPC)->u.operand;
3382 int argCount = (++vPC)->u.operand;
3384 JSValue* constrVal = r[constr].jsValue(exec);
3386 ConstructData constructData;
3387 ConstructType constructType = constrVal->getConstructData(constructData);
3389 // Removing this line of code causes a measurable regression on squirrelfish.
3390 JSObject* constructor = static_cast<JSObject*>(constrVal);
3392 if (constructType == ConstructTypeJS) {
3393 if (*enabledProfilerReference)
3394 (*enabledProfilerReference)->willExecute(exec, constructor);
3396 StructureID* structure;
3397 JSValue* prototype = r[constrProto].jsValue(exec);
3398 if (prototype->isObject())
3399 structure = static_cast<JSObject*>(prototype)->inheritorID();
3401 structure = scopeChain->globalObject()->emptyObjectStructure();
3402 JSObject* newObject = new (exec) JSObject(structure);
3404 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3405 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3406 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3408 r[firstArg] = newObject; // "this" value
3410 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3411 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, constructor);
3412 exec->m_callFrame = callFrame;
3414 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3418 codeBlock = newCodeBlock;
3419 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3420 vPC = codeBlock->instructions.begin();
3425 if (constructType == ConstructTypeHost) {
3426 if (*enabledProfilerReference)
3427 (*enabledProfilerReference)->willExecute(exec, constructor);
3429 ArgList args(r + firstArg + 1, argCount - 1);
3431 MACHINE_SAMPLING_callingHostFunction();
3433 JSValue* returnValue = constructData.native.function(exec, constructor, args);
3435 VM_CHECK_EXCEPTION();
3436 r[dst] = returnValue;
3438 if (*enabledProfilerReference)
3439 (*enabledProfilerReference)->didExecute(exec, constructor);
3445 ASSERT(constructType == ConstructTypeNone);
3447 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
3450 BEGIN_OPCODE(op_construct_verify) {
3451 /* construct_verify dst(r) override(r)
3453 Verifies that register dst holds an object. If not, moves
3454 the object in register override to register dst.
3457 int dst = vPC[1].u.operand;;
3458 if (LIKELY(r[dst].jsValue(exec)->isObject())) {
3463 int override = vPC[2].u.operand;
3464 r[dst] = r[override];
3469 BEGIN_OPCODE(op_push_scope) {
3470 /* push_scope scope(r)
3472 Converts register scope to object, and pushes it onto the top
3473 of the current scope chain.
3475 int scope = (++vPC)->u.operand;
3476 JSValue* v = r[scope].jsValue(exec);
3477 JSObject* o = v->toObject(exec);
3478 VM_CHECK_EXCEPTION();
3480 setScopeChain(exec, scopeChain, scopeChain->push(o));
3485 BEGIN_OPCODE(op_pop_scope) {
3488 Removes the top item from the current scope chain.
3490 setScopeChain(exec, scopeChain, scopeChain->pop());
3495 BEGIN_OPCODE(op_get_pnames) {
3496 /* get_pnames dst(r) base(r)
3498 Creates a property name list for register base and puts it
3499 in register dst. This is not a true JavaScript value, just
3500 a synthetic value used to keep the iteration state in a
3503 int dst = (++vPC)->u.operand;
3504 int base = (++vPC)->u.operand;
3506 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
3510 BEGIN_OPCODE(op_next_pname) {
3511 /* next_pname dst(r) iter(r) target(offset)
3513 Tries to copies the next name from property name list in
3514 register iter. If there are names left, then copies one to
3515 register dst, and jumps to offset target. If there are none
3516 left, invalidates the iterator and continues to the next
3519 int dst = (++vPC)->u.operand;
3520 int iter = (++vPC)->u.operand;
3521 int target = (++vPC)->u.operand;
3523 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
3524 if (JSValue* temp = it->next(exec)) {
3525 CHECK_FOR_TIMEOUT();
3535 BEGIN_OPCODE(op_jmp_scopes) {
3536 /* jmp_scopes count(n) target(offset)
3538 Removes the a number of items from the current scope chain
3539 specified by immediate number count, then jumps to offset
3542 int count = (++vPC)->u.operand;
3543 int target = (++vPC)->u.operand;
3545 ScopeChainNode* tmp = scopeChain;
3548 setScopeChain(exec, scopeChain, tmp);
3553 #if HAVE(COMPUTED_GOTO)
3555 goto *(&&skip_new_scope);
3557 BEGIN_OPCODE(op_push_new_scope) {
3558 /* new_scope dst(r) property(id) value(r)
3560 Constructs a new StaticScopeObject with property set to value. That scope
3561 object is then pushed onto the ScopeChain. The scope object is then stored
3564 setScopeChain(exec, scopeChain, createExceptionScope(exec, codeBlock, vPC, r, scopeChain));
3568 #if HAVE(COMPUTED_GOTO)
3571 BEGIN_OPCODE(op_catch) {
3574 Retrieves the VMs current exception and puts it in register
3575 ex. This is only valid after an exception has been raised,
3576 and usually forms the beginning of an exception handler.
3578 ASSERT(exceptionValue);
3579 ASSERT(!exec->hadException());
3580 int ex = (++vPC)->u.operand;
3581 r[ex] = exceptionValue;
3587 BEGIN_OPCODE(op_throw) {
3590 Throws register ex as an exception. This involves three
3591 steps: first, it is set as the current exception in the
3592 VM's internal state, then the stack is unwound until an
3593 exception handler or a native code boundary is found, and
3594 then control resumes at the exception handler if any or
3595 else the script returns control to the nearest native caller.
3598 int ex = (++vPC)->u.operand;
3599 exceptionValue = r[ex].jsValue(exec);
3601 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, true);
3603 *exception = exceptionValue;
3607 #if HAVE(COMPUTED_GOTO)
3608 // Hack around gcc performance quirk by performing an indirect goto
3609 // in order to set the vPC -- attempting to do so directly results in a
3610 // significant regression.
3611 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
3619 BEGIN_OPCODE(op_unexpected_load) {
3620 /* unexpected_load load dst(r) src(k)
3622 Copies constant src to register dst.
3624 int dst = (++vPC)->u.operand;
3625 int src = (++vPC)->u.operand;
3626 r[dst] = codeBlock->unexpectedConstants[src];
3631 BEGIN_OPCODE(op_new_error) {
3632 /* new_error dst(r) type(n) message(k)
3634 Constructs a new Error instance using the original
3635 constructor, using immediate number n as the type and
3636 constant message as the message string. The result is
3637 written to register dst.
3639 int dst = (++vPC)->u.operand;
3640 int type = (++vPC)->u.operand;
3641 int message = (++vPC)->u.operand;
3643 r[dst] = Error::create(exec, (ErrorType)type, codeBlock->unexpectedConstants[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
3648 BEGIN_OPCODE(op_end) {
3651 Return register result as the value of a global or eval
3652 program. Return control to the calling native code.
3655 if (codeBlock->needsFullScopeChain) {
3656 ASSERT(scopeChain->refCount > 1);
3657 scopeChain->deref();
3659 int result = (++vPC)->u.operand;
3660 return r[result].jsValue(exec);
3662 BEGIN_OPCODE(op_put_getter) {
3663 /* put_getter base(r) property(id) function(r)
3665 Sets register function on register base as the getter named
3666 by identifier property. Base and function are assumed to be
3667 objects as this op should only be used for getters defined
3668 in object literal form.
3670 Unlike many opcodes, this one does not write any output to
3673 int base = (++vPC)->u.operand;
3674 int property = (++vPC)->u.operand;
3675 int function = (++vPC)->u.operand;
3677 ASSERT(r[base].jsValue(exec)->isObject());
3678 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
3679 Identifier& ident = codeBlock->identifiers[property];
3680 ASSERT(r[function].jsValue(exec)->isObject());
3681 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
3686 BEGIN_OPCODE(op_put_setter) {
3687 /* put_setter base(r) property(id) function(r)
3689 Sets register function on register base as the setter named
3690 by identifier property. Base and function are assumed to be
3691 objects as this op should only be used for setters defined
3692 in object literal form.
3694 Unlike many opcodes, this one does not write any output to
3697 int base = (++vPC)->u.operand;
3698 int property = (++vPC)->u.operand;
3699 int function = (++vPC)->u.operand;
3701 ASSERT(r[base].jsValue(exec)->isObject());
3702 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
3703 Identifier& ident = codeBlock->identifiers[property];
3704 ASSERT(r[function].jsValue(exec)->isObject());
3705 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
3710 BEGIN_OPCODE(op_jsr) {
3711 /* jsr retAddrDst(r) target(offset)
3713 Places the address of the next instruction into the retAddrDst
3714 register and jumps to offset target from the current instruction.
3716 int retAddrDst = (++vPC)->u.operand;
3717 int target = (++vPC)->u.operand;
3718 r[retAddrDst] = vPC + 1;
3723 BEGIN_OPCODE(op_sret) {
3724 /* sret retAddrSrc(r)
3726 Jumps to the address stored in the retAddrSrc register. This
3727 differs from op_jmp because the target address is stored in a
3728 register, not as an immediate.
3730 int retAddrSrc = (++vPC)->u.operand;
3731 vPC = r[retAddrSrc].vPC();
3734 BEGIN_OPCODE(op_debug) {
3735 /* debug debugHookID(n) firstLine(n) lastLine(n)
3737 Notifies the debugger of the current state of execution. This opcode
3738 is only generated while the debugger is attached.
3740 int debugHookID = (++vPC)->u.operand;
3741 int firstLine = (++vPC)->u.operand;
3742 int lastLine = (++vPC)->u.operand;
3744 debug(exec, codeBlock, scopeChain, r, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3750 exec->clearException();
3752 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3753 // cannot fathom if we don't assign to the exceptionValue before branching)
3754 exceptionValue = createInterruptedExecutionException(exec);
3756 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, false);
3758 *exception = exceptionValue;
3767 #undef VM_CHECK_EXCEPTION
3768 #undef CHECK_FOR_TIMEOUT
3771 JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
3773 Register* callFrame = this->callFrame(exec, function);
3777 JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
3779 CodeBlock* codeBlock = &function->m_body->generatedByteCode();
3780 activation = new (exec) JSActivation(exec, function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
3781 callFrame[RegisterFile::OptionalCalleeActivation] = activation;
3784 return activation->get(exec, exec->propertyNames().arguments);
3787 JSValue* Machine::retrieveCaller(ExecState* exec, InternalFunction* function) const
3789 Register* callFrame = this->callFrame(exec, function);
3793 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3794 if (!callerCodeBlock)
3797 Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3798 if (JSValue* caller = callerCallFrame[RegisterFile::Callee].jsValue(exec))
3804 void Machine::retrieveLastCaller(ExecState* exec, int& lineNumber, int& sourceId, UString& sourceURL, JSValue*& function) const
3808 sourceURL = UString();
3810 Register* callFrame = exec->m_callFrame;
3814 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3815 if (!callerCodeBlock)
3818 Instruction* vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3819 lineNumber = callerCodeBlock->lineNumberForVPC(vPC - 1);
3820 sourceId = callerCodeBlock->ownerNode->sourceId();
3821 sourceURL = callerCodeBlock->ownerNode->sourceURL();
3823 JSValue* callee = callFrame[RegisterFile::Callee].getJSValue();
3824 if (callee->toThisObject(exec)->inherits(&InternalFunction::info))
3825 function = retrieveCaller(exec, static_cast<InternalFunction*>(callee));
3828 Register* Machine::callFrame(ExecState* exec, InternalFunction* function) const
3830 Register* callFrame = exec->m_callFrame;
3833 while (!callFrame) {
3834 exec = exec->m_prev;
3837 callFrame = exec->m_callFrame;
3840 if (callFrame[RegisterFile::Callee].jsValue(exec) == function)
3843 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3844 if (!callerCodeBlock) {
3849 callFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3853 void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, Register*& argv, int& argc)
3855 function = static_cast<JSFunction*>(callFrame[RegisterFile::Callee].getJSValue());
3856 ASSERT(function->inherits(&JSFunction::info));
3858 argv = callFrame[RegisterFile::CallerRegisters].r() + callFrame[RegisterFile::ArgumentStartRegister].i() + 1; // + 1 to skip "this"
3859 argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"
3864 NEVER_INLINE static void doSetReturnAddressVMThrowTrampoline(void** returnAddress)
3866 ctiSetReturnAddress(returnAddress, (void*)ctiVMThrowTrampoline);
3869 NEVER_INLINE void Machine::tryCTICachePutByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const PutPropertySlot& slot)
3871 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
3873 if (JSImmediate::isImmediate(baseValue))
3876 // Uncacheable: give up.
3877 if (!slot.isCacheable()) {
3878 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3882 JSCell* baseCell = static_cast<JSCell*>(baseValue);
3883 StructureID* structureID = baseCell->structureID();
3885 if (structureID->isDictionary()) {
3886 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3890 // In the interpreter the last structure is trapped here; in CTI we use the
3891 // *_second method to achieve a similar (but not quite the same) effect.
3893 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
3894 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
3896 // Cache hit: Specialize instruction and ref StructureIDs.
3898 // If baseCell != base, then baseCell must be a proxy for another object.
3899 if (baseCell != slot.base()) {
3900 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3904 // StructureID transition, cache transition info
3905 if (slot.type() == PutPropertySlot::NewProperty) {
3906 vPC[0] = getOpcode(op_put_by_id_transition);
3907 vPC[4] = structureID->previousID();
3908 vPC[5] = structureID;
3909 StructureIDChain* chain = structureID->cachedPrototypeChain();
3911 chain = cachePrototypeChain(exec, structureID);
3913 // This happens if someone has manually inserted null into the prototype chain
3914 vPC[0] = getOpcode(op_put_by_id_generic);
3919 vPC[7] = slot.cachedOffset();
3920 codeBlock->refStructureIDs(vPC);
3921 CTI::compilePutByIdTransition(this, exec, codeBlock, structureID->previousID(), structureID, slot.cachedOffset(), chain, returnAddress);
3925 vPC[0] = getOpcode(op_put_by_id_replace);
3926 vPC[4] = structureID;
3927 vPC[5] = slot.cachedOffset();
3928 codeBlock->refStructureIDs(vPC);
3930 #if USE(CTI_REPATCH_PIC)
3932 CTI::patchPutByIdReplace(codeBlock, structureID, slot.cachedOffset(), returnAddress);
3934 CTI::compilePutByIdReplace(this, exec, codeBlock, structureID, slot.cachedOffset(), returnAddress);
3938 void* Machine::getCTIArrayLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
3940 if (!m_ctiArrayLengthTrampoline)
3941 m_ctiArrayLengthTrampoline = CTI::compileArrayLengthTrampoline(this, exec, codeBlock);
3943 return m_ctiArrayLengthTrampoline;
3946 void* Machine::getCTIStringLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
3948 if (!m_ctiStringLengthTrampoline)
3949 m_ctiStringLengthTrampoline = CTI::compileStringLengthTrampoline(this, exec, codeBlock);
3951 return m_ctiStringLengthTrampoline;
3954 NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
3956 // FIXME: Write a test that proves we need to check for recursion here just
3957 // like the interpreter does, then add a check for recursion.
3959 // FIXME: Cache property access for immediates.
3960 if (JSImmediate::isImmediate(baseValue)) {
3961 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3965 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
3966 #if USE(CTI_REPATCH_PIC)
3967 CTI::compilePatchGetArrayLength(this, exec, codeBlock, returnAddress);
3969 ctiRepatchCallByReturnAddress(returnAddress, getCTIArrayLengthTrampoline(exec, codeBlock));
3973 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
3974 // The tradeoff of compiling an repatched inline string length access routine does not seem
3975 // to pay off, so we currently only do this for arrays.
3976 ctiRepatchCallByReturnAddress(returnAddress, getCTIStringLengthTrampoline(exec, codeBlock));
3980 // Uncacheable: give up.
3981 if (!slot.isCacheable()) {
3982 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3986 JSCell* baseCell = static_cast<JSCell*>(baseValue);
3987 StructureID* structureID = baseCell->structureID();
3989 if (structureID->isDictionary()) {
3990 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3994 // In the interpreter the last structure is trapped here; in CTI we use the
3995 // *_second method to achieve a similar (but not quite the same) effect.
3997 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
3998 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
4000 // Cache hit: Specialize instruction and ref StructureIDs.
4002 if (slot.slotBase() == baseValue) {
4003 // set this up, so derefStructureIDs can do it's job.
4004 vPC[0] = getOpcode(op_get_by_id_self);
4005 vPC[4] = structureID;
4006 vPC[5] = slot.cachedOffset();
4007 codeBlock->refStructureIDs(vPC);
4009 #if USE(CTI_REPATCH_PIC)
4010 CTI::patchGetByIdSelf(codeBlock, structureID, slot.cachedOffset(), returnAddress);
4012 CTI::compileGetByIdSelf(this, exec, codeBlock, structureID, slot.cachedOffset(), returnAddress);
4017 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
4018 ASSERT(slot.slotBase()->isObject());
4020 JSObject* slotBaseObject = static_cast<JSObject*>(slot.slotBase());
4022 // Heavy access to a prototype is a good indication that it's not being
4023 // used as a dictionary.
4024 if (slotBaseObject->structureID()->isDictionary()) {
4025 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(slotBaseObject->structureID());
4026 slotBaseObject->setStructureID(transition.release());
4027 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
4030 vPC[0] = getOpcode(op_get_by_id_proto);
4031 vPC[4] = structureID;
4032 vPC[5] = slotBaseObject->structureID();
4033 vPC[6] = slot.cachedOffset();
4034 codeBlock->refStructureIDs(vPC);
4036 CTI::compileGetByIdProto(this, exec, codeBlock, structureID, slotBaseObject->structureID(), slot.cachedOffset(), returnAddress);
4041 JSObject* o = static_cast<JSObject*>(baseValue);
4042 while (slot.slotBase() != o) {
4043 JSValue* v = o->structureID()->prototypeForLookup(exec);
4045 // If we didn't find slotBase in baseValue's prototype chain, then baseValue
4046 // must be a proxy for another object.
4049 vPC[0] = getOpcode(op_get_by_id_generic);
4053 o = static_cast<JSObject*>(v);
4055 // Heavy access to a prototype is a good indication that it's not being
4056 // used as a dictionary.
4057 if (o->structureID()->isDictionary()) {
4058 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
4059 o->setStructureID(transition.release());
4060 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
4066 StructureIDChain* chain = structureID->cachedPrototypeChain();
4068 chain = cachePrototypeChain(exec, structureID);
4071 vPC[0] = getOpcode(op_get_by_id_chain);
4072 vPC[4] = structureID;
4075 vPC[7] = slot.cachedOffset();
4076 codeBlock->refStructureIDs(vPC);
4078 CTI::compileGetByIdChain(this, exec, codeBlock, structureID, chain, count, slot.cachedOffset(), returnAddress);
4082 #define JSVALUE_VM_CHECK_EXCEPTION_ARG(exception) \
4084 if (UNLIKELY(exception != 0)) { \
4085 exec->setException(exception); \
4086 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
4087 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
4091 #define VM_CHECK_EXCEPTION_v() \
4093 if (UNLIKELY(exec->hadException())) { \
4094 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
4095 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
4099 #define VM_CHECK_EXCEPTION(type) \
4101 if (UNLIKELY(exec->hadException())) { \
4102 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
4103 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
4107 #define VM_CHECK_EXCEPTION_AT_END() \
4109 if (UNLIKELY(exec->hadException())) { \
4110 /*printf("VM_CHECK_EXCEPTION_AT_END()\n");*/ \
4111 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
4112 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
4116 void Machine::cti_op_end(CTI_ARGS)
4118 ASSERT(ARG_scopeChain->refCount > 1);
4119 ARG_scopeChain->deref();
4122 JSValue* Machine::cti_op_add(CTI_ARGS)
4124 JSValue* src1 = ARG_src1;
4125 JSValue* src2 = ARG_src2;
4127 ExecState* exec = ARG_exec;
4128 JSValue* result = jsAdd(exec, src1, src2);
4129 VM_CHECK_EXCEPTION_AT_END();
4133 JSValue* Machine::cti_op_pre_inc(CTI_ARGS)
4135 JSValue* v = ARG_src1;
4137 ExecState* exec = ARG_exec;
4138 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
4139 VM_CHECK_EXCEPTION_AT_END();
4143 void Machine::cti_timeout_check(CTI_ARGS)
4145 ExecState* exec = ARG_exec;
4147 if (exec->machine()->checkTimeout(exec->dynamicGlobalObject()))