2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "BatchedTransitionOptimizer.h"
34 #include "CodeBlock.h"
35 #include "DebuggerCallFrame.h"
36 #include "ExceptionHelpers.h"
37 #include "ExecState.h"
38 #include "GlobalEvalFunction.h"
39 #include "JSActivation.h"
41 #include "JSFunction.h"
42 #include "JSNotAnObject.h"
43 #include "JSPropertyNameIterator.h"
44 #include "JSStaticScopeObject.h"
46 #include "ObjectPrototype.h"
49 #include "RegExpObject.h"
50 #include "RegExpPrototype.h"
52 #include "collector.h"
54 #include "operations.h"
55 #include "SamplingTool.h"
59 #include <mach/mach.h>
78 // Preferred number of milliseconds between each timeout check
79 static const int preferredScriptCheckTimeInterval = 1000;
81 #if HAVE(COMPUTED_GOTO)
82 static void* op_throw_end_indirect;
83 static void* op_call_indirect;
86 // Returns the depth of the scope chain within a given call frame.
87 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
89 if (!codeBlock->needsFullScopeChain)
92 ScopeChainIterator iter = sc.begin();
93 ScopeChainIterator end = sc.end();
94 while (!(*iter)->isActivationObject()) {
103 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
104 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
105 static bool fastIsNumber(JSValue* value, double& arg)
107 if (JSImmediate::isNumber(value))
108 arg = JSImmediate::getTruncatedInt32(value);
109 else if (Heap::isNumber(static_cast<JSCell*>(value)))
110 arg = static_cast<JSNumberCell*>(value)->value();
116 // FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
117 static bool fastToInt32(JSValue* value, int32_t& arg)
119 if (JSImmediate::isNumber(value))
120 arg = JSImmediate::getTruncatedInt32(value);
121 else if (Heap::isNumber(static_cast<JSCell*>(value)))
122 arg = static_cast<JSNumberCell*>(value)->toInt32();
128 static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
130 if (JSImmediate::isNumber(value)) {
131 if (JSImmediate::getTruncatedUInt32(value, arg))
134 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
136 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
137 arg = static_cast<JSNumberCell*>(value)->toUInt32();
143 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
145 if (JSImmediate::areBothImmediateNumbers(v1, v2))
146 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
150 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
155 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
156 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
158 if (wasNotString1 | wasNotString2)
161 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
164 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
166 if (JSImmediate::areBothImmediateNumbers(v1, v2))
167 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
171 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
176 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
177 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
179 if (wasNotString1 | wasNotString2)
182 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
185 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
187 // exception for the Date exception in defaultValue()
188 JSValue* p1 = v1->toPrimitive(exec);
189 JSValue* p2 = v2->toPrimitive(exec);
191 if (p1->isString() || p2->isString()) {
192 RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
194 return throwOutOfMemoryError(exec);
195 return jsString(exec, value.release());
198 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
201 // Fast-path choices here are based on frequency data from SunSpider:
202 // <times> Add case: <t1> <t2>
203 // ---------------------------
204 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
205 // 247412 Add case: 5 5
206 // 20900 Add case: 5 6
207 // 13962 Add case: 5 3
208 // 4000 Add case: 3 5
210 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
214 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
215 return jsNumber(exec, left + right);
217 if (v1->isString() && v2->isString()) {
218 RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
220 return throwOutOfMemoryError(exec);
221 return jsString(exec, value.release());
224 // All other cases are pretty uncommon
225 return jsAddSlowCase(exec, v1, v2);
228 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
230 if (v->isUndefined())
231 return jsNontrivialString(exec, "undefined");
233 return jsNontrivialString(exec, "boolean");
235 return jsNontrivialString(exec, "number");
237 return jsNontrivialString(exec, "string");
239 // Return "undefined" for objects that should be treated
240 // as null when doing comparisons.
241 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
242 return jsNontrivialString(exec, "undefined");
244 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
245 return jsNontrivialString(exec, "function");
247 return jsNontrivialString(exec, "object");
250 static bool jsIsObjectType(JSValue* v)
252 if (JSImmediate::isImmediate(v))
255 JSType type = static_cast<JSCell*>(v)->structureID()->type();
256 if (type == NumberType || type == StringType)
258 if (type == ObjectType) {
259 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
262 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
268 static bool jsIsFunctionType(JSValue* v)
272 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
278 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
280 int dst = (vPC + 1)->u.operand;
281 int property = (vPC + 2)->u.operand;
283 ScopeChainIterator iter = scopeChain->begin();
284 ScopeChainIterator end = scopeChain->end();
287 Identifier& ident = codeBlock->identifiers[property];
290 PropertySlot slot(o);
291 if (o->getPropertySlot(exec, ident, slot)) {
292 JSValue* result = slot.getValue(exec, ident);
293 exceptionValue = exec->exception();
299 } while (++iter != end);
300 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
304 static bool NEVER_INLINE resolveSkip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
306 int dst = (vPC + 1)->u.operand;
307 int property = (vPC + 2)->u.operand;
308 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
310 ScopeChainIterator iter = scopeChain->begin();
311 ScopeChainIterator end = scopeChain->end();
317 Identifier& ident = codeBlock->identifiers[property];
320 PropertySlot slot(o);
321 if (o->getPropertySlot(exec, ident, slot)) {
322 JSValue* result = slot.getValue(exec, ident);
323 exceptionValue = exec->exception();
329 } while (++iter != end);
330 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
334 static bool NEVER_INLINE resolveGlobal(ExecState* exec, Instruction* vPC, Register* r, CodeBlock* codeBlock, JSValue*& exceptionValue)
336 int dst = (vPC + 1)->u.operand;
337 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
338 ASSERT(globalObject->isGlobalObject());
339 int property = (vPC + 3)->u.operand;
340 StructureID* structureID = (vPC + 4)->u.structureID;
341 int offset = (vPC + 5)->u.operand;
343 if (structureID == globalObject->structureID()) {
344 r[dst] = globalObject->getDirectOffset(offset);
348 Identifier& ident = codeBlock->identifiers[property];
349 PropertySlot slot(globalObject);
350 if (globalObject->getPropertySlot(exec, ident, slot)) {
351 JSValue* result = slot.getValue(exec, ident);
352 if (slot.isCacheable()) {
353 if (vPC[4].u.structureID)
354 vPC[4].u.structureID->deref();
355 globalObject->structureID()->ref();
356 vPC[4] = globalObject->structureID();
357 vPC[5] = slot.cachedOffset();
362 exceptionValue = exec->exception();
369 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
373 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
375 ScopeChainIterator iter = scopeChain->begin();
376 ScopeChainIterator next = iter;
378 ScopeChainIterator end = scopeChain->end();
385 if (next == end || base->getPropertySlot(exec, property, slot))
392 ASSERT_NOT_REACHED();
396 NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
398 int dst = (vPC + 1)->u.operand;
399 int property = (vPC + 2)->u.operand;
400 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
403 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
405 int baseDst = (vPC + 1)->u.operand;
406 int propDst = (vPC + 2)->u.operand;
407 int property = (vPC + 3)->u.operand;
409 ScopeChainIterator iter = scopeChain->begin();
410 ScopeChainIterator end = scopeChain->end();
412 // FIXME: add scopeDepthIsZero optimization
416 Identifier& ident = codeBlock->identifiers[property];
420 PropertySlot slot(base);
421 if (base->getPropertySlot(exec, ident, slot)) {
422 JSValue* result = slot.getValue(exec, ident);
423 exceptionValue = exec->exception();
431 } while (iter != end);
433 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
437 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
439 int baseDst = (vPC + 1)->u.operand;
440 int funcDst = (vPC + 2)->u.operand;
441 int property = (vPC + 3)->u.operand;
443 ScopeChainIterator iter = scopeChain->begin();
444 ScopeChainIterator end = scopeChain->end();
446 // FIXME: add scopeDepthIsZero optimization
450 Identifier& ident = codeBlock->identifiers[property];
454 PropertySlot slot(base);
455 if (base->getPropertySlot(exec, ident, slot)) {
456 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
457 // However, section 10.2.3 says that in the case where the value provided
458 // by the caller is null, the global object should be used. It also says
459 // that the section does not apply to internal functions, but for simplicity
460 // of implementation we use the global object anyway here. This guarantees
461 // that in host objects you always get a valid object for this.
462 // We also handle wrapper substitution for the global object at the same time.
463 JSObject* thisObj = base->toThisObject(exec);
464 JSValue* result = slot.getValue(exec, ident);
465 exceptionValue = exec->exception();
469 r[baseDst] = thisObj;
474 } while (iter != end);
476 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
480 #if HAVE(COMPUTED_GOTO)
481 Opcode Machine::s_opcodeTable[numOpcodeIDs];
484 Opcode Machine::getOpcode(OpcodeID id)
486 #if HAVE(COMPUTED_GOTO)
487 return s_opcodeTable[id];
493 ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, JSValue* function)
495 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
496 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
497 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
498 callFrame[RegisterFile::CallerRegisters] = r;
499 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
500 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
501 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
502 callFrame[RegisterFile::Callee] = function;
503 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
506 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
508 size_t registerOffset = argv + newCodeBlock->numLocals;
509 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
511 if (argc == newCodeBlock->numParameters) { // correct number of arguments
512 if (!registerFile->grow(size)) {
513 exceptionValue = createStackOverflowError(exec);
517 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
518 if (!registerFile->grow(size)) {
519 exceptionValue = createStackOverflowError(exec);
524 int omittedArgCount = newCodeBlock->numParameters - argc;
525 Register* endOfParams = r - newCodeBlock->numVars;
526 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
527 (*it) = jsUndefined();
528 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
529 int shift = argc + RegisterFile::CallFrameHeaderSize;
530 registerOffset += shift;
533 if (!registerFile->grow(size)) {
534 exceptionValue = createStackOverflowError(exec);
539 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
540 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
541 for ( ; it != end; ++it)
545 // initialize local variable slots
546 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
547 (*it) = jsUndefined();
549 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
550 r[i] = newCodeBlock->constantRegisters[i];
555 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
557 if (newCodeBlock->needsFullScopeChain) {
558 JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
559 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
561 return callDataScopeChain->copy()->push(activation);
564 return callDataScopeChain;
567 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
569 if (value->isObject())
571 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
575 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
578 return jsUndefined();
580 JSValue* program = r[argv + 1].jsValue(exec);
582 if (!program->isString())
585 Profiler** profiler = Profiler::enabledProfilerReference();
587 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
589 UString programSource = static_cast<JSString*>(program)->value();
591 RefPtr<EvalNode> evalNode = callingCodeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
595 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
598 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
606 , m_ctiArrayLengthTrampoline(0)
607 , m_ctiStringLengthTrampoline(0)
608 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
612 , m_timeAtLastCheckTimeout(0)
614 , m_timeoutCheckCount(0)
615 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
617 privateExecute(InitializeAndReturn);
619 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
620 void* storage = fastMalloc(sizeof(CollectorBlock));
622 JSArray* jsArray = new (storage) JSArray(StructureID::create(jsNull()));
623 m_jsArrayVptr = jsArray->vptr();
624 static_cast<JSCell*>(jsArray)->~JSCell();
626 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
627 m_jsStringVptr = jsString->vptr();
628 static_cast<JSCell*>(jsString)->~JSCell();
630 JSFunction* jsFunction = new (storage) JSFunction(StructureID::create(jsNull()));
631 m_jsFunctionVptr = jsFunction->vptr();
632 static_cast<JSCell*>(jsFunction)->~JSCell();
640 if (m_ctiArrayLengthTrampoline)
641 fastFree(m_ctiArrayLengthTrampoline);
642 if (m_ctiStringLengthTrampoline)
643 fastFree(m_ctiStringLengthTrampoline);
649 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
651 ScopeChain sc(scopeChain);
652 JSGlobalObject* globalObject = sc.globalObject();
653 codeBlock->dump(globalObject->globalExec());
654 dumpRegisters(codeBlock, registerFile, r);
657 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
659 printf("Register frame: \n\n");
660 printf("----------------------------------------------------\n");
661 printf(" use | address | value \n");
662 printf("----------------------------------------------------\n");
667 if (codeBlock->codeType == GlobalCode) {
668 it = registerFile->lastGlobal();
669 end = it + registerFile->numGlobals();
671 printf("[global var] | %10p | %10p \n", it, (*it).v());
674 printf("----------------------------------------------------\n");
677 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
678 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
679 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
680 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
681 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
682 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
683 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
684 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
685 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
686 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
687 printf("----------------------------------------------------\n");
689 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
690 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
693 printf("[param] | %10p | %10p \n", it, (*it).v());
697 printf("----------------------------------------------------\n");
699 if (codeBlock->codeType != GlobalCode) {
700 end = it + codeBlock->numVars;
703 printf("[var] | %10p | %10p \n", it, (*it).v());
706 printf("----------------------------------------------------\n");
710 end = it + codeBlock->numTemporaries;
713 printf("[temp] | %10p | %10p \n", it, (*it).v());
721 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
723 bool Machine::isOpcode(Opcode opcode)
725 #if HAVE(COMPUTED_GOTO)
726 return opcode != HashTraits<Opcode>::emptyValue()
727 && !HashTraits<Opcode>::isDeletedValue(opcode)
728 && m_opcodeIDTable.contains(opcode);
730 return opcode >= 0 && opcode <= op_end;
736 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
738 CodeBlock* oldCodeBlock = codeBlock;
739 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
741 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
742 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
743 if (callFrame[RegisterFile::Callee].jsValue(exec))
744 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
746 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
749 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
750 if (callFrame[RegisterFile::Callee].jsValue(exec))
751 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
753 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
756 if (oldCodeBlock->needsFullScopeChain)
759 // If this call frame created an activation, tear it off.
760 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
761 ASSERT(activation->isActivationObject());
762 activation->copyRegisters();
765 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
769 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
770 r = callFrame[RegisterFile::CallerRegisters].r();
771 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
772 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
777 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
779 // Set up the exception object
781 if (exceptionValue->isObject()) {
782 JSObject* exception = static_cast<JSObject*>(exceptionValue);
783 if (exception->isNotAnObjectErrorStub()) {
784 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
785 exceptionValue = exception;
787 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
788 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
789 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
790 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
791 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
792 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
797 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
798 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
800 // We only hit this path for error messages and throw statements, which don't have a specific failure position
801 // So we just give the full range of the error/throw statement.
802 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
803 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
805 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
806 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
807 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
810 if (exception->isWatchdogException()) {
811 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
812 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
819 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
820 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
821 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
824 // Calculate an exception handler vPC, unwinding call frames as necessary.
827 Instruction* handlerVPC;
829 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
830 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
834 // Now unwind the scope chain within the exception handler's call frame.
836 ScopeChain sc(scopeChain);
837 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
838 ASSERT(scopeDelta >= 0);
841 setScopeChain(exec, scopeChain, sc.node());
846 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
848 if (m_reentryDepth >= MaxReentryDepth) {
849 *exception = createStackOverflowError(exec);
853 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
855 size_t oldSize = m_registerFile.size();
856 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
857 if (!m_registerFile.grow(newSize)) {
858 *exception = createStackOverflowError(exec);
862 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
863 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
864 globalObject->copyGlobalsTo(m_registerFile);
866 Register* callFrame = m_registerFile.base() + oldSize;
868 // a 0 codeBlock indicates a built-in caller
869 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
871 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
872 r[codeBlock->thisRegister] = thisObj;
874 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
875 r[i] = codeBlock->constantRegisters[i];
877 if (codeBlock->needsFullScopeChain)
878 scopeChain = scopeChain->copy();
880 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
882 Profiler** profiler = Profiler::enabledProfilerReference();
884 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
888 if (!codeBlock->ctiCode)
889 CTI::compile(this, exec, codeBlock);
890 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
892 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
896 MACHINE_SAMPLING_privateExecuteReturned();
899 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
901 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
902 lastGlobalObject->copyGlobalsTo(m_registerFile);
904 m_registerFile.shrink(oldSize);
908 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
910 if (m_reentryDepth >= MaxReentryDepth) {
911 *exception = createStackOverflowError(exec);
915 int argv = RegisterFile::CallFrameHeaderSize;
916 int argc = args.size() + 1; // implicit "this" parameter
918 size_t oldSize = m_registerFile.size();
919 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
920 *exception = createStackOverflowError(exec);
924 Register* callFrame = m_registerFile.base() + oldSize;
926 // put args in place, including "this"
927 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
930 ArgList::const_iterator end = args.end();
931 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
934 // a 0 codeBlock indicates a built-in caller
935 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, function);
937 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
938 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
940 m_registerFile.shrink(oldSize);
944 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
946 Profiler** profiler = Profiler::enabledProfilerReference();
948 (*profiler)->willExecute(exec, function);
952 if (!newCodeBlock->ctiCode)
953 CTI::compile(this, exec, newCodeBlock);
954 JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
956 setScopeChain(&newExec, scopeChain, scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r));
957 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
961 MACHINE_SAMPLING_privateExecuteReturned();
963 m_registerFile.shrink(oldSize);
967 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
969 if (m_reentryDepth >= MaxReentryDepth) {
970 *exception = createStackOverflowError(exec);
974 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
976 JSVariableObject* variableObject;
977 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
979 if (node->object->isVariableObject()) {
980 variableObject = static_cast<JSVariableObject*>(node->object);
985 { // Scope for BatchedTransitionOptimizer
987 BatchedTransitionOptimizer optimizer(variableObject);
989 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
990 Node::VarStack::const_iterator varStackEnd = varStack.end();
991 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
992 const Identifier& ident = (*it).first;
993 if (!variableObject->hasProperty(exec, ident)) {
994 PutPropertySlot slot;
995 variableObject->put(exec, ident, jsUndefined(), slot);
999 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
1000 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
1001 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
1002 PutPropertySlot slot;
1003 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
1008 size_t oldSize = m_registerFile.size();
1009 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
1010 if (!m_registerFile.grow(newSize)) {
1011 *exception = createStackOverflowError(exec);
1015 Register* callFrame = m_registerFile.base() + registerOffset;
1017 // a 0 codeBlock indicates a built-in caller
1018 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
1020 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
1021 r[codeBlock->thisRegister] = thisObj;
1023 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
1024 r[i] = codeBlock->constantRegisters[i];
1026 if (codeBlock->needsFullScopeChain)
1027 scopeChain = scopeChain->copy();
1029 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
1031 Profiler** profiler = Profiler::enabledProfilerReference();
1033 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1037 if (!codeBlock->ctiCode)
1038 CTI::compile(this, exec, codeBlock);
1039 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
1041 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
1045 MACHINE_SAMPLING_privateExecuteReturned();
1048 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1050 m_registerFile.shrink(oldSize);
1054 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
1056 scopeChain = newScopeChain;
1057 exec->m_scopeChain = newScopeChain;
1060 NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
1062 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
1066 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
1068 switch (debugHookID) {
1069 case DidEnterCallFrame:
1070 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1072 case WillLeaveCallFrame:
1073 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1075 case WillExecuteStatement:
1076 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1078 case WillExecuteProgram:
1079 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1081 case DidExecuteProgram:
1082 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1084 case DidReachBreakpoint:
1085 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1090 void Machine::resetTimeoutCheck()
1092 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1093 m_timeAtLastCheckTimeout = 0;
1094 m_timeExecuting = 0;
1097 // Returns the time the current thread has spent executing, in milliseconds.
1098 static inline unsigned getCPUTime()
1100 #if PLATFORM(DARWIN)
1101 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1102 thread_basic_info_data_t info;
1104 // Get thread information
1105 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1107 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1108 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1111 #elif HAVE(SYS_TIME_H)
1112 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1114 gettimeofday(&tv, 0);
1115 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1117 QDateTime t = QDateTime::currentDateTime();
1118 return t.toTime_t() * 1000 + t.time().msec();
1119 #elif PLATFORM(WIN_OS)
1122 unsigned long long fileTimeAsLong;
1123 } userTime, kernelTime;
1125 // GetThreadTimes won't accept NULL arguments so we pass these even though
1126 // they're not used.
1127 FILETIME creationTime, exitTime;
1129 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1131 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1133 #error Platform does not have getCurrentTime function
1137 // We have to return a JSValue here, gcc seems to produce worse code if
1138 // we attempt to return a bool
1139 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1141 unsigned currentTime = getCPUTime();
1143 if (!m_timeAtLastCheckTimeout) {
1144 // Suspicious amount of looping in a script -- start timing it
1145 m_timeAtLastCheckTimeout = currentTime;
1149 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1154 m_timeExecuting += timeDiff;
1155 m_timeAtLastCheckTimeout = currentTime;
1157 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1158 // preferredScriptCheckTimeInterval
1159 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1160 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1161 // preferred script check time interval.
1162 if (m_ticksUntilNextTimeoutCheck == 0)
1163 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1165 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1166 if (globalObject->shouldInterruptScript())
1167 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1169 resetTimeoutCheck();
1175 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1177 int dst = (++vPC)->u.operand;
1178 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1179 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1180 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1182 return scopeChain->push(scope);
1185 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1187 JSValue* prototype = structureID->prototypeForLookup(exec);
1188 if (JSImmediate::isImmediate(prototype))
1190 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(prototype)->structureID());
1191 structureID->setCachedPrototypeChain(chain.release());
1192 return structureID->cachedPrototypeChain();
1195 NEVER_INLINE void Machine::tryCachePutByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1197 // Recursive invocation may already have specialized this instruction.
1198 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1201 if (JSImmediate::isImmediate(baseValue))
1204 // Uncacheable: give up.
1205 if (!slot.isCacheable()) {
1206 vPC[0] = getOpcode(op_put_by_id_generic);
1210 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1211 StructureID* structureID = baseCell->structureID();
1213 if (structureID->isDictionary()) {
1214 vPC[0] = getOpcode(op_put_by_id_generic);
1218 // Cache miss: record StructureID to compare against next time.
1219 StructureID* lastStructureID = vPC[4].u.structureID;
1220 if (structureID != lastStructureID) {
1221 // First miss: record StructureID to compare against next time.
1222 if (!lastStructureID) {
1223 vPC[4] = structureID;
1227 // Second miss: give up.
1228 vPC[0] = getOpcode(op_put_by_id_generic);
1232 // Cache hit: Specialize instruction and ref StructureIDs.
1234 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1235 if (baseCell != slot.base()) {
1236 vPC[0] = getOpcode(op_put_by_id_generic);
1240 // StructureID transition, cache transition info
1241 if (slot.type() == PutPropertySlot::NewProperty) {
1242 vPC[0] = getOpcode(op_put_by_id_transition);
1243 vPC[4] = structureID->previousID();
1244 vPC[5] = structureID;
1245 StructureIDChain* chain = structureID->cachedPrototypeChain();
1247 chain = cachePrototypeChain(exec, structureID);
1249 // This happens if someone has manually inserted null into the prototype chain
1250 vPC[0] = getOpcode(op_put_by_id_generic);
1255 vPC[7] = slot.cachedOffset();
1256 codeBlock->refStructureIDs(vPC);
1260 vPC[0] = getOpcode(op_put_by_id_replace);
1261 vPC[5] = slot.cachedOffset();
1262 codeBlock->refStructureIDs(vPC);
1265 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1267 codeBlock->derefStructureIDs(vPC);
1268 vPC[0] = getOpcode(op_put_by_id);
1272 NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1274 // Recursive invocation may already have specialized this instruction.
1275 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1278 // FIXME: Cache property access for immediates.
1279 if (JSImmediate::isImmediate(baseValue)) {
1280 vPC[0] = getOpcode(op_get_by_id_generic);
1284 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1285 vPC[0] = getOpcode(op_get_array_length);
1289 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1290 vPC[0] = getOpcode(op_get_string_length);
1294 // Uncacheable: give up.
1295 if (!slot.isCacheable()) {
1296 vPC[0] = getOpcode(op_get_by_id_generic);
1300 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1302 if (structureID->isDictionary()) {
1303 vPC[0] = getOpcode(op_get_by_id_generic);
1308 StructureID* lastStructureID = vPC[4].u.structureID;
1309 if (structureID != lastStructureID) {
1310 // First miss: record StructureID to compare against next time.
1311 if (!lastStructureID) {
1312 vPC[4] = structureID;
1316 // Second miss: give up.
1317 vPC[0] = getOpcode(op_get_by_id_generic);
1321 // Cache hit: Specialize instruction and ref StructureIDs.
1323 if (slot.slotBase() == baseValue) {
1324 vPC[0] = getOpcode(op_get_by_id_self);
1325 vPC[5] = slot.cachedOffset();
1327 codeBlock->refStructureIDs(vPC);
1331 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1332 ASSERT(slot.slotBase()->isObject());
1334 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1336 // Heavy access to a prototype is a good indication that it's not being
1337 // used as a dictionary.
1338 if (baseObject->structureID()->isDictionary()) {
1339 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1340 baseObject->setStructureID(transition.release());
1341 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1344 vPC[0] = getOpcode(op_get_by_id_proto);
1345 vPC[5] = baseObject->structureID();
1346 vPC[6] = slot.cachedOffset();
1348 codeBlock->refStructureIDs(vPC);
1353 JSObject* o = static_cast<JSObject*>(baseValue);
1354 while (slot.slotBase() != o) {
1355 JSValue* v = o->structureID()->prototypeForLookup(exec);
1357 // If we didn't find base in baseValue's prototype chain, then baseValue
1358 // must be a proxy for another object.
1360 vPC[0] = getOpcode(op_get_by_id_generic);
1364 o = static_cast<JSObject*>(v);
1366 // Heavy access to a prototype is a good indication that it's not being
1367 // used as a dictionary.
1368 if (o->structureID()->isDictionary()) {
1369 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1370 o->setStructureID(transition.release());
1371 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1377 StructureIDChain* chain = structureID->cachedPrototypeChain();
1379 chain = cachePrototypeChain(exec, structureID);
1382 vPC[0] = getOpcode(op_get_by_id_chain);
1383 vPC[4] = structureID;
1386 vPC[7] = slot.cachedOffset();
1387 codeBlock->refStructureIDs(vPC);
1390 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1392 codeBlock->derefStructureIDs(vPC);
1393 vPC[0] = getOpcode(op_get_by_id);
1397 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1399 // One-time initialization of our address tables. We have to put this code
1400 // here because our labels are only in scope inside this function.
1401 if (flag == InitializeAndReturn) {
1402 #if HAVE(COMPUTED_GOTO)
1403 #define ADD_OPCODE(id) s_opcodeTable[id] = &&id;
1404 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1407 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1408 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1409 #undef ADD_OPCODE_ID
1410 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1411 op_throw_end_indirect = &&op_throw_end;
1412 op_call_indirect = &&op_call;
1413 #endif // HAVE(COMPUTED_GOTO)
1418 // Currently with CTI enabled we never interpret functions
1419 ASSERT_NOT_REACHED();
1422 JSValue* exceptionValue = 0;
1423 Instruction* handlerVPC = 0;
1425 Register* registerBase = registerFile->base();
1426 Instruction* vPC = codeBlock->instructions.begin();
1427 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1428 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1430 #define VM_CHECK_EXCEPTION() \
1432 if (UNLIKELY(exec->hadException())) { \
1433 exceptionValue = exec->exception(); \
1438 #if DUMP_OPCODE_STATS
1439 OpcodeStats::resetLastInstruction();
1442 #define CHECK_FOR_TIMEOUT() \
1443 if (!--tickCount) { \
1444 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1446 tickCount = m_ticksUntilNextTimeoutCheck; \
1449 #if HAVE(COMPUTED_GOTO)
1450 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1451 #if DUMP_OPCODE_STATS
1452 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1454 #define BEGIN_OPCODE(opcode) opcode:
1458 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1459 #if DUMP_OPCODE_STATS
1460 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1462 #define BEGIN_OPCODE(opcode) case opcode:
1464 while (1) // iterator loop begins
1465 switch (vPC->u.opcode)
1468 BEGIN_OPCODE(op_new_object) {
1469 /* new_object dst(r)
1471 Constructs a new empty Object instance using the original
1472 constructor, and puts the result in register dst.
1474 int dst = (++vPC)->u.operand;
1475 r[dst] = constructEmptyObject(exec);
1480 BEGIN_OPCODE(op_new_array) {
1481 /* new_array dst(r) firstArg(r) argCount(n)
1483 Constructs a new Array instance using the original
1484 constructor, and puts the result in register dst.
1485 The array will contain argCount elements with values
1486 taken from registers starting at register firstArg.
1488 int dst = (++vPC)->u.operand;
1489 int firstArg = (++vPC)->u.operand;
1490 int argCount = (++vPC)->u.operand;
1491 ArgList args(r + firstArg, argCount);
1492 r[dst] = constructArray(exec, args);
1497 BEGIN_OPCODE(op_new_regexp) {
1498 /* new_regexp dst(r) regExp(re)
1500 Constructs a new RegExp instance using the original
1501 constructor from regexp regExp, and puts the result in
1504 int dst = (++vPC)->u.operand;
1505 int regExp = (++vPC)->u.operand;
1506 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1511 BEGIN_OPCODE(op_mov) {
1512 /* mov dst(r) src(r)
1514 Copies register src to register dst.
1516 int dst = (++vPC)->u.operand;
1517 int src = (++vPC)->u.operand;
1523 BEGIN_OPCODE(op_eq) {
1524 /* eq dst(r) src1(r) src2(r)
1526 Checks whether register src1 and register src2 are equal,
1527 as with the ECMAScript '==' operator, and puts the result
1528 as a boolean in register dst.
1530 int dst = (++vPC)->u.operand;
1531 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1532 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1533 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1534 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1536 JSValue* result = jsBoolean(equal(exec, src1, src2));
1537 VM_CHECK_EXCEPTION();
1544 BEGIN_OPCODE(op_eq_null) {
1545 /* neq dst(r) src(r)
1547 Checks whether register src is null, as with the ECMAScript '!='
1548 operator, and puts the result as a boolean in register dst.
1550 int dst = (++vPC)->u.operand;
1551 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1553 if (src->isUndefinedOrNull()) {
1554 r[dst] = jsBoolean(true);
1559 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined());
1563 BEGIN_OPCODE(op_neq) {
1564 /* neq dst(r) src1(r) src2(r)
1566 Checks whether register src1 and register src2 are not
1567 equal, as with the ECMAScript '!=' operator, and puts the
1568 result as a boolean in register dst.
1570 int dst = (++vPC)->u.operand;
1571 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1572 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1573 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1574 r[dst] = jsBoolean(src1 != src2);
1576 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1577 VM_CHECK_EXCEPTION();
1584 BEGIN_OPCODE(op_neq_null) {
1585 /* neq dst(r) src(r)
1587 Checks whether register src is not null, as with the ECMAScript '!='
1588 operator, and puts the result as a boolean in register dst.
1590 int dst = (++vPC)->u.operand;
1591 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1593 if (src->isUndefinedOrNull()) {
1594 r[dst] = jsBoolean(false);
1599 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined());
1603 BEGIN_OPCODE(op_stricteq) {
1604 /* stricteq dst(r) src1(r) src2(r)
1606 Checks whether register src1 and register src2 are strictly
1607 equal, as with the ECMAScript '===' operator, and puts the
1608 result as a boolean in register dst.
1610 int dst = (++vPC)->u.operand;
1611 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1612 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1613 if (JSImmediate::areBothImmediate(src1, src2))
1614 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1615 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1616 r[dst] = jsBoolean(false);
1618 r[dst] = jsBoolean(strictEqualSlowCase(src1, src2));
1623 BEGIN_OPCODE(op_nstricteq) {
1624 /* nstricteq dst(r) src1(r) src2(r)
1626 Checks whether register src1 and register src2 are not
1627 strictly equal, as with the ECMAScript '!==' operator, and
1628 puts the result as a boolean in register dst.
1630 int dst = (++vPC)->u.operand;
1631 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1632 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1634 if (JSImmediate::areBothImmediate(src1, src2))
1635 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1636 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1637 r[dst] = jsBoolean(true);
1639 r[dst] = jsBoolean(!strictEqualSlowCase(src1, src2));
1644 BEGIN_OPCODE(op_less) {
1645 /* less dst(r) src1(r) src2(r)
1647 Checks whether register src1 is less than register src2, as
1648 with the ECMAScript '<' operator, and puts the result as
1649 a boolean in register dst.
1651 int dst = (++vPC)->u.operand;
1652 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1653 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1654 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1655 VM_CHECK_EXCEPTION();
1661 BEGIN_OPCODE(op_lesseq) {
1662 /* lesseq dst(r) src1(r) src2(r)
1664 Checks whether register src1 is less than or equal to
1665 register src2, as with the ECMAScript '<=' operator, and
1666 puts the result as a boolean in register dst.
1668 int dst = (++vPC)->u.operand;
1669 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1670 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1671 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1672 VM_CHECK_EXCEPTION();
1678 BEGIN_OPCODE(op_pre_inc) {
1679 /* pre_inc srcDst(r)
1681 Converts register srcDst to number, adds one, and puts the result
1682 back in register srcDst.
1684 int srcDst = (++vPC)->u.operand;
1685 JSValue* v = r[srcDst].jsValue(exec);
1686 if (JSImmediate::canDoFastAdditiveOperations(v))
1687 r[srcDst] = JSImmediate::incImmediateNumber(v);
1689 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1690 VM_CHECK_EXCEPTION();
1697 BEGIN_OPCODE(op_pre_dec) {
1698 /* pre_dec srcDst(r)
1700 Converts register srcDst to number, subtracts one, and puts the result
1701 back in register srcDst.
1703 int srcDst = (++vPC)->u.operand;
1704 JSValue* v = r[srcDst].jsValue(exec);
1705 if (JSImmediate::canDoFastAdditiveOperations(v))
1706 r[srcDst] = JSImmediate::decImmediateNumber(v);
1708 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1709 VM_CHECK_EXCEPTION();
1716 BEGIN_OPCODE(op_post_inc) {
1717 /* post_inc dst(r) srcDst(r)
1719 Converts register srcDst to number. The number itself is
1720 written to register dst, and the number plus one is written
1721 back to register srcDst.
1723 int dst = (++vPC)->u.operand;
1724 int srcDst = (++vPC)->u.operand;
1725 JSValue* v = r[srcDst].jsValue(exec);
1726 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1728 r[srcDst] = JSImmediate::incImmediateNumber(v);
1730 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1731 VM_CHECK_EXCEPTION();
1733 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1739 BEGIN_OPCODE(op_post_dec) {
1740 /* post_dec dst(r) srcDst(r)
1742 Converts register srcDst to number. The number itself is
1743 written to register dst, and the number minus one is written
1744 back to register srcDst.
1746 int dst = (++vPC)->u.operand;
1747 int srcDst = (++vPC)->u.operand;
1748 JSValue* v = r[srcDst].jsValue(exec);
1749 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1751 r[srcDst] = JSImmediate::decImmediateNumber(v);
1753 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1754 VM_CHECK_EXCEPTION();
1756 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1762 BEGIN_OPCODE(op_to_jsnumber) {
1763 /* to_jsnumber dst(r) src(r)
1765 Converts register src to number, and puts the result
1768 int dst = (++vPC)->u.operand;
1769 int src = (++vPC)->u.operand;
1770 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1771 VM_CHECK_EXCEPTION();
1778 BEGIN_OPCODE(op_negate) {
1779 /* negate dst(r) src(r)
1781 Converts register src to number, negates it, and puts the
1782 result in register dst.
1784 int dst = (++vPC)->u.operand;
1785 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1787 if (fastIsNumber(src, v))
1788 r[dst] = jsNumber(exec, -v);
1790 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1791 VM_CHECK_EXCEPTION();
1798 BEGIN_OPCODE(op_add) {
1799 /* add dst(r) src1(r) src2(r)
1801 Adds register src1 and register src2, and puts the result
1802 in register dst. (JS add may be string concatenation or
1803 numeric add, depending on the types of the operands.)
1805 int dst = (++vPC)->u.operand;
1806 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1807 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1808 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1809 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1811 JSValue* result = jsAdd(exec, src1, src2);
1812 VM_CHECK_EXCEPTION();
1818 BEGIN_OPCODE(op_mul) {
1819 /* mul dst(r) src1(r) src2(r)
1821 Multiplies register src1 and register src2 (converted to
1822 numbers), and puts the product in register dst.
1824 int dst = (++vPC)->u.operand;
1825 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1826 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1829 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1830 r[dst] = jsNumber(exec, left * right);
1832 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1833 VM_CHECK_EXCEPTION();
1840 BEGIN_OPCODE(op_div) {
1841 /* div dst(r) dividend(r) divisor(r)
1843 Divides register dividend (converted to number) by the
1844 register divisor (converted to number), and puts the
1845 quotient in register dst.
1847 int dst = (++vPC)->u.operand;
1848 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1849 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1852 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1853 r[dst] = jsNumber(exec, left / right);
1855 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1856 VM_CHECK_EXCEPTION();
1862 BEGIN_OPCODE(op_mod) {
1863 /* mod dst(r) dividend(r) divisor(r)
1865 Divides register dividend (converted to number) by
1866 register divisor (converted to number), and puts the
1867 remainder in register dst.
1869 int dst = (++vPC)->u.operand;
1870 int dividend = (++vPC)->u.operand;
1871 int divisor = (++vPC)->u.operand;
1873 JSValue* dividendValue = r[dividend].jsValue(exec);
1874 JSValue* divisorValue = r[divisor].jsValue(exec);
1876 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1877 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1882 double d = dividendValue->toNumber(exec);
1883 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1884 VM_CHECK_EXCEPTION();
1889 BEGIN_OPCODE(op_sub) {
1890 /* sub dst(r) src1(r) src2(r)
1892 Subtracts register src2 (converted to number) from register
1893 src1 (converted to number), and puts the difference in
1896 int dst = (++vPC)->u.operand;
1897 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1898 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1901 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1902 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1903 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1904 r[dst] = jsNumber(exec, left - right);
1906 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1907 VM_CHECK_EXCEPTION();
1913 BEGIN_OPCODE(op_lshift) {
1914 /* lshift dst(r) val(r) shift(r)
1916 Performs left shift of register val (converted to int32) by
1917 register shift (converted to uint32), and puts the result
1920 int dst = (++vPC)->u.operand;
1921 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1922 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1925 if (JSImmediate::areBothImmediateNumbers(val, shift))
1926 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1927 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1928 r[dst] = jsNumber(exec, left << (right & 0x1f));
1930 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1931 VM_CHECK_EXCEPTION();
1938 BEGIN_OPCODE(op_rshift) {
1939 /* rshift dst(r) val(r) shift(r)
1941 Performs arithmetic right shift of register val (converted
1942 to int32) by register shift (converted to
1943 uint32), and puts the result in register dst.
1945 int dst = (++vPC)->u.operand;
1946 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1947 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1950 if (JSImmediate::areBothImmediateNumbers(val, shift))
1951 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1952 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1953 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1955 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1956 VM_CHECK_EXCEPTION();
1963 BEGIN_OPCODE(op_urshift) {
1964 /* rshift dst(r) val(r) shift(r)
1966 Performs logical right shift of register val (converted
1967 to uint32) by register shift (converted to
1968 uint32), and puts the result in register dst.
1970 int dst = (++vPC)->u.operand;
1971 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1972 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1973 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1974 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1976 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1977 VM_CHECK_EXCEPTION();
1984 BEGIN_OPCODE(op_bitand) {
1985 /* bitand dst(r) src1(r) src2(r)
1987 Computes bitwise AND of register src1 (converted to int32)
1988 and register src2 (converted to int32), and puts the result
1991 int dst = (++vPC)->u.operand;
1992 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1993 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1996 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1997 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1998 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1999 r[dst] = jsNumber(exec, left & right);
2001 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
2002 VM_CHECK_EXCEPTION();
2009 BEGIN_OPCODE(op_bitxor) {
2010 /* bitxor dst(r) src1(r) src2(r)
2012 Computes bitwise XOR of register src1 (converted to int32)
2013 and register src2 (converted to int32), and puts the result
2016 int dst = (++vPC)->u.operand;
2017 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2018 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2021 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2022 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
2023 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2024 r[dst] = jsNumber(exec, left ^ right);
2026 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
2027 VM_CHECK_EXCEPTION();
2034 BEGIN_OPCODE(op_bitor) {
2035 /* bitor dst(r) src1(r) src2(r)
2037 Computes bitwise OR of register src1 (converted to int32)
2038 and register src2 (converted to int32), and puts the
2039 result in register dst.
2041 int dst = (++vPC)->u.operand;
2042 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2043 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2046 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2047 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
2048 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2049 r[dst] = jsNumber(exec, left | right);
2051 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
2052 VM_CHECK_EXCEPTION();
2059 BEGIN_OPCODE(op_bitnot) {
2060 /* bitnot dst(r) src(r)
2062 Computes bitwise NOT of register src1 (converted to int32),
2063 and puts the result in register dst.
2065 int dst = (++vPC)->u.operand;
2066 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
2068 if (fastToInt32(src, value))
2069 r[dst] = jsNumber(exec, ~value);
2071 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
2072 VM_CHECK_EXCEPTION();
2078 BEGIN_OPCODE(op_not) {
2079 /* not dst(r) src(r)
2081 Computes logical NOT of register src (converted to
2082 boolean), and puts the result in register dst.
2084 int dst = (++vPC)->u.operand;
2085 int src = (++vPC)->u.operand;
2086 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
2087 VM_CHECK_EXCEPTION();
2093 BEGIN_OPCODE(op_instanceof) {
2094 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2096 Tests whether register value is an instance of register
2097 constructor, and puts the boolean result in register
2098 dst. Register constructorProto must contain the "prototype"
2099 property (not the actual prototype) of the object in
2100 register constructor. This lookup is separated so that
2101 polymorphic inline caching can apply.
2103 Raises an exception if register constructor is not an
2106 int dst = (++vPC)->u.operand;
2107 int value = (++vPC)->u.operand;
2108 int base = (++vPC)->u.operand;
2109 int baseProto = (++vPC)->u.operand;
2111 JSValue* baseVal = r[base].jsValue(exec);
2113 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
2116 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2117 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec), r[baseProto].jsValue(exec)) : false);
2122 BEGIN_OPCODE(op_typeof) {
2123 /* typeof dst(r) src(r)
2125 Determines the type string for src according to ECMAScript
2126 rules, and puts the result in register dst.
2128 int dst = (++vPC)->u.operand;
2129 int src = (++vPC)->u.operand;
2130 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2135 BEGIN_OPCODE(op_is_undefined) {
2136 /* is_undefined dst(r) src(r)
2138 Determines whether the type string for src according to
2139 the ECMAScript rules is "undefined", and puts the result
2142 int dst = (++vPC)->u.operand;
2143 int src = (++vPC)->u.operand;
2144 JSValue* v = r[src].jsValue(exec);
2145 r[dst] = jsBoolean(v->isUndefined() || (v->isObject() && static_cast<JSObject*>(v)->masqueradeAsUndefined()));
2150 BEGIN_OPCODE(op_is_boolean) {
2151 /* is_boolean dst(r) src(r)
2153 Determines whether the type string for src according to
2154 the ECMAScript rules is "boolean", and puts the result
2157 int dst = (++vPC)->u.operand;
2158 int src = (++vPC)->u.operand;
2159 r[dst] = jsBoolean(r[src].jsValue(exec)->isBoolean());
2164 BEGIN_OPCODE(op_is_number) {
2165 /* is_number dst(r) src(r)
2167 Determines whether the type string for src according to
2168 the ECMAScript rules is "number", and puts the result
2171 int dst = (++vPC)->u.operand;
2172 int src = (++vPC)->u.operand;
2173 r[dst] = jsBoolean(r[src].jsValue(exec)->isNumber());
2178 BEGIN_OPCODE(op_is_string) {
2179 /* is_string dst(r) src(r)
2181 Determines whether the type string for src according to
2182 the ECMAScript rules is "string", and puts the result
2185 int dst = (++vPC)->u.operand;
2186 int src = (++vPC)->u.operand;
2187 r[dst] = jsBoolean(r[src].jsValue(exec)->isString());
2192 BEGIN_OPCODE(op_is_object) {
2193 /* is_object dst(r) src(r)
2195 Determines whether the type string for src according to
2196 the ECMAScript rules is "object", and puts the result
2199 int dst = (++vPC)->u.operand;
2200 int src = (++vPC)->u.operand;
2201 r[dst] = jsBoolean(jsIsObjectType(r[src].jsValue(exec)));
2206 BEGIN_OPCODE(op_is_function) {
2207 /* is_function dst(r) src(r)
2209 Determines whether the type string for src according to
2210 the ECMAScript rules is "function", and puts the result
2213 int dst = (++vPC)->u.operand;
2214 int src = (++vPC)->u.operand;
2215 r[dst] = jsBoolean(jsIsFunctionType(r[src].jsValue(exec)));
2220 BEGIN_OPCODE(op_in) {
2221 /* in dst(r) property(r) base(r)
2223 Tests whether register base has a property named register
2224 property, and puts the boolean result in register dst.
2226 Raises an exception if register constructor is not an
2229 int dst = (++vPC)->u.operand;
2230 int property = (++vPC)->u.operand;
2231 int base = (++vPC)->u.operand;
2233 JSValue* baseVal = r[base].jsValue(exec);
2234 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
2237 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2239 JSValue* propName = r[property].jsValue(exec);
2242 if (propName->getUInt32(i))
2243 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2245 Identifier property(exec, propName->toString(exec));
2246 VM_CHECK_EXCEPTION();
2247 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2253 BEGIN_OPCODE(op_resolve) {
2254 /* resolve dst(r) property(id)
2256 Looks up the property named by identifier property in the
2257 scope chain, and writes the resulting value to register
2258 dst. If the property is not found, raises an exception.
2260 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2266 BEGIN_OPCODE(op_resolve_skip) {
2267 /* resolve_skip dst(r) property(id) skip(n)
2269 Looks up the property named by identifier property in the
2270 scope chain skipping the top 'skip' levels, and writes the resulting
2271 value to register dst. If the property is not found, raises an exception.
2273 if (UNLIKELY(!resolveSkip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2280 BEGIN_OPCODE(op_resolve_global) {
2281 /* resolve_skip dst(r) globalObject(c) property(id) structureID(sID) offset(n)
2283 Performs a dynamic property lookup for the given property, on the provided
2284 global object. If structureID matches the StructureID of the global then perform
2285 a fast lookup using the case offset, otherwise fall back to a full resolve and
2286 cache the new structureID and offset
2288 if (UNLIKELY(!resolveGlobal(exec, vPC, r, codeBlock, exceptionValue)))
2295 BEGIN_OPCODE(op_get_global_var) {
2296 /* get_global_var dst(r) globalObject(c) index(n)
2298 Gets the global var at global slot index and places it in register dst.
2300 int dst = (++vPC)->u.operand;
2301 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2302 ASSERT(scope->isGlobalObject());
2303 int index = (++vPC)->u.operand;
2305 r[dst] = scope->registerAt(index);
2309 BEGIN_OPCODE(op_put_global_var) {
2310 /* put_global_var globalObject(c) index(n) value(r)
2312 Puts value into global slot index.
2314 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2315 ASSERT(scope->isGlobalObject());
2316 int index = (++vPC)->u.operand;
2317 int value = (++vPC)->u.operand;
2319 scope->registerAt(index) = r[value].jsValue(exec);
2323 BEGIN_OPCODE(op_get_scoped_var) {
2324 /* get_scoped_var dst(r) index(n) skip(n)
2326 Loads the contents of the index-th local from the scope skip nodes from
2327 the top of the scope chain, and places it in register dst
2329 int dst = (++vPC)->u.operand;
2330 int index = (++vPC)->u.operand;
2331 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2333 ScopeChainIterator iter = scopeChain->begin();
2334 ScopeChainIterator end = scopeChain->end();
2335 ASSERT(iter != end);
2338 ASSERT(iter != end);
2341 ASSERT((*iter)->isVariableObject());
2342 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2343 r[dst] = scope->registerAt(index);
2347 BEGIN_OPCODE(op_put_scoped_var) {
2348 /* put_scoped_var index(n) skip(n) value(r)
2351 int index = (++vPC)->u.operand;
2352 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2353 int value = (++vPC)->u.operand;
2355 ScopeChainIterator iter = scopeChain->begin();
2356 ScopeChainIterator end = scopeChain->end();
2357 ASSERT(iter != end);
2360 ASSERT(iter != end);
2363 ASSERT((*iter)->isVariableObject());
2364 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2365 scope->registerAt(index) = r[value].jsValue(exec);
2369 BEGIN_OPCODE(op_resolve_base) {
2370 /* resolve_base dst(r) property(id)
2372 Searches the scope chain for an object containing
2373 identifier property, and if one is found, writes it to
2374 register dst. If none is found, the outermost scope (which
2375 will be the global object) is stored in register dst.
2377 resolveBase(exec, vPC, r, scopeChain, codeBlock);
2382 BEGIN_OPCODE(op_resolve_with_base) {
2383 /* resolve_with_base baseDst(r) propDst(r) property(id)
2385 Searches the scope chain for an object containing
2386 identifier property, and if one is found, writes it to
2387 register srcDst, and the retrieved property value to register
2388 propDst. If the property is not found, raises an exception.
2390 This is more efficient than doing resolve_base followed by
2391 resolve, or resolve_base followed by get_by_id, as it
2392 avoids duplicate hash lookups.
2394 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2400 BEGIN_OPCODE(op_resolve_func) {
2401 /* resolve_func baseDst(r) funcDst(r) property(id)
2403 Searches the scope chain for an object containing
2404 identifier property, and if one is found, writes the
2405 appropriate object to use as "this" when calling its
2406 properties to register baseDst; and the retrieved property
2407 value to register propDst. If the property is not found,
2408 raises an exception.
2410 This differs from resolve_with_base, because the
2411 global this value will be substituted for activations or
2412 the global object, which is the right behavior for function
2413 calls but not for other property lookup.
2415 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2421 BEGIN_OPCODE(op_get_by_id) {
2422 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2424 Generic property access: Gets the property named by identifier
2425 property from the value base, and puts the result in register dst.
2427 int dst = vPC[1].u.operand;
2428 int base = vPC[2].u.operand;
2429 int property = vPC[3].u.operand;
2431 Identifier& ident = codeBlock->identifiers[property];
2432 JSValue* baseValue = r[base].jsValue(exec);
2433 PropertySlot slot(baseValue);
2434 JSValue* result = baseValue->get(exec, ident, slot);
2435 VM_CHECK_EXCEPTION();
2437 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2443 BEGIN_OPCODE(op_get_by_id_self) {
2444 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2446 Cached property access: Attempts to get a cached property from the
2447 value base. If the cache misses, op_get_by_id_self reverts to
2450 int base = vPC[2].u.operand;
2451 JSValue* baseValue = r[base].jsValue(exec);
2453 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2454 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2455 StructureID* structureID = vPC[4].u.structureID;
2457 if (LIKELY(baseCell->structureID() == structureID)) {
2458 ASSERT(baseCell->isObject());
2459 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2460 int dst = vPC[1].u.operand;
2461 int offset = vPC[5].u.operand;
2463 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2464 r[dst] = baseObject->getDirectOffset(offset);
2471 uncacheGetByID(codeBlock, vPC);
2474 BEGIN_OPCODE(op_get_by_id_proto) {
2475 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2477 Cached property access: Attempts to get a cached property from the
2478 value base's prototype. If the cache misses, op_get_by_id_proto
2479 reverts to op_get_by_id.
2481 int base = vPC[2].u.operand;
2482 JSValue* baseValue = r[base].jsValue(exec);
2484 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2485 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2486 StructureID* structureID = vPC[4].u.structureID;
2488 if (LIKELY(baseCell->structureID() == structureID)) {
2489 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2490 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2491 StructureID* protoStructureID = vPC[5].u.structureID;
2493 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2494 int dst = vPC[1].u.operand;
2495 int offset = vPC[6].u.operand;
2497 ASSERT(protoObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2498 r[dst] = protoObject->getDirectOffset(offset);
2506 uncacheGetByID(codeBlock, vPC);
2509 BEGIN_OPCODE(op_get_by_id_chain) {
2510 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2512 Cached property access: Attempts to get a cached property from the
2513 value base's prototype chain. If the cache misses, op_get_by_id_chain
2514 reverts to op_get_by_id.
2516 int base = vPC[2].u.operand;
2517 JSValue* baseValue = r[base].jsValue(exec);
2519 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2520 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2521 StructureID* structureID = vPC[4].u.structureID;
2523 if (LIKELY(baseCell->structureID() == structureID)) {
2524 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2525 size_t count = vPC[6].u.operand;
2526 RefPtr<StructureID>* end = it + count;
2528 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2530 baseObject = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2531 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2535 int dst = vPC[1].u.operand;
2536 int offset = vPC[7].u.operand;
2538 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2539 r[dst] = baseObject->getDirectOffset(offset);
2548 uncacheGetByID(codeBlock, vPC);
2551 BEGIN_OPCODE(op_get_by_id_generic) {
2552 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2554 Generic property access: Gets the property named by identifier
2555 property from the value base, and puts the result in register dst.
2557 int dst = vPC[1].u.operand;
2558 int base = vPC[2].u.operand;
2559 int property = vPC[3].u.operand;
2561 Identifier& ident = codeBlock->identifiers[property];
2563 JSValue* baseValue = r[base].jsValue(exec);
2564 PropertySlot slot(baseValue);
2565 JSValue* result = baseValue->get(exec, ident, slot);
2566 VM_CHECK_EXCEPTION();
2572 BEGIN_OPCODE(op_get_array_length) {
2573 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2575 Cached property access: Gets the length of the array in register base,
2576 and puts the result in register dst. If register base does not hold
2577 an array, op_get_array_length reverts to op_get_by_id.
2580 int base = vPC[2].u.operand;
2581 JSValue* baseValue = r[base].jsValue(exec);
2582 if (LIKELY(isJSArray(baseValue))) {
2583 int dst = vPC[1].u.operand;
2584 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2589 uncacheGetByID(codeBlock, vPC);
2592 BEGIN_OPCODE(op_get_string_length) {
2593 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2595 Cached property access: Gets the length of the string in register base,
2596 and puts the result in register dst. If register base does not hold
2597 a string, op_get_string_length reverts to op_get_by_id.
2600 int base = vPC[2].u.operand;
2601 JSValue* baseValue = r[base].jsValue(exec);
2602 if (LIKELY(isJSString(baseValue))) {
2603 int dst = vPC[1].u.operand;
2604 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2609 uncacheGetByID(codeBlock, vPC);
2612 BEGIN_OPCODE(op_put_by_id) {
2613 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2615 Generic property access: Sets the property named by identifier
2616 property, belonging to register base, to register value.
2618 Unlike many opcodes, this one does not write any output to
2622 int base = vPC[1].u.operand;
2623 int property = vPC[2].u.operand;
2624 int value = vPC[3].u.operand;
2626 JSValue* baseValue = r[base].jsValue(exec);
2628 PutPropertySlot slot;
2629 Identifier& ident = codeBlock->identifiers[property];
2630 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2631 VM_CHECK_EXCEPTION();
2633 tryCachePutByID(exec, codeBlock, vPC, baseValue, slot);
2638 BEGIN_OPCODE(op_put_by_id_transition) {
2639 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2641 Cached property access: Attempts to set a new property with a cached transition
2642 property named by identifier property, belonging to register base,
2643 to register value. If the cache misses, op_put_by_id_transition
2644 reverts to op_put_by_id_generic.
2646 Unlike many opcodes, this one does not write any output to
2649 int base = vPC[1].u.operand;
2650 JSValue* baseValue = r[base].jsValue(exec);
2652 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2653 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2654 StructureID* oldStructureID = vPC[4].u.structureID;
2655 StructureID* newStructureID = vPC[5].u.structureID;
2657 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2658 ASSERT(baseCell->isObject());
2659 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2661 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2663 JSObject* proto = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2664 while (!proto->isNull()) {
2665 if (UNLIKELY(proto->structureID() != (*it).get())) {
2666 uncachePutByID(codeBlock, vPC);
2670 proto = static_cast<JSObject*>(proto->structureID()->prototypeForLookup(exec));
2673 baseObject->transitionTo(newStructureID);
2674 if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
2675 baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
2677 int value = vPC[3].u.operand;
2678 unsigned offset = vPC[7].u.operand;
2679 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2680 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2687 uncachePutByID(codeBlock, vPC);
2690 BEGIN_OPCODE(op_put_by_id_replace) {
2691 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2693 Cached property access: Attempts to set a pre-existing, cached
2694 property named by identifier property, belonging to register base,
2695 to register value. If the cache misses, op_put_by_id_replace
2696 reverts to op_put_by_id.
2698 Unlike many opcodes, this one does not write any output to
2701 int base = vPC[1].u.operand;
2702 JSValue* baseValue = r[base].jsValue(exec);
2704 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2705 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2706 StructureID* structureID = vPC[4].u.structureID;
2708 if (LIKELY(baseCell->structureID() == structureID)) {
2709 ASSERT(baseCell->isObject());
2710 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2711 int value = vPC[3].u.operand;
2712 unsigned offset = vPC[5].u.operand;
2714 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2715 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2722 uncachePutByID(codeBlock, vPC);
2725 BEGIN_OPCODE(op_put_by_id_generic) {
2726 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2728 Generic property access: Sets the property named by identifier
2729 property, belonging to register base, to register value.
2731 Unlike many opcodes, this one does not write any output to
2734 int base = vPC[1].u.operand;
2735 int property = vPC[2].u.operand;
2736 int value = vPC[3].u.operand;
2738 JSValue* baseValue = r[base].jsValue(exec);
2740 PutPropertySlot slot;
2741 Identifier& ident = codeBlock->identifiers[property];
2742 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2743 VM_CHECK_EXCEPTION();
2748 BEGIN_OPCODE(op_del_by_id) {
2749 /* del_by_id dst(r) base(r) property(id)
2751 Converts register base to Object, deletes the property
2752 named by identifier property from the object, and writes a
2753 boolean indicating success (if true) or failure (if false)
2756 int dst = (++vPC)->u.operand;
2757 int base = (++vPC)->u.operand;
2758 int property = (++vPC)->u.operand;
2760 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2762 Identifier& ident = codeBlock->identifiers[property];
2763 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2764 VM_CHECK_EXCEPTION();
2769 BEGIN_OPCODE(op_get_by_val) {
2770 /* get_by_val dst(r) base(r) property(r)
2772 Converts register base to Object, gets the property named
2773 by register property from the object, and puts the result
2774 in register dst. property is nominally converted to string
2775 but numbers are treated more efficiently.
2777 int dst = (++vPC)->u.operand;
2778 int base = (++vPC)->u.operand;
2779 int property = (++vPC)->u.operand;
2781 JSValue* baseValue = r[base].jsValue(exec);
2782 JSValue* subscript = r[property].jsValue(exec);
2787 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2788 if (LIKELY(isUInt32)) {
2789 if (isJSArray(baseValue)) {
2790 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2791 if (jsArray->canGetIndex(i))
2792 result = jsArray->getIndex(i);
2794 result = jsArray->JSArray::get(exec, i);
2795 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2796 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2798 result = baseValue->get(exec, i);
2800 Identifier property(exec, subscript->toString(exec));
2801 result = baseValue->get(exec, property);
2804 VM_CHECK_EXCEPTION();
2809 BEGIN_OPCODE(op_put_by_val) {
2810 /* put_by_val base(r) property(r) value(r)
2812 Sets register value on register base as the property named
2813 by register property. Base is converted to object
2814 first. register property is nominally converted to string
2815 but numbers are treated more efficiently.
2817 Unlike many opcodes, this one does not write any output to
2820 int base = (++vPC)->u.operand;
2821 int property = (++vPC)->u.operand;
2822 int value = (++vPC)->u.operand;
2824 JSValue* baseValue = r[base].jsValue(exec);
2825 JSValue* subscript = r[property].jsValue(exec);
2829 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2830 if (LIKELY(isUInt32)) {
2831 if (isJSArray(baseValue)) {
2832 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2833 if (jsArray->canSetIndex(i))
2834 jsArray->setIndex(i, r[value].jsValue(exec));
2836 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2838 baseValue->put(exec, i, r[value].jsValue(exec));
2840 Identifier property(exec, subscript->toString(exec));
2841 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2842 PutPropertySlot slot;
2843 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2847 VM_CHECK_EXCEPTION();
2851 BEGIN_OPCODE(op_del_by_val) {
2852 /* del_by_val dst(r) base(r) property(r)
2854 Converts register base to Object, deletes the property
2855 named by register property from the object, and writes a
2856 boolean indicating success (if true) or failure (if false)
2859 int dst = (++vPC)->u.operand;
2860 int base = (++vPC)->u.operand;
2861 int property = (++vPC)->u.operand;
2863 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2865 JSValue* subscript = r[property].jsValue(exec);
2868 if (subscript->getUInt32(i))
2869 result = jsBoolean(baseObj->deleteProperty(exec, i));
2871 VM_CHECK_EXCEPTION();
2872 Identifier property(exec, subscript->toString(exec));
2873 VM_CHECK_EXCEPTION();
2874 result = jsBoolean(baseObj->deleteProperty(exec, property));
2877 VM_CHECK_EXCEPTION();
2882 BEGIN_OPCODE(op_put_by_index) {
2883 /* put_by_index base(r) property(n) value(r)
2885 Sets register value on register base as the property named
2886 by the immediate number property. Base is converted to
2889 Unlike many opcodes, this one does not write any output to
2892 This opcode is mainly used to initialize array literals.
2894 int base = (++vPC)->u.operand;
2895 unsigned property = (++vPC)->u.operand;
2896 int value = (++vPC)->u.operand;
2898 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2903 BEGIN_OPCODE(op_loop) {
2904 /* loop target(offset)
2906 Jumps unconditionally to offset target from the current
2909 Additionally this loop instruction may terminate JS execution is
2910 the JS timeout is reached.
2912 #if DUMP_OPCODE_STATS
2913 OpcodeStats::resetLastInstruction();
2915 int target = (++vPC)->u.operand;
2916 CHECK_FOR_TIMEOUT();
2920 BEGIN_OPCODE(op_jmp) {
2921 /* jmp target(offset)
2923 Jumps unconditionally to offset target from the current
2926 #if DUMP_OPCODE_STATS
2927 OpcodeStats::resetLastInstruction();
2929 int target = (++vPC)->u.operand;
2934 BEGIN_OPCODE(op_loop_if_true) {
2935 /* loop_if_true cond(r) target(offset)
2937 Jumps to offset target from the current instruction, if and
2938 only if register cond converts to boolean as true.
2940 Additionally this loop instruction may terminate JS execution is
2941 the JS timeout is reached.
2943 int cond = (++vPC)->u.operand;
2944 int target = (++vPC)->u.operand;
2945 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2947 CHECK_FOR_TIMEOUT();
2954 BEGIN_OPCODE(op_jtrue) {
2955 /* jtrue cond(r) target(offset)
2957 Jumps to offset target from the current instruction, if and
2958 only if register cond converts to boolean as true.
2960 int cond = (++vPC)->u.operand;
2961 int target = (++vPC)->u.operand;
2962 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2970 BEGIN_OPCODE(op_jfalse) {
2971 /* jfalse cond(r) target(offset)
2973 Jumps to offset target from the current instruction, if and
2974 only if register cond converts to boolean as false.
2976 int cond = (++vPC)->u.operand;
2977 int target = (++vPC)->u.operand;
2978 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2986 BEGIN_OPCODE(op_loop_if_less) {
2987 /* loop_if_less src1(r) src2(r) target(offset)
2989 Checks whether register src1 is less than register src2, as
2990 with the ECMAScript '<' operator, and then jumps to offset
2991 target from the current instruction, if and only if the
2992 result of the comparison is true.
2994 Additionally this loop instruction may terminate JS execution is
2995 the JS timeout is reached.
2997 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2998 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2999 int target = (++vPC)->u.operand;
3001 bool result = jsLess(exec, src1, src2);
3002 VM_CHECK_EXCEPTION();
3006 CHECK_FOR_TIMEOUT();
3013 BEGIN_OPCODE(op_loop_if_lesseq) {
3014 /* loop_if_lesseq src1(r) src2(r) target(offset)
3016 Checks whether register src1 is less than or equal to register
3017 src2, as with the ECMAScript '<=' operator, and then jumps to
3018 offset target from the current instruction, if and only if the
3019 result of the comparison is true.
3021 Additionally this loop instruction may terminate JS execution is
3022 the JS timeout is reached.
3024 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3025 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3026 int target = (++vPC)->u.operand;
3028 bool result = jsLessEq(exec, src1, src2);
3029 VM_CHECK_EXCEPTION();
3033 CHECK_FOR_TIMEOUT();
3040 BEGIN_OPCODE(op_jnless) {
3041 /* jnless src1(r) src2(r) target(offset)
3043 Checks whether register src1 is less than register src2, as
3044 with the ECMAScript '<' operator, and then jumps to offset
3045 target from the current instruction, if and only if the
3046 result of the comparison is false.
3048 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
3049 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
3050 int target = (++vPC)->u.operand;
3052 bool result = jsLess(exec, src1, src2);
3053 VM_CHECK_EXCEPTION();
3063 BEGIN_OPCODE(op_switch_imm) {
3064 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3066 Performs a range checked switch on the scrutinee value, using
3067 the tableIndex-th immediate switch jump table. If the scrutinee value
3068 is an immediate number in the range covered by the referenced jump
3069 table, and the value at jumpTable[scrutinee value] is non-zero, then
3070 that value is used as the jump offset, otherwise defaultOffset is used.
3072 int tableIndex = (++vPC)->u.operand;
3073 int defaultOffset = (++vPC)->u.operand;
3074 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3075 if (!JSImmediate::isNumber(scrutinee))
3076 vPC += defaultOffset;
3078 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3079 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
3083 BEGIN_OPCODE(op_switch_char) {
3084 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3086 Performs a range checked switch on the scrutinee value, using
3087 the tableIndex-th character switch jump table. If the scrutinee value
3088 is a single character string in the range covered by the referenced jump
3089 table, and the value at jumpTable[scrutinee value] is non-zero, then
3090 that value is used as the jump offset, otherwise defaultOffset is used.
3092 int tableIndex = (++vPC)->u.operand;
3093 int defaultOffset = (++vPC)->u.operand;
3094 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3095 if (!scrutinee->isString())
3096 vPC += defaultOffset;
3098 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
3099 if (value->size() != 1)
3100 vPC += defaultOffset;
3102 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
3106 BEGIN_OPCODE(op_switch_string) {
3107 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3109 Performs a sparse hashmap based switch on the value in the scrutinee
3110 register, using the tableIndex-th string switch jump table. If the
3111 scrutinee value is a string that exists as a key in the referenced
3112 jump table, then the value associated with the string is used as the
3113 jump offset, otherwise defaultOffset is used.
3115 int tableIndex = (++vPC)->u.operand;
3116 int defaultOffset = (++vPC)->u.operand;
3117 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3118 if (!scrutinee->isString())
3119 vPC += defaultOffset;
3121 vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
3124 BEGIN_OPCODE(op_new_func) {
3125 /* new_func dst(r) func(f)
3127 Constructs a new Function instance from function func and
3128 the current scope chain using the original Function
3129 constructor, using the rules for function declarations, and
3130 puts the result in register dst.
3132 int dst = (++vPC)->u.operand;
3133 int func = (++vPC)->u.operand;
3135 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
3140 BEGIN_OPCODE(op_new_func_exp) {
3141 /* new_func_exp dst(r) func(f)
3143 Constructs a new Function instance from function func and
3144 the current scope chain using the original Function
3145 constructor, using the rules for function expressions, and
3146 puts the result in register dst.
3148 int dst = (++vPC)->u.operand;
3149 int func = (++vPC)->u.operand;
3151 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
3156 BEGIN_OPCODE(op_call_eval) {
3157 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3159 Call a function named "eval" with no explicit "this" value
3160 (which may therefore be the eval operator). If register
3161 thisVal is the global object, and register func contains
3162 that global object's original global eval function, then
3163 perform the eval operator in local scope (interpreting
3164 the argument registers as for the "call"
3165 opcode). Otherwise, act exactly as the "call" opcode would.
3168 int dst = (++vPC)->u.operand;
3169 int func = (++vPC)->u.operand;
3170 int thisVal = (++vPC)->u.operand;
3171 int firstArg = (++vPC)->u.operand;
3172 int argCount = (++vPC)->u.operand;
3174 JSValue* funcVal = r[func].jsValue(exec);
3175 JSValue* baseVal = r[thisVal].jsValue(exec);
3177 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
3178 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
3179 JSValue* result = callEval(exec, codeBlock, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
3189 // We didn't find the blessed version of eval, so reset vPC and process
3190 // this instruction as a normal function call, supplying the proper 'this'
3193 r[thisVal] = baseVal->toThisObject(exec);
3195 #if HAVE(COMPUTED_GOTO)
3196 // Hack around gcc performance quirk by performing an indirect goto
3197 // in order to set the vPC -- attempting to do so directly results in a
3198 // significant regression.
3199 goto *op_call_indirect; // indirect goto -> op_call
3201 // fall through to op_call
3203 BEGIN_OPCODE(op_call) {
3204 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3206 Perform a function call. Specifically, call register func
3207 with a "this" value of register thisVal, and put the result
3210 The arguments start at register firstArg and go up to
3211 argCount, but the "this" value is considered an implicit
3212 first argument, so the argCount should be one greater than
3213 the number of explicit arguments passed, and the register
3214 after firstArg should contain the actual first
3215 argument. This opcode will copy from the thisVal register
3216 to the firstArg register, unless the register index of
3217 thisVal is the special missing this object marker, which is
3218 2^31-1; in that case, the global object will be used as the
3221 If func is a native code function, then this opcode calls
3222 it and returns the value immediately.
3224 But if it is a JS function, then the current scope chain
3225 and code block is set to the function's, and we slide the
3226 register window so that the arguments would form the first
3227 few local registers of the called function's register
3228 window. In addition, a call frame header is written
3229 immediately before the arguments; see the call frame
3230 documentation for an explanation of how many registers a
3231 call frame takes and what they contain. That many registers
3232 before the firstArg register will be overwritten by the
3233 call. In addition, any registers higher than firstArg +
3234 argCount may be overwritten. Once this setup is complete,
3235 execution continues from the called function's first
3236 argument, and does not return until a "ret" opcode is
3240 int dst = (++vPC)->u.operand;
3241 int func = (++vPC)->u.operand;
3242 int thisVal = (++vPC)->u.operand;
3243 int firstArg = (++vPC)->u.operand;
3244 int argCount = (++vPC)->u.operand;
3246 JSValue* v = r[func].jsValue(exec);
3249 CallType callType = v->getCallData(callData);
3251 if (*enabledProfilerReference)
3252 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3254 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3255 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, v);
3256 exec->m_callFrame = callFrame;
3258 if (callType == CallTypeJS) {
3260 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3261 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3262 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3264 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3266 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3267 if (UNLIKELY(exceptionValue != 0))
3270 codeBlock = newCodeBlock;
3271 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3272 vPC = codeBlock->instructions.begin();
3274 #if DUMP_OPCODE_STATS
3275 OpcodeStats::resetLastInstruction();
3281 if (callType == CallTypeHost) {
3282 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3283 ArgList args(r + firstArg + 1, argCount - 1);
3285 MACHINE_SAMPLING_callingHostFunction();
3287 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
3288 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3289 VM_CHECK_EXCEPTION();
3291 r[dst] = returnValue;
3293 if (*enabledProfilerReference)
3294 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3300 ASSERT(callType == CallTypeNone);
3302 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
3303 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3306 BEGIN_OPCODE(op_ret) {
3309 Return register result as the return value of the current
3310 function call, writing it into the caller's expected return
3311 value register. In addition, unwind one call frame and
3312 restore the scope chain, code block instruction pointer and
3313 register base to those of the calling function.
3316 int result = (++vPC)->u.operand;
3318 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3319 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
3320 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
3321 ASSERT(activation->isActivationObject());
3322 activation->copyRegisters();
3325 if (*enabledProfilerReference)
3326 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
3328 if (codeBlock->needsFullScopeChain)
3329 scopeChain->deref();
3331 JSValue* returnValue = r[result].jsValue(exec);
3333 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3337 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3338 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
3339 r = callFrame[RegisterFile::CallerRegisters].r();
3340 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3341 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
3342 r[dst] = returnValue;
3346 BEGIN_OPCODE(op_construct) {
3347 /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n)
3349 Invoke register "constr" as a constructor. For JS
3350 functions, the calling convention is exactly as for the
3351 "call" opcode, except that the "this" value is a newly
3352 created Object. For native constructors, a null "this"
3353 value is passed. In either case, the firstArg and argCount
3354 registers are interpreted as for the "call" opcode.
3356 Register constrProto must contain the prototype property of
3357 register constsr. This is to enable polymorphic inline
3358 caching of this lookup.
3361 int dst = (++vPC)->u.operand;
3362 int constr = (++vPC)->u.operand;
3363 int constrProto = (++vPC)->u.operand;
3364 int firstArg = (++vPC)->u.operand;
3365 int argCount = (++vPC)->u.operand;
3367 JSValue* constrVal = r[constr].jsValue(exec);
3369 ConstructData constructData;
3370 ConstructType constructType = constrVal->getConstructData(constructData);
3372 // Removing this line of code causes a measurable regression on squirrelfish.
3373 JSObject* constructor = static_cast<JSObject*>(constrVal);
3375 if (constructType == ConstructTypeJS) {
3376 if (*enabledProfilerReference)
3377 (*enabledProfilerReference)->willExecute(exec, constructor);
3379 JSObject* prototype;
3380 JSValue* p = r[constrProto].jsValue(exec);
3382 prototype = static_cast<JSObject*>(p);
3384 prototype = scopeChain->globalObject()->objectPrototype();
3385 JSObject* newObject = new (exec) JSObject(prototype);
3387 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3388 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3389 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3391 r[firstArg] = newObject; // "this" value
3393 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3394 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, constructor);
3395 exec->m_callFrame = callFrame;
3397 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3401 codeBlock = newCodeBlock;
3402 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3403 vPC = codeBlock->instructions.begin();
3408 if (constructType == ConstructTypeHost) {
3409 if (*enabledProfilerReference)
3410 (*enabledProfilerReference)->willExecute(exec, constructor);
3412 ArgList args(r + firstArg + 1, argCount - 1);
3414 MACHINE_SAMPLING_callingHostFunction();
3416 JSValue* returnValue = constructData.native.function(exec, constructor, args);
3418 VM_CHECK_EXCEPTION();
3419 r[dst] = returnValue;
3421 if (*enabledProfilerReference)
3422 (*enabledProfilerReference)->didExecute(exec, constructor);
3428 ASSERT(constructType == ConstructTypeNone);
3430 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
3433 BEGIN_OPCODE(op_construct_verify) {
3434 /* construct_verify dst(r) override(r)
3436 Verifies that register dst holds an object. If not, moves
3437 the object in register override to register dst.
3440 int dst = vPC[1].u.operand;;
3441 if (LIKELY(r[dst].jsValue(exec)->isObject())) {
3446 int override = vPC[2].u.operand;
3447 r[dst] = r[override];
3452 BEGIN_OPCODE(op_push_scope) {
3453 /* push_scope scope(r)
3455 Converts register scope to object, and pushes it onto the top
3456 of the current scope chain.
3458 int scope = (++vPC)->u.operand;
3459 JSValue* v = r[scope].jsValue(exec);
3460 JSObject* o = v->toObject(exec);
3461 VM_CHECK_EXCEPTION();
3463 setScopeChain(exec, scopeChain, scopeChain->push(o));
3468 BEGIN_OPCODE(op_pop_scope) {
3471 Removes the top item from the current scope chain.
3473 setScopeChain(exec, scopeChain, scopeChain->pop());
3478 BEGIN_OPCODE(op_get_pnames) {
3479 /* get_pnames dst(r) base(r)
3481 Creates a property name list for register base and puts it
3482 in register dst. This is not a true JavaScript value, just
3483 a synthetic value used to keep the iteration state in a
3486 int dst = (++vPC)->u.operand;
3487 int base = (++vPC)->u.operand;
3489 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
3493 BEGIN_OPCODE(op_next_pname) {
3494 /* next_pname dst(r) iter(r) target(offset)
3496 Tries to copies the next name from property name list in
3497 register iter. If there are names left, then copies one to
3498 register dst, and jumps to offset target. If there are none
3499 left, invalidates the iterator and continues to the next
3502 int dst = (++vPC)->u.operand;
3503 int iter = (++vPC)->u.operand;
3504 int target = (++vPC)->u.operand;
3506 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
3507 if (JSValue* temp = it->next(exec)) {
3508 CHECK_FOR_TIMEOUT();
3518 BEGIN_OPCODE(op_jmp_scopes) {
3519 /* jmp_scopes count(n) target(offset)
3521 Removes the a number of items from the current scope chain
3522 specified by immediate number count, then jumps to offset
3525 int count = (++vPC)->u.operand;
3526 int target = (++vPC)->u.operand;
3528 ScopeChainNode* tmp = scopeChain;
3531 setScopeChain(exec, scopeChain, tmp);
3536 #if HAVE(COMPUTED_GOTO)
3538 goto *(&&skip_new_scope);
3540 BEGIN_OPCODE(op_push_new_scope) {
3541 /* new_scope dst(r) property(id) value(r)
3543 Constructs a new StaticScopeObject with property set to value. That scope
3544 object is then pushed onto the ScopeChain. The scope object is then stored
3547 setScopeChain(exec, scopeChain, createExceptionScope(exec, codeBlock, vPC, r, scopeChain));
3551 #if HAVE(COMPUTED_GOTO)
3554 BEGIN_OPCODE(op_catch) {
3557 Retrieves the VMs current exception and puts it in register
3558 ex. This is only valid after an exception has been raised,
3559 and usually forms the beginning of an exception handler.
3561 ASSERT(exceptionValue);
3562 ASSERT(!exec->hadException());
3563 int ex = (++vPC)->u.operand;
3564 r[ex] = exceptionValue;
3570 BEGIN_OPCODE(op_throw) {
3573 Throws register ex as an exception. This involves three
3574 steps: first, it is set as the current exception in the
3575 VM's internal state, then the stack is unwound until an
3576 exception handler or a native code boundary is found, and
3577 then control resumes at the exception handler if any or
3578 else the script returns control to the nearest native caller.
3581 int ex = (++vPC)->u.operand;
3582 exceptionValue = r[ex].jsValue(exec);
3584 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, true);
3586 *exception = exceptionValue;
3590 #if HAVE(COMPUTED_GOTO)
3591 // Hack around gcc performance quirk by performing an indirect goto
3592 // in order to set the vPC -- attempting to do so directly results in a
3593 // significant regression.
3594 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
3602 BEGIN_OPCODE(op_unexpected_load) {
3603 /* unexpected_load load dst(r) src(k)
3605 Copies constant src to register dst.
3607 int dst = (++vPC)->u.operand;
3608 int src = (++vPC)->u.operand;
3609 r[dst] = codeBlock->unexpectedConstants[src];
3614 BEGIN_OPCODE(op_new_error) {
3615 /* new_error dst(r) type(n) message(k)
3617 Constructs a new Error instance using the original
3618 constructor, using immediate number n as the type and
3619 constant message as the message string. The result is
3620 written to register dst.
3622 int dst = (++vPC)->u.operand;
3623 int type = (++vPC)->u.operand;
3624 int message = (++vPC)->u.operand;
3626 r[dst] = Error::create(exec, (ErrorType)type, codeBlock->unexpectedConstants[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
3631 BEGIN_OPCODE(op_end) {
3634 Return register result as the value of a global or eval
3635 program. Return control to the calling native code.
3638 if (codeBlock->needsFullScopeChain) {
3639 ASSERT(scopeChain->refCount > 1);
3640 scopeChain->deref();
3642 int result = (++vPC)->u.operand;
3643 return r[result].jsValue(exec);
3645 BEGIN_OPCODE(op_put_getter) {
3646 /* put_getter base(r) property(id) function(r)
3648 Sets register function on register base as the getter named
3649 by identifier property. Base and function are assumed to be
3650 objects as this op should only be used for getters defined
3651 in object literal form.
3653 Unlike many opcodes, this one does not write any output to
3656 int base = (++vPC)->u.operand;
3657 int property = (++vPC)->u.operand;
3658 int function = (++vPC)->u.operand;
3660 ASSERT(r[base].jsValue(exec)->isObject());
3661 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
3662 Identifier& ident = codeBlock->identifiers[property];
3663 ASSERT(r[function].jsValue(exec)->isObject());
3664 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
3669 BEGIN_OPCODE(op_put_setter) {
3670 /* put_setter base(r) property(id) function(r)
3672 Sets register function on register base as the setter named
3673 by identifier property. Base and function are assumed to be
3674 objects as this op should only be used for setters defined
3675 in object literal form.
3677 Unlike many opcodes, this one does not write any output to
3680 int base = (++vPC)->u.operand;
3681 int property = (++vPC)->u.operand;
3682 int function = (++vPC)->u.operand;
3684 ASSERT(r[base].jsValue(exec)->isObject());
3685 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
3686 Identifier& ident = codeBlock->identifiers[property];
3687 ASSERT(r[function].jsValue(exec)->isObject());
3688 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
3693 BEGIN_OPCODE(op_jsr) {
3694 /* jsr retAddrDst(r) target(offset)
3696 Places the address of the next instruction into the retAddrDst
3697 register and jumps to offset target from the current instruction.
3699 int retAddrDst = (++vPC)->u.operand;
3700 int target = (++vPC)->u.operand;
3701 r[retAddrDst] = vPC + 1;
3706 BEGIN_OPCODE(op_sret) {
3707 /* sret retAddrSrc(r)
3709 Jumps to the address stored in the retAddrSrc register. This
3710 differs from op_jmp because the target address is stored in a
3711 register, not as an immediate.
3713 int retAddrSrc = (++vPC)->u.operand;
3714 vPC = r[retAddrSrc].vPC();
3717 BEGIN_OPCODE(op_debug) {
3718 /* debug debugHookID(n) firstLine(n) lastLine(n)
3720 Notifies the debugger of the current state of execution. This opcode
3721 is only generated while the debugger is attached.
3723 int debugHookID = (++vPC)->u.operand;
3724 int firstLine = (++vPC)->u.operand;
3725 int lastLine = (++vPC)->u.operand;
3727 debug(exec, codeBlock, scopeChain, r, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3733 exec->clearException();
3735 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3736 // cannot fathom if we don't assign to the exceptionValue before branching)
3737 exceptionValue = createInterruptedExecutionException(exec);
3739 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, false);
3741 *exception = exceptionValue;
3750 #undef VM_CHECK_EXCEPTION
3751 #undef CHECK_FOR_TIMEOUT
3754 JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
3756 Register* callFrame = this->callFrame(exec, function);
3760 JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
3762 CodeBlock* codeBlock = &function->m_body->generatedByteCode();
3763 activation = new (exec) JSActivation(exec, function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
3764 callFrame[RegisterFile::OptionalCalleeActivation] = activation;
3767 return activation->get(exec, exec->propertyNames().arguments);
3770 JSValue* Machine::retrieveCaller(ExecState* exec, InternalFunction* function) const
3772 Register* callFrame = this->callFrame(exec, function);
3776 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3777 if (!callerCodeBlock)
3780 Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3781 if (JSValue* caller = callerCallFrame[RegisterFile::Callee].jsValue(exec))
3787 void Machine::retrieveLastCaller(ExecState* exec, int& lineNumber, int& sourceId, UString& sourceURL, JSValue*& function) const
3791 sourceURL = UString();
3793 Register* callFrame = exec->m_callFrame;
3797 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3798 if (!callerCodeBlock)
3801 Instruction* vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3802 lineNumber = callerCodeBlock->lineNumberForVPC(vPC - 1);
3803 sourceId = callerCodeBlock->ownerNode->sourceId();
3804 sourceURL = callerCodeBlock->ownerNode->sourceURL();
3806 JSValue* callee = callFrame[RegisterFile::Callee].getJSValue();
3807 if (callee->toThisObject(exec)->inherits(&InternalFunction::info))
3808 function = retrieveCaller(exec, static_cast<InternalFunction*>(callee));
3811 Register* Machine::callFrame(ExecState* exec, InternalFunction* function) const
3813 Register* callFrame = exec->m_callFrame;
3816 while (!callFrame) {
3817 exec = exec->m_prev;
3820 callFrame = exec->m_callFrame;
3823 if (callFrame[RegisterFile::Callee].jsValue(exec) == function)
3826 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3827 if (!callerCodeBlock) {
3832 callFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3836 void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, Register*& argv, int& argc)
3838 function = static_cast<JSFunction*>(callFrame[RegisterFile::Callee].getJSValue());
3839 ASSERT(function->inherits(&JSFunction::info));
3841 argv = callFrame[RegisterFile::CallerRegisters].r() + callFrame[RegisterFile::ArgumentStartRegister].i() + 1; // + 1 to skip "this"
3842 argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"
3847 NEVER_INLINE static void doSetReturnAddressVMThrowTrampoline(void** returnAddress)
3849 ctiSetReturnAddress(returnAddress, (void*)ctiVMThrowTrampoline);
3852 NEVER_INLINE void Machine::tryCTICachePutByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const PutPropertySlot& slot)
3854 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
3856 if (JSImmediate::isImmediate(baseValue))
3859 // Uncacheable: give up.
3860 if (!slot.isCacheable()) {
3861 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3865 JSCell* baseCell = static_cast<JSCell*>(baseValue);
3866 StructureID* structureID = baseCell->structureID();
3868 if (structureID->isDictionary()) {
3869 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3873 // In the interpreter the last structure is trapped here; in CTI we use the
3874 // *_second method to achieve a similar (but not quite the same) effect.
3876 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
3877 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
3879 // Cache hit: Specialize instruction and ref StructureIDs.
3881 // If baseCell != base, then baseCell must be a proxy for another object.
3882 if (baseCell != slot.base()) {
3883 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3887 // StructureID transition, cache transition info
3888 if (slot.type() == PutPropertySlot::NewProperty) {
3889 vPC[0] = getOpcode(op_put_by_id_transition);
3890 vPC[4] = structureID->previousID();
3891 vPC[5] = structureID;
3892 StructureIDChain* chain = structureID->cachedPrototypeChain();
3894 chain = cachePrototypeChain(exec, structureID);
3896 // This happens if someone has manually inserted null into the prototype chain
3897 vPC[0] = getOpcode(op_put_by_id_generic);
3902 vPC[7] = slot.cachedOffset();
3903 codeBlock->refStructureIDs(vPC);
3904 CTI::compilePutByIdTransition(this, exec, codeBlock, structureID->previousID(), structureID, slot.cachedOffset(), chain, returnAddress);
3908 vPC[0] = getOpcode(op_put_by_id_replace);
3909 vPC[4] = structureID;
3910 vPC[5] = slot.cachedOffset();
3911 codeBlock->refStructureIDs(vPC);
3913 #if USE(CTI_REPATCH_PIC)
3915 CTI::patchPutByIdReplace(codeBlock, structureID, slot.cachedOffset(), returnAddress);
3917 CTI::compilePutByIdReplace(this, exec, codeBlock, structureID, slot.cachedOffset(), returnAddress);
3921 void* Machine::getCTIArrayLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
3923 if (!m_ctiArrayLengthTrampoline)
3924 m_ctiArrayLengthTrampoline = CTI::compileArrayLengthTrampoline(this, exec, codeBlock);
3926 return m_ctiArrayLengthTrampoline;
3929 void* Machine::getCTIStringLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
3931 if (!m_ctiStringLengthTrampoline)
3932 m_ctiStringLengthTrampoline = CTI::compileStringLengthTrampoline(this, exec, codeBlock);
3934 return m_ctiStringLengthTrampoline;
3937 NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
3939 // FIXME: Write a test that proves we need to check for recursion here just
3940 // like the interpreter does, then add a check for recursion.
3942 // FIXME: Cache property access for immediates.
3943 if (JSImmediate::isImmediate(baseValue)) {
3944 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3948 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
3949 #if USE(CTI_REPATCH_PIC)
3950 CTI::compilePatchGetArrayLength(this, exec, codeBlock, returnAddress);
3952 ctiRepatchCallByReturnAddress(returnAddress, getCTIArrayLengthTrampoline(exec, codeBlock));
3956 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
3957 // The tradeoff of compiling an repatched inline string length access routine does not seem
3958 // to pay off, so we currently only do this for arrays.
3959 ctiRepatchCallByReturnAddress(returnAddress, getCTIStringLengthTrampoline(exec, codeBlock));
3963 // Uncacheable: give up.
3964 if (!slot.isCacheable()) {
3965 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3969 JSCell* baseCell = static_cast<JSCell*>(baseValue);
3970 StructureID* structureID = baseCell->structureID();
3972 if (structureID->isDictionary()) {
3973 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3977 // In the interpreter the last structure is trapped here; in CTI we use the
3978 // *_second method to achieve a similar (but not quite the same) effect.
3980 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
3981 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
3983 // Cache hit: Specialize instruction and ref StructureIDs.
3985 if (slot.slotBase() == baseValue) {
3986 // set this up, so derefStructureIDs can do it's job.
3987 vPC[0] = getOpcode(op_get_by_id_self);
3988 vPC[4] = structureID;
3989 vPC[5] = slot.cachedOffset();
3990 codeBlock->refStructureIDs(vPC);
3992 #if USE(CTI_REPATCH_PIC)
3993 CTI::patchGetByIdSelf(codeBlock, structureID, slot.cachedOffset(), returnAddress);
3995 CTI::compileGetByIdSelf(this, exec, codeBlock, structureID, slot.cachedOffset(), returnAddress);
4000 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
4001 ASSERT(slot.slotBase()->isObject());
4003 JSObject* slotBaseObject = static_cast<JSObject*>(slot.slotBase());
4005 // Heavy access to a prototype is a good indication that it's not being
4006 // used as a dictionary.
4007 if (slotBaseObject->structureID()->isDictionary()) {
4008 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(slotBaseObject->structureID());
4009 slotBaseObject->setStructureID(transition.release());
4010 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
4013 vPC[0] = getOpcode(op_get_by_id_proto);
4014 vPC[4] = structureID;
4015 vPC[5] = slotBaseObject->structureID();
4016 vPC[6] = slot.cachedOffset();
4017 codeBlock->refStructureIDs(vPC);
4019 CTI::compileGetByIdProto(this, exec, codeBlock, structureID, slotBaseObject->structureID(), slot.cachedOffset(), returnAddress);
4024 JSObject* o = static_cast<JSObject*>(baseValue);
4025 while (slot.slotBase() != o) {
4026 JSValue* v = o->structureID()->prototypeForLookup(exec);
4028 // If we didn't find slotBase in baseValue's prototype chain, then baseValue
4029 // must be a proxy for another object.
4032 vPC[0] = getOpcode(op_get_by_id_generic);
4036 o = static_cast<JSObject*>(v);
4038 // Heavy access to a prototype is a good indication that it's not being
4039 // used as a dictionary.
4040 if (o->structureID()->isDictionary()) {
4041 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
4042 o->setStructureID(transition.release());