2 * Copyright (C) 2008, 2009, 2010 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.
31 #include "Interpreter.h"
33 #include "Arguments.h"
34 #include "BatchedTransitionOptimizer.h"
35 #include "CallFrame.h"
36 #include "CallFrameClosure.h"
37 #include "CodeBlock.h"
40 #include "DebuggerCallFrame.h"
41 #include "ErrorInstance.h"
42 #include "EvalCodeCache.h"
43 #include "ExceptionHelpers.h"
44 #include "GetterSetter.h"
45 #include "JSActivation.h"
47 #include "JSBoundFunction.h"
48 #include "JSByteArray.h"
49 #include "JSNotAnObject.h"
50 #include "JSPropertyNameIterator.h"
51 #include "LiteralParser.h"
52 #include "JSStaticScopeObject.h"
54 #include "ObjectPrototype.h"
55 #include "Operations.h"
58 #include "RegExpObject.h"
59 #include "RegExpPrototype.h"
61 #include "SamplingTool.h"
62 #include "StrictEvalActivation.h"
63 #include "StrongInlines.h"
64 #include "UStringConcatenate.h"
67 #include <wtf/Threading.h>
73 #define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND ((ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)) && !defined(__llvm__))
79 // Returns the depth of the scope chain within a given call frame.
80 static int depth(CodeBlock* codeBlock, ScopeChainNode* sc)
82 if (!codeBlock->needsFullScopeChain())
84 return sc->localDepth();
87 #if ENABLE(CLASSIC_INTERPRETER)
88 static NEVER_INLINE JSValue concatenateStrings(ExecState* exec, Register* strings, unsigned count)
90 return jsString(exec, strings, count);
93 NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
95 int dst = vPC[1].u.operand;
96 int property = vPC[2].u.operand;
98 ScopeChainNode* scopeChain = callFrame->scopeChain();
99 ScopeChainIterator iter = scopeChain->begin();
100 ScopeChainIterator end = scopeChain->end();
103 CodeBlock* codeBlock = callFrame->codeBlock();
104 Identifier& ident = codeBlock->identifier(property);
106 JSObject* o = iter->get();
107 PropertySlot slot(o);
108 if (o->getPropertySlot(callFrame, ident, slot)) {
109 JSValue result = slot.getValue(callFrame, ident);
110 exceptionValue = callFrame->globalData().exception;
113 callFrame->uncheckedR(dst) = JSValue(result);
116 } while (++iter != end);
117 exceptionValue = createUndefinedVariableError(callFrame, ident);
121 NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
123 CodeBlock* codeBlock = callFrame->codeBlock();
125 int dst = vPC[1].u.operand;
126 int property = vPC[2].u.operand;
127 int skip = vPC[3].u.operand;
129 ScopeChainNode* scopeChain = callFrame->scopeChain();
130 ScopeChainIterator iter = scopeChain->begin();
131 ScopeChainIterator end = scopeChain->end();
133 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
134 ASSERT(skip || !checkTopLevel);
135 if (checkTopLevel && skip--) {
136 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
143 Identifier& ident = codeBlock->identifier(property);
145 JSObject* o = iter->get();
146 PropertySlot slot(o);
147 if (o->getPropertySlot(callFrame, ident, slot)) {
148 JSValue result = slot.getValue(callFrame, ident);
149 exceptionValue = callFrame->globalData().exception;
153 callFrame->uncheckedR(dst) = JSValue(result);
156 } while (++iter != end);
157 exceptionValue = createUndefinedVariableError(callFrame, ident);
161 NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
163 int dst = vPC[1].u.operand;
164 CodeBlock* codeBlock = callFrame->codeBlock();
165 JSGlobalObject* globalObject = codeBlock->globalObject();
166 ASSERT(globalObject->isGlobalObject());
167 int property = vPC[2].u.operand;
168 Structure* structure = vPC[3].u.structure.get();
169 int offset = vPC[4].u.operand;
171 if (structure == globalObject->structure()) {
172 callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
176 Identifier& ident = codeBlock->identifier(property);
177 PropertySlot slot(globalObject);
178 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
179 JSValue result = slot.getValue(callFrame, ident);
180 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
181 vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
182 vPC[4] = slot.cachedOffset();
183 callFrame->uncheckedR(dst) = JSValue(result);
187 exceptionValue = callFrame->globalData().exception;
190 callFrame->uncheckedR(dst) = JSValue(result);
194 exceptionValue = createUndefinedVariableError(callFrame, ident);
198 NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
200 int dst = vPC[1].u.operand;
201 CodeBlock* codeBlock = callFrame->codeBlock();
202 JSGlobalObject* globalObject = codeBlock->globalObject();
203 ASSERT(globalObject->isGlobalObject());
204 int property = vPC[2].u.operand;
205 Structure* structure = vPC[3].u.structure.get();
206 int offset = vPC[4].u.operand;
207 int skip = vPC[5].u.operand;
209 ScopeChainNode* scopeChain = callFrame->scopeChain();
210 ScopeChainIterator iter = scopeChain->begin();
211 ScopeChainIterator end = scopeChain->end();
213 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
214 ASSERT(skip || !checkTopLevel);
215 if (checkTopLevel && skip--) {
216 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
220 JSObject* o = iter->get();
221 if (o->hasCustomProperties()) {
222 Identifier& ident = codeBlock->identifier(property);
224 PropertySlot slot(o);
225 if (o->getPropertySlot(callFrame, ident, slot)) {
226 JSValue result = slot.getValue(callFrame, ident);
227 exceptionValue = callFrame->globalData().exception;
231 callFrame->uncheckedR(dst) = JSValue(result);
239 exceptionValue = createUndefinedVariableError(callFrame, ident);
245 if (structure == globalObject->structure()) {
246 callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
247 ASSERT(callFrame->uncheckedR(dst).jsValue());
251 Identifier& ident = codeBlock->identifier(property);
252 PropertySlot slot(globalObject);
253 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
254 JSValue result = slot.getValue(callFrame, ident);
255 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
256 vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
257 vPC[4] = slot.cachedOffset();
259 callFrame->uncheckedR(dst) = JSValue(result);
263 exceptionValue = callFrame->globalData().exception;
267 callFrame->uncheckedR(dst) = JSValue(result);
271 exceptionValue = createUndefinedVariableError(callFrame, ident);
275 NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
277 int dst = vPC[1].u.operand;
278 int property = vPC[2].u.operand;
279 bool isStrictPut = vPC[3].u.operand;
280 Identifier ident = callFrame->codeBlock()->identifier(property);
281 JSValue result = JSC::resolveBase(callFrame, ident, callFrame->scopeChain(), isStrictPut);
283 callFrame->uncheckedR(dst) = result;
284 ASSERT(callFrame->uncheckedR(dst).jsValue());
286 callFrame->globalData().exception = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
289 NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
291 int baseDst = vPC[1].u.operand;
292 int propDst = vPC[2].u.operand;
293 int property = vPC[3].u.operand;
295 ScopeChainNode* scopeChain = callFrame->scopeChain();
296 ScopeChainIterator iter = scopeChain->begin();
297 ScopeChainIterator end = scopeChain->end();
299 // FIXME: add scopeDepthIsZero optimization
303 CodeBlock* codeBlock = callFrame->codeBlock();
304 Identifier& ident = codeBlock->identifier(property);
308 PropertySlot slot(base);
309 if (base->getPropertySlot(callFrame, ident, slot)) {
310 JSValue result = slot.getValue(callFrame, ident);
311 exceptionValue = callFrame->globalData().exception;
314 callFrame->uncheckedR(propDst) = JSValue(result);
315 callFrame->uncheckedR(baseDst) = JSValue(base);
319 } while (iter != end);
321 exceptionValue = createUndefinedVariableError(callFrame, ident);
325 NEVER_INLINE bool Interpreter::resolveThisAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
327 int thisDst = vPC[1].u.operand;
328 int propDst = vPC[2].u.operand;
329 int property = vPC[3].u.operand;
331 ScopeChainNode* scopeChain = callFrame->scopeChain();
332 ScopeChainIterator iter = scopeChain->begin();
333 ScopeChainIterator end = scopeChain->end();
335 // FIXME: add scopeDepthIsZero optimization
339 CodeBlock* codeBlock = callFrame->codeBlock();
340 Identifier& ident = codeBlock->identifier(property);
345 PropertySlot slot(base);
346 if (base->getPropertySlot(callFrame, ident, slot)) {
347 JSValue result = slot.getValue(callFrame, ident);
348 exceptionValue = callFrame->globalData().exception;
351 callFrame->uncheckedR(propDst) = JSValue(result);
352 // All entries on the scope chain should be EnvironmentRecords (activations etc),
353 // other then 'with' object, which are directly referenced from the scope chain,
354 // and the global object. If we hit either an EnvironmentRecord or a global
355 // object at the end of the scope chain, this is undefined. If we hit a non-
356 // EnvironmentRecord within the scope chain, pass the base as the this value.
357 if (iter == end || base->structure()->typeInfo().isEnvironmentRecord())
358 callFrame->uncheckedR(thisDst) = jsUndefined();
360 callFrame->uncheckedR(thisDst) = JSValue(base);
363 } while (iter != end);
365 exceptionValue = createUndefinedVariableError(callFrame, ident);
369 #endif // ENABLE(CLASSIC_INTERPRETER)
371 ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argumentCountIncludingThis)
373 // This ensures enough space for the worst case scenario of zero arguments passed by the caller.
374 if (!registerFile->grow(callFrame->registers() + registerOffset + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters))
377 if (argumentCountIncludingThis >= newCodeBlock->numParameters()) {
378 Register* newCallFrame = callFrame->registers() + registerOffset;
379 return CallFrame::create(newCallFrame);
382 // Too few arguments -- copy arguments, then fill in missing arguments with undefined.
383 size_t delta = newCodeBlock->numParameters() - argumentCountIncludingThis;
384 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset + delta);
386 Register* dst = &newCallFrame->uncheckedR(CallFrame::thisArgumentOffset());
387 Register* end = dst - argumentCountIncludingThis;
388 for ( ; dst != end; --dst)
389 *dst = *(dst - delta);
392 for ( ; dst != end; --dst)
393 *dst = jsUndefined();
398 #if ENABLE(CLASSIC_INTERPRETER)
399 static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
401 if (value.isObject())
403 exceptionData = createInvalidParamError(callFrame, "in" , value);
407 static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
409 if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
411 exceptionData = createInvalidParamError(callFrame, "instanceof" , value);
416 JSValue eval(CallFrame* callFrame)
418 if (!callFrame->argumentCount())
419 return jsUndefined();
421 JSValue program = callFrame->argument(0);
422 if (!program.isString())
425 UString programSource = asString(program)->value(callFrame);
426 if (callFrame->hadException())
429 CallFrame* callerFrame = callFrame->callerFrame();
430 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
431 ScopeChainNode* callerScopeChain = callerFrame->scopeChain();
432 EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, callerScopeChain);
435 if (!callerCodeBlock->isStrictMode()) {
436 // FIXME: We can use the preparser in strict mode, we just need additional logic
437 // to prevent duplicates.
438 if (programSource.is8Bit()) {
439 LiteralParser<LChar> preparser(callFrame, programSource.characters8(), programSource.length(), NonStrictJSON);
440 if (JSValue parsedObject = preparser.tryLiteralParse())
443 LiteralParser<UChar> preparser(callFrame, programSource.characters16(), programSource.length(), NonStrictJSON);
444 if (JSValue parsedObject = preparser.tryLiteralParse())
449 JSValue exceptionValue;
450 eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), programSource, callerScopeChain, exceptionValue);
452 ASSERT(!eval == exceptionValue);
454 return throwError(callFrame, exceptionValue);
457 JSValue thisValue = callerFrame->thisValue();
458 ASSERT(isValidThisObject(thisValue, callFrame));
459 Interpreter* interpreter = callFrame->globalData().interpreter;
460 return interpreter->execute(eval, callFrame, thisValue, callerScopeChain, callFrame->registers() - interpreter->registerFile().begin() + 1 + RegisterFile::CallFrameHeaderSize);
463 CallFrame* loadVarargs(CallFrame* callFrame, RegisterFile* registerFile, JSValue thisValue, JSValue arguments, int firstFreeRegister)
465 if (!arguments) { // f.apply(x, arguments), with arguments unmodified.
466 unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
467 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister + argumentCountIncludingThis + RegisterFile::CallFrameHeaderSize);
468 if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !registerFile->grow(newCallFrame->registers())) {
469 callFrame->globalData().exception = createStackOverflowError(callFrame);
473 newCallFrame->setArgumentCountIncludingThis(argumentCountIncludingThis);
474 newCallFrame->setThisValue(thisValue);
475 for (size_t i = 0; i < callFrame->argumentCount(); ++i)
476 newCallFrame->setArgument(i, callFrame->argument(i));
480 if (arguments.isUndefinedOrNull()) {
481 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister + 1 + RegisterFile::CallFrameHeaderSize);
482 if (!registerFile->grow(newCallFrame->registers())) {
483 callFrame->globalData().exception = createStackOverflowError(callFrame);
486 newCallFrame->setArgumentCountIncludingThis(1);
487 newCallFrame->setThisValue(thisValue);
491 if (!arguments.isObject()) {
492 callFrame->globalData().exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
496 if (asObject(arguments)->classInfo() == &Arguments::s_info) {
497 Arguments* argsObject = asArguments(arguments);
498 unsigned argCount = argsObject->length(callFrame);
499 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister + CallFrame::offsetFor(argCount + 1));
500 if (argCount > Arguments::MaxArguments || !registerFile->grow(newCallFrame->registers())) {
501 callFrame->globalData().exception = createStackOverflowError(callFrame);
504 newCallFrame->setArgumentCountIncludingThis(argCount + 1);
505 newCallFrame->setThisValue(thisValue);
506 argsObject->copyToArguments(callFrame, newCallFrame, argCount);
510 if (isJSArray(arguments)) {
511 JSArray* array = asArray(arguments);
512 unsigned argCount = array->length();
513 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister + CallFrame::offsetFor(argCount + 1));
514 if (argCount > Arguments::MaxArguments || !registerFile->grow(newCallFrame->registers())) {
515 callFrame->globalData().exception = createStackOverflowError(callFrame);
518 newCallFrame->setArgumentCountIncludingThis(argCount + 1);
519 newCallFrame->setThisValue(thisValue);
520 array->copyToArguments(callFrame, newCallFrame, argCount);
524 JSObject* argObject = asObject(arguments);
525 unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
526 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + firstFreeRegister + CallFrame::offsetFor(argCount + 1));
527 if (argCount > Arguments::MaxArguments || !registerFile->grow(newCallFrame->registers())) {
528 callFrame->globalData().exception = createStackOverflowError(callFrame);
531 newCallFrame->setArgumentCountIncludingThis(argCount + 1);
532 newCallFrame->setThisValue(thisValue);
533 for (size_t i = 0; i < argCount; ++i) {
534 newCallFrame->setArgument(i, asObject(arguments)->get(callFrame, i));
535 if (UNLIKELY(callFrame->globalData().exception))
541 Interpreter::Interpreter()
542 : m_sampleEntryDepth(0)
545 , m_initialized(false)
547 , m_classicEnabled(false)
551 Interpreter::~Interpreter()
554 if (m_classicEnabled)
555 delete[] m_opcodeTable;
559 void Interpreter::initialize(LLInt::Data* llintData, bool canUseJIT)
561 UNUSED_PARAM(llintData);
562 UNUSED_PARAM(canUseJIT);
563 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)
564 #if !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
565 // Having LLInt enabled, but not being able to use the JIT, and not having
566 // a computed goto interpreter, is not supported. Not because we cannot
567 // support it, but because I decided to draw the line at the number of
568 // permutations of execution engines that I wanted this code to grok.
573 m_opcodeTable = llintData->opcodeMap();
574 for (int i = 0; i < numOpcodeIDs; ++i)
575 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
577 // If the JIT is present, don't use jump destinations for opcodes.
579 for (int i = 0; i < numOpcodeIDs; ++i) {
580 Opcode opcode = bitwise_cast<void*>(static_cast<uintptr_t>(i));
581 m_opcodeTable[i] = opcode;
586 m_opcodeTable = new Opcode[numOpcodeIDs];
588 privateExecute(InitializeAndReturn, 0, 0);
590 for (int i = 0; i < numOpcodeIDs; ++i)
591 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
593 m_classicEnabled = true;
596 #if ENABLE(CLASSIC_INTERPRETER)
597 m_classicEnabled = true;
599 m_classicEnabled = false;
601 #endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
603 m_initialized = true;
606 #if ENABLE(OPCODE_SAMPLING)
613 void Interpreter::dumpCallFrame(CallFrame* callFrame)
615 callFrame->codeBlock()->dump(callFrame);
616 dumpRegisters(callFrame);
619 void Interpreter::dumpRegisters(CallFrame* callFrame)
621 dataLog("Register frame: \n\n");
622 dataLog("-----------------------------------------------------------------------------\n");
623 dataLog(" use | address | value \n");
624 dataLog("-----------------------------------------------------------------------------\n");
626 CodeBlock* codeBlock = callFrame->codeBlock();
631 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->numParameters();
633 #if USE(JSVALUE32_64)
634 dataLog("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it;
636 dataLog("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it;
638 end = it + max(codeBlock->numParameters() - 1, 0); // - 1 to skip "this"
642 #if USE(JSVALUE32_64)
643 dataLog("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
645 dataLog("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
650 dataLog("-----------------------------------------------------------------------------\n");
651 dataLog("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it;
652 dataLog("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
653 dataLog("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
654 dataLog("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
655 dataLog("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
656 dataLog("[Callee] | %10p | %p \n", it, (*it).function()); ++it;
657 dataLog("-----------------------------------------------------------------------------\n");
659 int registerCount = 0;
661 end = it + codeBlock->m_numVars;
665 #if USE(JSVALUE32_64)
666 dataLog("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
668 dataLog("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
674 dataLog("-----------------------------------------------------------------------------\n");
676 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
680 #if USE(JSVALUE32_64)
681 dataLog("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
683 dataLog("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
689 dataLog("-----------------------------------------------------------------------------\n");
694 bool Interpreter::isOpcode(Opcode opcode)
696 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)
698 if (!m_classicEnabled)
699 return opcode >= 0 && static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)) <= op_end;
701 return opcode != HashTraits<Opcode>::emptyValue()
702 && !HashTraits<Opcode>::isDeletedValue(opcode)
703 && m_opcodeIDTable.contains(opcode);
705 return opcode >= 0 && opcode <= op_end;
709 NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
711 CodeBlock* oldCodeBlock = codeBlock;
712 ScopeChainNode* scopeChain = callFrame->scopeChain();
714 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
715 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
716 if (callFrame->callee())
717 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
719 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
722 // If this call frame created an activation or an 'arguments' object, tear it off.
723 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
724 if (!callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue()) {
725 oldCodeBlock->createActivation(callFrame);
726 scopeChain = callFrame->scopeChain();
728 while (!scopeChain->object->inherits(&JSActivation::s_info))
729 scopeChain = scopeChain->pop();
731 callFrame->setScopeChain(scopeChain);
732 JSActivation* activation = asActivation(scopeChain->object.get());
733 activation->tearOff(*scopeChain->globalData);
734 if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
735 asArguments(arguments)->didTearOffActivation(callFrame->globalData(), activation);
736 } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) {
737 if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
738 asArguments(arguments)->tearOff(callFrame);
741 CallFrame* callerFrame = callFrame->callerFrame();
742 callFrame->globalData().topCallFrame = callerFrame;
743 if (callerFrame->hasHostCallFrameFlag())
746 codeBlock = callerFrame->codeBlock();
748 // Because of how the JIT records call site->bytecode offset
749 // information the JIT reports the bytecodeOffset for the returnPC
750 // to be at the beginning of the opcode that has caused the call.
751 // In the interpreter we have an actual return address, which is
752 // the beginning of next instruction to execute. To get an offset
753 // inside the call instruction that triggered the exception we
754 // have to subtract 1.
755 #if ENABLE(JIT) && ENABLE(CLASSIC_INTERPRETER)
756 if (callerFrame->globalData().canUseJIT())
757 bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC());
759 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1;
761 bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC());
763 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1;
766 callFrame = callerFrame;
770 static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
772 exception->clearAppendSourceToMessage();
774 if (!callFrame->codeBlock()->hasExpressionInfo())
781 CodeBlock* codeBlock = callFrame->codeBlock();
782 codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset);
784 int expressionStart = divotPoint - startOffset;
785 int expressionStop = divotPoint + endOffset;
787 if (!expressionStop || expressionStart > codeBlock->source()->length())
790 JSGlobalData* globalData = &callFrame->globalData();
791 JSValue jsMessage = exception->getDirect(*globalData, globalData->propertyNames->message);
792 if (!jsMessage || !jsMessage.isString())
795 UString message = asString(jsMessage)->value(callFrame);
797 if (expressionStart < expressionStop)
798 message = makeUString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')");
800 // No range information, so give a few characters of context
801 const StringImpl* data = codeBlock->source()->data();
802 int dataLength = codeBlock->source()->length();
803 int start = expressionStart;
804 int stop = expressionStart;
805 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
806 // then strip whitespace.
807 while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n')
809 while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start]))
811 while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n')
813 while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1]))
815 message = makeUString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')");
818 exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message));
821 static int getLineNumberForCallFrame(JSGlobalData* globalData, CallFrame* callFrame)
823 UNUSED_PARAM(globalData);
824 callFrame = callFrame->removeHostCallFrameFlag();
825 CodeBlock* codeBlock = callFrame->codeBlock();
828 #if ENABLE(CLASSIC_INTERPRETER)
829 if (!globalData->canUseJIT())
830 return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode() - 1);
834 if (codeBlock->getJITType() == JITCode::DFGJIT)
835 return codeBlock->lineNumberForBytecodeOffset(codeBlock->codeOrigin(callFrame->codeOriginIndexForDFG()).bytecodeIndex);
837 return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode());
843 static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber)
845 UNUSED_PARAM(globalData);
846 unsigned bytecodeOffset = 0;
848 ASSERT(!callFrame->hasHostCallFrameFlag());
849 CallFrame* callerFrame = callFrame->codeBlock() ? callFrame->trueCallerFrame() : callFrame->callerFrame()->removeHostCallFrameFlag();
850 bool callframeIsHost = callerFrame->addHostCallFrameFlag() == callFrame->callerFrame();
851 ASSERT(!callerFrame->hasHostCallFrameFlag());
853 if (callerFrame == CallFrame::noCaller() || !callerFrame || !callerFrame->codeBlock())
856 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
859 if (!callFrame->hasReturnPC())
860 callframeIsHost = true;
863 if (callFrame->isInlineCallFrame())
864 callframeIsHost = false;
867 if (callframeIsHost) {
868 // Don't need to deal with inline callframes here as by definition we haven't
869 // inlined a call with an intervening native call frame.
870 #if ENABLE(CLASSIC_INTERPRETER)
871 if (!globalData->canUseJIT()) {
872 bytecodeOffset = callerFrame->bytecodeOffsetForNonDFGCode();
873 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);
879 if (callerCodeBlock && callerCodeBlock->getJITType() == JITCode::DFGJIT) {
880 unsigned codeOriginIndex = callerFrame->codeOriginIndexForDFG();
881 bytecodeOffset = callerCodeBlock->codeOrigin(codeOriginIndex).bytecodeIndex;
884 bytecodeOffset = callerFrame->bytecodeOffsetForNonDFGCode();
887 #if ENABLE(CLASSIC_INTERPRETER)
888 if (!globalData->canUseJIT()) {
889 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());
890 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);
896 if (callFrame->isInlineCallFrame()) {
897 InlineCallFrame* icf = callFrame->inlineCallFrame();
898 bytecodeOffset = icf->caller.bytecodeIndex;
899 if (InlineCallFrame* parentCallFrame = icf->caller.inlineCallFrame) {
900 FunctionExecutable* executable = static_cast<FunctionExecutable*>(parentCallFrame->executable.get());
901 CodeBlock* newCodeBlock = executable->baselineCodeBlockFor(parentCallFrame->isCall ? CodeForCall : CodeForConstruct);
902 ASSERT(newCodeBlock);
903 ASSERT(newCodeBlock->instructionCount() > bytecodeOffset);
904 callerCodeBlock = newCodeBlock;
906 } else if (callerCodeBlock && callerCodeBlock->getJITType() == JITCode::DFGJIT) {
908 if (!callerCodeBlock->codeOriginForReturn(callFrame->returnPC(), origin))
909 ASSERT_NOT_REACHED();
910 bytecodeOffset = origin.bytecodeIndex;
911 if (InlineCallFrame* icf = origin.inlineCallFrame) {
912 FunctionExecutable* executable = static_cast<FunctionExecutable*>(icf->executable.get());
913 CodeBlock* newCodeBlock = executable->baselineCodeBlockFor(icf->isCall ? CodeForCall : CodeForConstruct);
914 ASSERT(newCodeBlock);
915 ASSERT(newCodeBlock->instructionCount() > bytecodeOffset);
916 callerCodeBlock = newCodeBlock;
920 bytecodeOffset = callerCodeBlock->bytecodeOffset(callerFrame, callFrame->returnPC());
924 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset);
928 static ALWAYS_INLINE const UString getSourceURLFromCallFrame(CallFrame* callFrame)
930 ASSERT(!callFrame->hasHostCallFrameFlag());
931 #if ENABLE(CLASSIC_INTERPRETER)
933 if (callFrame->globalData().canUseJIT())
934 return callFrame->codeBlock()->ownerExecutable()->sourceURL();
936 return callFrame->codeBlock()->source()->url();
939 return callFrame->codeBlock()->ownerExecutable()->sourceURL();
943 static StackFrameCodeType getStackFrameCodeType(CallFrame* callFrame)
945 ASSERT(!callFrame->hasHostCallFrameFlag());
947 switch (callFrame->codeBlock()->codeType()) {
949 return StackFrameEvalCode;
951 return StackFrameFunctionCode;
953 return StackFrameGlobalCode;
955 ASSERT_NOT_REACHED();
956 return StackFrameGlobalCode;
959 void Interpreter::getStackTrace(JSGlobalData* globalData, int line, Vector<StackFrame>& results)
961 CallFrame* callFrame = globalData->topCallFrame->removeHostCallFrameFlag()->trueCallFrameFromVMCode();
962 if (!callFrame || callFrame == CallFrame::noCaller())
966 line = getLineNumberForCallFrame(globalData, callFrame);
968 while (callFrame && callFrame != CallFrame::noCaller()) {
970 if (callFrame->codeBlock()) {
971 sourceURL = getSourceURLFromCallFrame(callFrame);
972 StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), getStackFrameCodeType(callFrame), Strong<ExecutableBase>(*globalData, callFrame->codeBlock()->ownerExecutable()), line, sourceURL};
975 StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), -1, UString()};
978 callFrame = getCallerInfo(globalData, callFrame, line);
982 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
984 CodeBlock* codeBlock = callFrame->codeBlock();
985 bool isInterrupt = false;
987 // Set up the exception object
988 if (exceptionValue.isObject()) {
989 JSObject* exception = asObject(exceptionValue);
991 if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage())
992 appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset);
994 // Using hasExpressionInfo to imply we are interested in rich exception info.
995 if (codeBlock->hasExpressionInfo() && !hasErrorInfo(callFrame, exception)) {
996 ASSERT(codeBlock->hasLineInfo());
998 // FIXME: should only really be adding these properties to VM generated exceptions,
999 // but the inspector currently requires these for all thrown objects.
1000 Vector<StackFrame> stackTrace;
1001 getStackTrace(&callFrame->globalData(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), stackTrace);
1002 addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source(), stackTrace);
1005 isInterrupt = isInterruptedExecutionException(exception) || isTerminatedExecutionException(exception);
1008 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
1009 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
1010 bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
1011 debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), hasHandler);
1014 // Calculate an exception handler vPC, unwinding call frames as necessary.
1015 HandlerInfo* handler = 0;
1016 while (isInterrupt || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
1017 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
1018 if (Profiler* profiler = *Profiler::enabledProfilerReference())
1019 profiler->exceptionUnwind(callFrame);
1024 if (Profiler* profiler = *Profiler::enabledProfilerReference())
1025 profiler->exceptionUnwind(callFrame);
1027 // Shrink the JS stack, in case stack overflow made it huge.
1028 Register* highWaterMark = 0;
1029 for (CallFrame* callerFrame = callFrame; callerFrame; callerFrame = callerFrame->callerFrame()->removeHostCallFrameFlag()) {
1030 CodeBlock* codeBlock = callerFrame->codeBlock();
1033 Register* callerHighWaterMark = callerFrame->registers() + codeBlock->m_numCalleeRegisters;
1034 highWaterMark = max(highWaterMark, callerHighWaterMark);
1036 m_registerFile.shrink(highWaterMark);
1038 // Unwind the scope chain within the exception handler's call frame.
1039 ScopeChainNode* scopeChain = callFrame->scopeChain();
1041 if (!codeBlock->needsFullScopeChain() || codeBlock->codeType() != FunctionCode
1042 || callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
1043 scopeDelta = depth(codeBlock, scopeChain) - handler->scopeDepth;
1044 ASSERT(scopeDelta >= 0);
1045 while (scopeDelta--)
1046 scopeChain = scopeChain->pop();
1047 callFrame->setScopeChain(scopeChain);
1052 static inline JSValue checkedReturn(JSValue returnValue)
1054 ASSERT(returnValue);
1058 static inline JSObject* checkedReturn(JSObject* returnValue)
1060 ASSERT(returnValue);
1064 JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
1066 ASSERT(isValidThisObject(thisObj, callFrame));
1067 ASSERT(!scopeChain->globalData->exception);
1068 ASSERT(!callFrame->globalData().isCollectorBusy());
1069 if (callFrame->globalData().isCollectorBusy())
1072 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
1073 return checkedReturn(throwStackOverflowError(callFrame));
1075 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
1076 Vector<JSONPData> JSONPData;
1078 const UString programSource = program->source().toString();
1079 if (programSource.isNull())
1080 return jsUndefined();
1081 if (programSource.is8Bit()) {
1082 LiteralParser<LChar> literalParser(callFrame, programSource.characters8(), programSource.length(), JSONP);
1083 parseResult = literalParser.tryJSONPParse(JSONPData, scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get()));
1085 LiteralParser<UChar> literalParser(callFrame, programSource.characters16(), programSource.length(), JSONP);
1086 parseResult = literalParser.tryJSONPParse(JSONPData, scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get()));
1090 JSGlobalObject* globalObject = scopeChain->globalObject.get();
1092 for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
1093 Vector<JSONPPathEntry> JSONPPath;
1094 JSONPPath.swap(JSONPData[entry].m_path);
1095 JSValue JSONPValue = JSONPData[entry].m_value.get();
1096 if (JSONPPath.size() == 1 && JSONPPath[0].m_type == JSONPPathEntryTypeDeclare) {
1097 if (globalObject->hasProperty(callFrame, JSONPPath[0].m_pathEntryName)) {
1098 PutPropertySlot slot;
1099 globalObject->methodTable()->put(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
1101 globalObject->methodTable()->putDirectVirtual(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, DontEnum | DontDelete);
1102 // var declarations return undefined
1103 result = jsUndefined();
1106 JSValue baseObject(globalObject);
1107 for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
1108 ASSERT(JSONPPath[i].m_type != JSONPPathEntryTypeDeclare);
1109 switch (JSONPPath[i].m_type) {
1110 case JSONPPathEntryTypeDot: {
1112 PropertySlot slot(globalObject);
1113 if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) {
1115 return throwError(callFrame, createUndefinedVariableError(globalObject->globalExec(), JSONPPath[i].m_pathEntryName));
1118 baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);
1120 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName);
1121 if (callFrame->hadException())
1122 return jsUndefined();
1125 case JSONPPathEntryTypeLookup: {
1126 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathIndex);
1127 if (callFrame->hadException())
1128 return jsUndefined();
1132 ASSERT_NOT_REACHED();
1133 return jsUndefined();
1136 PutPropertySlot slot;
1137 switch (JSONPPath.last().m_type) {
1138 case JSONPPathEntryTypeCall: {
1139 JSValue function = baseObject.get(callFrame, JSONPPath.last().m_pathEntryName);
1140 if (callFrame->hadException())
1141 return jsUndefined();
1143 CallType callType = getCallData(function, callData);
1144 if (callType == CallTypeNone)
1145 return throwError(callFrame, createNotAFunctionError(callFrame, function));
1146 MarkedArgumentBuffer jsonArg;
1147 jsonArg.append(JSONPValue);
1148 JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined(): baseObject;
1149 JSONPValue = JSC::call(callFrame, function, callType, callData, thisValue, jsonArg);
1150 if (callFrame->hadException())
1151 return jsUndefined();
1154 case JSONPPathEntryTypeDot: {
1155 baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
1156 if (callFrame->hadException())
1157 return jsUndefined();
1160 case JSONPPathEntryTypeLookup: {
1161 baseObject.put(callFrame, JSONPPath.last().m_pathIndex, JSONPValue);
1162 if (callFrame->hadException())
1163 return jsUndefined();
1167 ASSERT_NOT_REACHED();
1168 return jsUndefined();
1170 result = JSONPValue;
1175 JSObject* error = program->compile(callFrame, scopeChain);
1177 return checkedReturn(throwError(callFrame, error));
1178 CodeBlock* codeBlock = &program->generatedBytecode();
1180 Register* oldEnd = m_registerFile.end();
1181 Register* newEnd = oldEnd + codeBlock->numParameters() + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
1182 if (!m_registerFile.grow(newEnd))
1183 return checkedReturn(throwStackOverflowError(callFrame));
1185 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->numParameters() + RegisterFile::CallFrameHeaderSize);
1186 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1187 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), codeBlock->numParameters(), 0);
1188 newCallFrame->setThisValue(thisObj);
1189 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
1191 Profiler** profiler = Profiler::enabledProfilerReference();
1193 (*profiler)->willExecute(callFrame, program->sourceURL(), program->lineNo());
1197 SamplingTool::CallRecord callRecord(m_sampler.get());
1201 if (callFrame->globalData().canUseJIT())
1202 result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
1205 result = privateExecute(Normal, &m_registerFile, newCallFrame);
1211 (*profiler)->didExecute(callFrame, program->sourceURL(), program->lineNo());
1213 m_registerFile.shrink(oldEnd);
1215 return checkedReturn(result);
1218 JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
1220 ASSERT(isValidThisObject(thisValue, callFrame));
1221 ASSERT(!callFrame->hadException());
1222 ASSERT(!callFrame->globalData().isCollectorBusy());
1223 if (callFrame->globalData().isCollectorBusy())
1226 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
1227 return checkedReturn(throwStackOverflowError(callFrame));
1229 Register* oldEnd = m_registerFile.end();
1230 int argCount = 1 + args.size(); // implicit "this" parameter
1231 size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
1233 CallFrame* newCallFrame = CallFrame::create(oldEnd + registerOffset);
1234 if (!m_registerFile.grow(newCallFrame->registers()))
1235 return checkedReturn(throwStackOverflowError(callFrame));
1237 newCallFrame->setThisValue(thisValue);
1238 for (size_t i = 0; i < args.size(); ++i)
1239 newCallFrame->setArgument(i, args.at(i));
1241 if (callType == CallTypeJS) {
1242 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
1244 DynamicGlobalObjectScope globalObjectScope(*callDataScopeChain->globalData, callDataScopeChain->globalObject.get());
1246 JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
1247 if (UNLIKELY(!!compileError)) {
1248 m_registerFile.shrink(oldEnd);
1249 return checkedReturn(throwError(callFrame, compileError));
1252 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
1253 newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, 0, argCount);
1254 if (UNLIKELY(!newCallFrame)) {
1255 m_registerFile.shrink(oldEnd);
1256 return checkedReturn(throwStackOverflowError(callFrame));
1259 newCallFrame->init(newCodeBlock, 0, callDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
1261 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
1263 Profiler** profiler = Profiler::enabledProfilerReference();
1265 (*profiler)->willExecute(callFrame, function);
1269 SamplingTool::CallRecord callRecord(m_sampler.get());
1273 if (callFrame->globalData().canUseJIT())
1274 result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScopeChain->globalData);
1277 result = privateExecute(Normal, &m_registerFile, newCallFrame);
1282 (*profiler)->didExecute(callFrame, function);
1284 m_registerFile.shrink(oldEnd);
1285 return checkedReturn(result);
1288 ASSERT(callType == CallTypeHost);
1289 ScopeChainNode* scopeChain = callFrame->scopeChain();
1290 newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
1292 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
1294 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
1296 Profiler** profiler = Profiler::enabledProfilerReference();
1298 (*profiler)->willExecute(callFrame, function);
1302 SamplingTool::HostCallRecord callRecord(m_sampler.get());
1303 result = JSValue::decode(callData.native.function(newCallFrame));
1307 (*profiler)->didExecute(callFrame, function);
1309 m_registerFile.shrink(oldEnd);
1310 return checkedReturn(result);
1313 JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
1315 ASSERT(!callFrame->hadException());
1316 ASSERT(!callFrame->globalData().isCollectorBusy());
1317 // We throw in this case because we have to return something "valid" but we're
1318 // already in an invalid state.
1319 if (callFrame->globalData().isCollectorBusy())
1320 return checkedReturn(throwStackOverflowError(callFrame));
1322 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
1323 return checkedReturn(throwStackOverflowError(callFrame));
1325 Register* oldEnd = m_registerFile.end();
1326 int argCount = 1 + args.size(); // implicit "this" parameter
1327 size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
1329 if (!m_registerFile.grow(oldEnd + registerOffset))
1330 return checkedReturn(throwStackOverflowError(callFrame));
1332 CallFrame* newCallFrame = CallFrame::create(oldEnd + registerOffset);
1333 newCallFrame->setThisValue(jsUndefined());
1334 for (size_t i = 0; i < args.size(); ++i)
1335 newCallFrame->setArgument(i, args.at(i));
1337 if (constructType == ConstructTypeJS) {
1338 ScopeChainNode* constructDataScopeChain = constructData.js.scopeChain;
1340 DynamicGlobalObjectScope globalObjectScope(*constructDataScopeChain->globalData, constructDataScopeChain->globalObject.get());
1342 JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, constructDataScopeChain);
1343 if (UNLIKELY(!!compileError)) {
1344 m_registerFile.shrink(oldEnd);
1345 return checkedReturn(throwError(callFrame, compileError));
1348 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
1349 newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, 0, argCount);
1350 if (UNLIKELY(!newCallFrame)) {
1351 m_registerFile.shrink(oldEnd);
1352 return checkedReturn(throwStackOverflowError(callFrame));
1355 newCallFrame->init(newCodeBlock, 0, constructDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
1357 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
1359 Profiler** profiler = Profiler::enabledProfilerReference();
1361 (*profiler)->willExecute(callFrame, constructor);
1365 SamplingTool::CallRecord callRecord(m_sampler.get());
1369 if (callFrame->globalData().canUseJIT())
1370 result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScopeChain->globalData);
1373 result = privateExecute(Normal, &m_registerFile, newCallFrame);
1378 (*profiler)->didExecute(callFrame, constructor);
1380 m_registerFile.shrink(oldEnd);
1381 if (callFrame->hadException())
1383 ASSERT(result.isObject());
1384 return checkedReturn(asObject(result));
1387 ASSERT(constructType == ConstructTypeHost);
1388 ScopeChainNode* scopeChain = callFrame->scopeChain();
1389 newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
1391 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
1393 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
1395 Profiler** profiler = Profiler::enabledProfilerReference();
1397 (*profiler)->willExecute(callFrame, constructor);
1401 SamplingTool::HostCallRecord callRecord(m_sampler.get());
1402 result = JSValue::decode(constructData.native.function(newCallFrame));
1406 (*profiler)->didExecute(callFrame, constructor);
1408 m_registerFile.shrink(oldEnd);
1409 if (callFrame->hadException())
1411 ASSERT(result.isObject());
1412 return checkedReturn(asObject(result));
1415 CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, int argumentCountIncludingThis, ScopeChainNode* scopeChain)
1417 ASSERT(!scopeChain->globalData->exception);
1419 if (callFrame->globalData().isCollectorBusy())
1420 return CallFrameClosure();
1422 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
1423 throwStackOverflowError(callFrame);
1424 return CallFrameClosure();
1427 Register* oldEnd = m_registerFile.end();
1428 size_t registerOffset = argumentCountIncludingThis + RegisterFile::CallFrameHeaderSize;
1430 CallFrame* newCallFrame = CallFrame::create(oldEnd + registerOffset);
1431 if (!m_registerFile.grow(newCallFrame->registers())) {
1432 throwStackOverflowError(callFrame);
1433 return CallFrameClosure();
1436 JSObject* error = functionExecutable->compileForCall(callFrame, scopeChain);
1438 throwError(callFrame, error);
1439 m_registerFile.shrink(oldEnd);
1440 return CallFrameClosure();
1442 CodeBlock* codeBlock = &functionExecutable->generatedBytecodeForCall();
1444 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, 0, argumentCountIncludingThis);
1445 if (UNLIKELY(!newCallFrame)) {
1446 throwStackOverflowError(callFrame);
1447 m_registerFile.shrink(oldEnd);
1448 return CallFrameClosure();
1450 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), argumentCountIncludingThis, function);
1451 scopeChain->globalData->topCallFrame = newCallFrame;
1452 CallFrameClosure result = { callFrame, newCallFrame, function, functionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->numParameters(), argumentCountIncludingThis };
1456 JSValue Interpreter::execute(CallFrameClosure& closure)
1458 ASSERT(!closure.oldCallFrame->globalData().isCollectorBusy());
1459 if (closure.oldCallFrame->globalData().isCollectorBusy())
1461 closure.resetCallFrame();
1462 Profiler** profiler = Profiler::enabledProfilerReference();
1464 (*profiler)->willExecute(closure.oldCallFrame, closure.function);
1466 TopCallFrameSetter topCallFrame(*closure.globalData, closure.newCallFrame);
1470 SamplingTool::CallRecord callRecord(m_sampler.get());
1474 #if ENABLE(CLASSIC_INTERPRETER)
1475 if (closure.newCallFrame->globalData().canUseJIT())
1477 result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, closure.newCallFrame, closure.globalData);
1478 #if ENABLE(CLASSIC_INTERPRETER)
1482 #if ENABLE(CLASSIC_INTERPRETER)
1483 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame);
1489 (*profiler)->didExecute(closure.oldCallFrame, closure.function);
1490 return checkedReturn(result);
1493 void Interpreter::endRepeatCall(CallFrameClosure& closure)
1495 closure.globalData->topCallFrame = closure.oldCallFrame;
1496 m_registerFile.shrink(closure.oldEnd);
1499 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, ScopeChainNode* scopeChain, int globalRegisterOffset)
1501 ASSERT(isValidThisObject(thisValue, callFrame));
1502 ASSERT(!scopeChain->globalData->exception);
1503 ASSERT(!callFrame->globalData().isCollectorBusy());
1504 if (callFrame->globalData().isCollectorBusy())
1507 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
1509 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
1510 return checkedReturn(throwStackOverflowError(callFrame));
1512 JSObject* compileError = eval->compile(callFrame, scopeChain);
1513 if (UNLIKELY(!!compileError))
1514 return checkedReturn(throwError(callFrame, compileError));
1515 EvalCodeBlock* codeBlock = &eval->generatedBytecode();
1517 JSObject* variableObject;
1518 for (ScopeChainNode* node = scopeChain; ; node = node->next.get()) {
1520 if (node->object->isVariableObject() && !node->object->isStaticScopeObject()) {
1521 variableObject = static_cast<JSVariableObject*>(node->object.get());
1526 unsigned numVariables = codeBlock->numVariables();
1527 int numFunctions = codeBlock->numberOfFunctionDecls();
1528 bool pushedScope = false;
1529 if (numVariables || numFunctions) {
1530 if (codeBlock->isStrictMode()) {
1531 variableObject = StrictEvalActivation::create(callFrame);
1532 scopeChain = scopeChain->push(variableObject);
1535 // Scope for BatchedTransitionOptimizer
1536 BatchedTransitionOptimizer optimizer(callFrame->globalData(), variableObject);
1538 for (unsigned i = 0; i < numVariables; ++i) {
1539 const Identifier& ident = codeBlock->variable(i);
1540 if (!variableObject->hasProperty(callFrame, ident)) {
1541 PutPropertySlot slot;
1542 variableObject->methodTable()->put(variableObject, callFrame, ident, jsUndefined(), slot);
1546 for (int i = 0; i < numFunctions; ++i) {
1547 FunctionExecutable* function = codeBlock->functionDecl(i);
1548 PutPropertySlot slot;
1549 variableObject->methodTable()->put(variableObject, callFrame, function->name(), function->make(callFrame, scopeChain), slot);
1553 Register* oldEnd = m_registerFile.end();
1554 Register* newEnd = m_registerFile.begin() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
1555 if (!m_registerFile.grow(newEnd)) {
1558 return checkedReturn(throwStackOverflowError(callFrame));
1561 CallFrame* newCallFrame = CallFrame::create(m_registerFile.begin() + globalRegisterOffset);
1563 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1564 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->numParameters(), 0);
1565 newCallFrame->setThisValue(thisValue);
1567 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
1569 Profiler** profiler = Profiler::enabledProfilerReference();
1571 (*profiler)->willExecute(callFrame, eval->sourceURL(), eval->lineNo());
1575 SamplingTool::CallRecord callRecord(m_sampler.get());
1580 #if ENABLE(CLASSIC_INTERPRETER)
1581 if (callFrame->globalData().canUseJIT())
1583 result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
1584 #if ENABLE(CLASSIC_INTERPRETER)
1588 #if ENABLE(CLASSIC_INTERPRETER)
1589 result = privateExecute(Normal, &m_registerFile, newCallFrame);
1595 (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
1597 m_registerFile.shrink(oldEnd);
1600 return checkedReturn(result);
1603 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
1605 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
1609 switch (debugHookID) {
1610 case DidEnterCallFrame:
1611 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
1613 case WillLeaveCallFrame:
1614 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
1616 case WillExecuteStatement:
1617 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
1619 case WillExecuteProgram:
1620 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
1622 case DidExecuteProgram:
1623 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
1625 case DidReachBreakpoint:
1626 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
1631 #if ENABLE(CLASSIC_INTERPRETER)
1632 NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
1634 int dst = vPC[1].u.operand;
1635 CodeBlock* codeBlock = callFrame->codeBlock();
1636 Identifier& property = codeBlock->identifier(vPC[2].u.operand);
1637 JSValue value = callFrame->r(vPC[3].u.operand).jsValue();
1638 JSObject* scope = JSStaticScopeObject::create(callFrame, property, value, DontDelete);
1639 callFrame->uncheckedR(dst) = JSValue(scope);
1641 return callFrame->scopeChain()->push(scope);
1644 NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot)
1646 // Recursive invocation may already have specialized this instruction.
1647 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1650 if (!baseValue.isCell())
1653 // Uncacheable: give up.
1654 if (!slot.isCacheable()) {
1655 vPC[0] = getOpcode(op_put_by_id_generic);
1659 JSCell* baseCell = baseValue.asCell();
1660 Structure* structure = baseCell->structure();
1662 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
1663 vPC[0] = getOpcode(op_put_by_id_generic);
1667 // Cache miss: record Structure to compare against next time.
1668 Structure* lastStructure = vPC[4].u.structure.get();
1669 if (structure != lastStructure) {
1670 // First miss: record Structure to compare against next time.
1671 if (!lastStructure) {
1672 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1676 // Second miss: give up.
1677 vPC[0] = getOpcode(op_put_by_id_generic);
1681 // Cache hit: Specialize instruction and ref Structures.
1683 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1684 if (baseCell != slot.base()) {
1685 vPC[0] = getOpcode(op_put_by_id_generic);
1689 // Structure transition, cache transition info
1690 if (slot.type() == PutPropertySlot::NewProperty) {
1691 if (structure->isDictionary()) {
1692 vPC[0] = getOpcode(op_put_by_id_generic);
1696 // put_by_id_transition checks the prototype chain for setters.
1697 normalizePrototypeChain(callFrame, baseCell);
1698 JSCell* owner = codeBlock->ownerExecutable();
1699 JSGlobalData& globalData = callFrame->globalData();
1700 // Get the prototype here because the call to prototypeChain could cause a
1701 // GC allocation, which we don't want to happen while we're in the middle of
1702 // initializing the union.
1703 StructureChain* prototypeChain = structure->prototypeChain(callFrame);
1704 vPC[0] = getOpcode(op_put_by_id_transition);
1705 vPC[4].u.structure.set(globalData, owner, structure->previousID());
1706 vPC[5].u.structure.set(globalData, owner, structure);
1707 vPC[6].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), prototypeChain);
1708 ASSERT(vPC[6].u.structureChain);
1709 vPC[7] = slot.cachedOffset();
1713 vPC[0] = getOpcode(op_put_by_id_replace);
1714 vPC[5] = slot.cachedOffset();
1717 NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock*, Instruction* vPC)
1719 vPC[0] = getOpcode(op_put_by_id);
1723 NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)
1725 // Recursive invocation may already have specialized this instruction.
1726 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1729 // FIXME: Cache property access for immediates.
1730 if (!baseValue.isCell()) {
1731 vPC[0] = getOpcode(op_get_by_id_generic);
1735 if (isJSArray(baseValue) && propertyName == callFrame->propertyNames().length) {
1736 vPC[0] = getOpcode(op_get_array_length);
1740 if (isJSString(baseValue) && propertyName == callFrame->propertyNames().length) {
1741 vPC[0] = getOpcode(op_get_string_length);
1745 // Uncacheable: give up.
1746 if (!slot.isCacheable()) {
1747 vPC[0] = getOpcode(op_get_by_id_generic);
1751 Structure* structure = baseValue.asCell()->structure();
1753 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
1754 vPC[0] = getOpcode(op_get_by_id_generic);
1759 Structure* lastStructure = vPC[4].u.structure.get();
1760 if (structure != lastStructure) {
1761 // First miss: record Structure to compare against next time.
1762 if (!lastStructure) {
1763 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1767 // Second miss: give up.
1768 vPC[0] = getOpcode(op_get_by_id_generic);
1772 // Cache hit: Specialize instruction and ref Structures.
1774 if (slot.slotBase() == baseValue) {
1775 switch (slot.cachedPropertyType()) {
1776 case PropertySlot::Getter:
1777 vPC[0] = getOpcode(op_get_by_id_getter_self);
1778 vPC[5] = slot.cachedOffset();
1780 case PropertySlot::Custom:
1781 vPC[0] = getOpcode(op_get_by_id_custom_self);
1782 vPC[5] = slot.customGetter();
1785 vPC[0] = getOpcode(op_get_by_id_self);
1786 vPC[5] = slot.cachedOffset();
1792 if (structure->isDictionary()) {
1793 vPC[0] = getOpcode(op_get_by_id_generic);
1797 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
1798 ASSERT(slot.slotBase().isObject());
1800 JSObject* baseObject = asObject(slot.slotBase());
1801 size_t offset = slot.cachedOffset();
1803 // Since we're accessing a prototype in a loop, it's a good bet that it
1804 // should not be treated as a dictionary.
1805 if (baseObject->structure()->isDictionary()) {
1806 baseObject->flattenDictionaryObject(callFrame->globalData());
1807 offset = baseObject->structure()->get(callFrame->globalData(), propertyName);
1810 ASSERT(!baseObject->structure()->isUncacheableDictionary());
1812 switch (slot.cachedPropertyType()) {
1813 case PropertySlot::Getter:
1814 vPC[0] = getOpcode(op_get_by_id_getter_proto);
1817 case PropertySlot::Custom:
1818 vPC[0] = getOpcode(op_get_by_id_custom_proto);
1819 vPC[6] = slot.customGetter();
1822 vPC[0] = getOpcode(op_get_by_id_proto);
1826 vPC[5].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), baseObject->structure());
1830 size_t offset = slot.cachedOffset();
1831 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
1833 vPC[0] = getOpcode(op_get_by_id_generic);
1838 switch (slot.cachedPropertyType()) {
1839 case PropertySlot::Getter:
1840 vPC[0] = getOpcode(op_get_by_id_getter_chain);
1843 case PropertySlot::Custom:
1844 vPC[0] = getOpcode(op_get_by_id_custom_chain);
1845 vPC[7] = slot.customGetter();
1848 vPC[0] = getOpcode(op_get_by_id_chain);
1852 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1853 vPC[5].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure->prototypeChain(callFrame));
1857 NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock*, Instruction* vPC)
1859 vPC[0] = getOpcode(op_get_by_id);
1863 #endif // ENABLE(CLASSIC_INTERPRETER)
1865 JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame)
1867 // One-time initialization of our address tables. We have to put this code
1868 // here because our labels are only in scope inside this function.
1869 if (UNLIKELY(flag == InitializeAndReturn)) {
1870 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
1871 #define LIST_OPCODE_LABEL(id, length) &&id,
1872 static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) };
1873 for (size_t i = 0; i < WTF_ARRAY_LENGTH(labels); ++i)
1874 m_opcodeTable[i] = labels[i];
1875 #undef LIST_OPCODE_LABEL
1876 #endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
1880 ASSERT(m_initialized);
1881 ASSERT(m_classicEnabled);
1884 #if ENABLE(CLASSIC_INTERPRETER)
1885 // Mixing Interpreter + JIT is not supported.
1886 if (callFrame->globalData().canUseJIT())
1888 ASSERT_NOT_REACHED();
1891 #if !ENABLE(CLASSIC_INTERPRETER)
1892 UNUSED_PARAM(registerFile);
1893 UNUSED_PARAM(callFrame);
1897 ASSERT(callFrame->globalData().topCallFrame == callFrame);
1899 JSGlobalData* globalData = &callFrame->globalData();
1900 JSValue exceptionValue;
1901 HandlerInfo* handler = 0;
1902 CallFrame** topCallFrameSlot = &globalData->topCallFrame;
1904 CodeBlock* codeBlock = callFrame->codeBlock();
1905 Instruction* vPC = codeBlock->instructions().begin();
1906 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1907 unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();
1908 JSValue functionReturnValue;
1910 #define CHECK_FOR_EXCEPTION() \
1912 if (UNLIKELY(globalData->exception != JSValue())) { \
1913 exceptionValue = globalData->exception; \
1918 #if ENABLE(OPCODE_STATS)
1919 OpcodeStats::resetLastInstruction();
1922 #define CHECK_FOR_TIMEOUT() \
1923 if (!--tickCount) { \
1924 if (globalData->terminator.shouldTerminate() || globalData->timeoutChecker.didTimeOut(callFrame)) { \
1925 exceptionValue = jsNull(); \
1928 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1931 #if ENABLE(OPCODE_SAMPLING)
1932 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1934 #define SAMPLE(codeBlock, vPC)
1937 #define UPDATE_BYTECODE_OFFSET() \
1939 callFrame->setBytecodeOffsetForNonDFGCode(vPC - codeBlock->instructions().data() + 1);\
1942 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
1943 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode
1944 #if ENABLE(OPCODE_STATS)
1945 #define DEFINE_OPCODE(opcode) \
1947 OpcodeStats::recordInstruction(opcode);\
1948 UPDATE_BYTECODE_OFFSET();
1950 #define DEFINE_OPCODE(opcode) opcode: UPDATE_BYTECODE_OFFSET();
1954 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart
1955 #if ENABLE(OPCODE_STATS)
1956 #define DEFINE_OPCODE(opcode) \
1958 OpcodeStats::recordInstruction(opcode);\
1959 UPDATE_BYTECODE_OFFSET();
1961 #define DEFINE_OPCODE(opcode) case opcode: UPDATE_BYTECODE_OFFSET();
1963 while (1) { // iterator loop begins
1964 interpreterLoopStart:;
1965 switch (vPC->u.opcode)
1968 DEFINE_OPCODE(op_new_object) {
1969 /* new_object dst(r)
1971 Constructs a new empty Object instance using the original
1972 constructor, and puts the result in register dst.
1974 int dst = vPC[1].u.operand;
1975 callFrame->uncheckedR(dst) = JSValue(constructEmptyObject(callFrame));
1977 vPC += OPCODE_LENGTH(op_new_object);
1980 DEFINE_OPCODE(op_new_array) {
1981 /* new_array dst(r) firstArg(r) argCount(n)
1983 Constructs a new Array instance using the original
1984 constructor, and puts the result in register dst.
1985 The array will contain argCount elements with values
1986 taken from registers starting at register firstArg.
1988 int dst = vPC[1].u.operand;
1989 int firstArg = vPC[2].u.operand;
1990 int argCount = vPC[3].u.operand;
1991 callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, reinterpret_cast<JSValue*>(&callFrame->registers()[firstArg]), argCount));
1993 vPC += OPCODE_LENGTH(op_new_array);
1996 DEFINE_OPCODE(op_new_array_buffer) {
1997 /* new_array_buffer dst(r) index(n) argCount(n)
1999 Constructs a new Array instance using the original
2000 constructor, and puts the result in register dst.
2001 The array be initialized with the values from constantBuffer[index]
2003 int dst = vPC[1].u.operand;
2004 int firstArg = vPC[2].u.operand;
2005 int argCount = vPC[3].u.operand;
2006 callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, codeBlock->constantBuffer(firstArg), argCount));
2008 vPC += OPCODE_LENGTH(op_new_array);
2011 DEFINE_OPCODE(op_new_regexp) {
2012 /* new_regexp dst(r) regExp(re)
2014 Constructs a new RegExp instance using the original
2015 constructor from regexp regExp, and puts the result in
2018 int dst = vPC[1].u.operand;
2019 RegExp* regExp = codeBlock->regexp(vPC[2].u.operand);
2020 if (!regExp->isValid()) {
2021 exceptionValue = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor.");
2024 callFrame->uncheckedR(dst) = JSValue(RegExpObject::create(*globalData, callFrame->lexicalGlobalObject(), callFrame->scopeChain()->globalObject->regExpStructure(), regExp));
2026 vPC += OPCODE_LENGTH(op_new_regexp);
2029 DEFINE_OPCODE(op_mov) {
2030 /* mov dst(r) src(r)
2032 Copies register src to register dst.
2034 int dst = vPC[1].u.operand;
2035 int src = vPC[2].u.operand;
2037 callFrame->uncheckedR(dst) = callFrame->r(src);
2039 vPC += OPCODE_LENGTH(op_mov);
2042 DEFINE_OPCODE(op_eq) {
2043 /* eq dst(r) src1(r) src2(r)
2045 Checks whether register src1 and register src2 are equal,
2046 as with the ECMAScript '==' operator, and puts the result
2047 as a boolean in register dst.
2049 int dst = vPC[1].u.operand;
2050 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2051 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2052 if (src1.isInt32() && src2.isInt32())
2053 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
2055 JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));
2056 CHECK_FOR_EXCEPTION();
2057 callFrame->uncheckedR(dst) = result;
2060 vPC += OPCODE_LENGTH(op_eq);
2063 DEFINE_OPCODE(op_eq_null) {
2064 /* eq_null dst(r) src(r)
2066 Checks whether register src is null, as with the ECMAScript '!='
2067 operator, and puts the result as a boolean in register dst.
2069 int dst = vPC[1].u.operand;
2070 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
2072 if (src.isUndefinedOrNull()) {
2073 callFrame->uncheckedR(dst) = jsBoolean(true);
2074 vPC += OPCODE_LENGTH(op_eq_null);
2078 callFrame->uncheckedR(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
2079 vPC += OPCODE_LENGTH(op_eq_null);
2082 DEFINE_OPCODE(op_neq) {
2083 /* neq dst(r) src1(r) src2(r)
2085 Checks whether register src1 and register src2 are not
2086 equal, as with the ECMAScript '!=' operator, and puts the
2087 result as a boolean in register dst.
2089 int dst = vPC[1].u.operand;
2090 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2091 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2092 if (src1.isInt32() && src2.isInt32())
2093 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
2095 JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));
2096 CHECK_FOR_EXCEPTION();
2097 callFrame->uncheckedR(dst) = result;
2100 vPC += OPCODE_LENGTH(op_neq);
2103 DEFINE_OPCODE(op_neq_null) {
2104 /* neq_null dst(r) src(r)
2106 Checks whether register src is not null, as with the ECMAScript '!='
2107 operator, and puts the result as a boolean in register dst.
2109 int dst = vPC[1].u.operand;
2110 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
2112 if (src.isUndefinedOrNull()) {
2113 callFrame->uncheckedR(dst) = jsBoolean(false);
2114 vPC += OPCODE_LENGTH(op_neq_null);
2118 callFrame->uncheckedR(dst) = jsBoolean(!src.isCell() || !src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
2119 vPC += OPCODE_LENGTH(op_neq_null);
2122 DEFINE_OPCODE(op_stricteq) {
2123 /* stricteq dst(r) src1(r) src2(r)
2125 Checks whether register src1 and register src2 are strictly
2126 equal, as with the ECMAScript '===' operator, and puts the
2127 result as a boolean in register dst.
2129 int dst = vPC[1].u.operand;
2130 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2131 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2132 bool result = JSValue::strictEqual(callFrame, src1, src2);
2133 CHECK_FOR_EXCEPTION();
2134 callFrame->uncheckedR(dst) = jsBoolean(result);
2136 vPC += OPCODE_LENGTH(op_stricteq);
2139 DEFINE_OPCODE(op_nstricteq) {
2140 /* nstricteq dst(r) src1(r) src2(r)
2142 Checks whether register src1 and register src2 are not
2143 strictly equal, as with the ECMAScript '!==' operator, and
2144 puts the result as a boolean in register dst.
2146 int dst = vPC[1].u.operand;
2147 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2148 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2149 bool result = !JSValue::strictEqual(callFrame, src1, src2);
2150 CHECK_FOR_EXCEPTION();
2151 callFrame->uncheckedR(dst) = jsBoolean(result);
2153 vPC += OPCODE_LENGTH(op_nstricteq);
2156 DEFINE_OPCODE(op_less) {
2157 /* less dst(r) src1(r) src2(r)
2159 Checks whether register src1 is less than register src2, as
2160 with the ECMAScript '<' operator, and puts the result as
2161 a boolean in register dst.
2163 int dst = vPC[1].u.operand;
2164 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2165 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2166 JSValue result = jsBoolean(jsLess<true>(callFrame, src1, src2));
2167 CHECK_FOR_EXCEPTION();
2168 callFrame->uncheckedR(dst) = result;
2170 vPC += OPCODE_LENGTH(op_less);
2173 DEFINE_OPCODE(op_lesseq) {
2174 /* lesseq dst(r) src1(r) src2(r)
2176 Checks whether register src1 is less than or equal to
2177 register src2, as with the ECMAScript '<=' operator, and
2178 puts the result as a boolean in register dst.
2180 int dst = vPC[1].u.operand;
2181 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2182 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2183 JSValue result = jsBoolean(jsLessEq<true>(callFrame, src1, src2));
2184 CHECK_FOR_EXCEPTION();
2185 callFrame->uncheckedR(dst) = result;
2187 vPC += OPCODE_LENGTH(op_lesseq);
2190 DEFINE_OPCODE(op_greater) {
2191 /* greater dst(r) src1(r) src2(r)
2193 Checks whether register src1 is greater than register src2, as
2194 with the ECMAScript '>' operator, and puts the result as
2195 a boolean in register dst.
2197 int dst = vPC[1].u.operand;
2198 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2199 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2200 JSValue result = jsBoolean(jsLess<false>(callFrame, src2, src1));
2201 CHECK_FOR_EXCEPTION();
2202 callFrame->uncheckedR(dst) = result;
2204 vPC += OPCODE_LENGTH(op_greater);
2207 DEFINE_OPCODE(op_greatereq) {
2208 /* greatereq dst(r) src1(r) src2(r)
2210 Checks whether register src1 is greater than or equal to
2211 register src2, as with the ECMAScript '>=' operator, and
2212 puts the result as a boolean in register dst.
2214 int dst = vPC[1].u.operand;
2215 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2216 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2217 JSValue result = jsBoolean(jsLessEq<false>(callFrame, src2, src1));
2218 CHECK_FOR_EXCEPTION();
2219 callFrame->uncheckedR(dst) = result;
2221 vPC += OPCODE_LENGTH(op_greatereq);
2224 DEFINE_OPCODE(op_pre_inc) {
2225 /* pre_inc srcDst(r)
2227 Converts register srcDst to number, adds one, and puts the result
2228 back in register srcDst.
2230 int srcDst = vPC[1].u.operand;
2231 JSValue v = callFrame->r(srcDst).jsValue();
2232 if (v.isInt32() && v.asInt32() < INT_MAX)
2233 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
2235 JSValue result = jsNumber(v.toNumber(callFrame) + 1);
2236 CHECK_FOR_EXCEPTION();
2237 callFrame->uncheckedR(srcDst) = result;
2240 vPC += OPCODE_LENGTH(op_pre_inc);
2243 DEFINE_OPCODE(op_pre_dec) {
2244 /* pre_dec srcDst(r)
2246 Converts register srcDst to number, subtracts one, and puts the result
2247 back in register srcDst.
2249 int srcDst = vPC[1].u.operand;
2250 JSValue v = callFrame->r(srcDst).jsValue();
2251 if (v.isInt32() && v.asInt32() > INT_MIN)
2252 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
2254 JSValue result = jsNumber(v.toNumber(callFrame) - 1);
2255 CHECK_FOR_EXCEPTION();
2256 callFrame->uncheckedR(srcDst) = result;
2259 vPC += OPCODE_LENGTH(op_pre_dec);
2262 DEFINE_OPCODE(op_post_inc) {
2263 /* post_inc dst(r) srcDst(r)
2265 Converts register srcDst to number. The number itself is
2266 written to register dst, and the number plus one is written
2267 back to register srcDst.
2269 int dst = vPC[1].u.operand;
2270 int srcDst = vPC[2].u.operand;
2271 JSValue v = callFrame->r(srcDst).jsValue();
2272 if (v.isInt32() && v.asInt32() < INT_MAX) {
2273 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
2274 callFrame->uncheckedR(dst) = v;
2276 double number = callFrame->r(srcDst).jsValue().toNumber(callFrame);
2277 CHECK_FOR_EXCEPTION();
2278 callFrame->uncheckedR(srcDst) = jsNumber(number + 1);
2279 callFrame->uncheckedR(dst) = jsNumber(number);
2282 vPC += OPCODE_LENGTH(op_post_inc);
2285 DEFINE_OPCODE(op_post_dec) {
2286 /* post_dec dst(r) srcDst(r)
2288 Converts register srcDst to number. The number itself is
2289 written to register dst, and the number minus one is written
2290 back to register srcDst.
2292 int dst = vPC[1].u.operand;
2293 int srcDst = vPC[2].u.operand;
2294 JSValue v = callFrame->r(srcDst).jsValue();
2295 if (v.isInt32() && v.asInt32() > INT_MIN) {
2296 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
2297 callFrame->uncheckedR(dst) = v;
2299 double number = callFrame->r(srcDst).jsValue().toNumber(callFrame);
2300 CHECK_FOR_EXCEPTION();
2301 callFrame->uncheckedR(srcDst) = jsNumber(number - 1);
2302 callFrame->uncheckedR(dst) = jsNumber(number);
2305 vPC += OPCODE_LENGTH(op_post_dec);
2308 DEFINE_OPCODE(op_to_jsnumber) {
2309 /* to_jsnumber dst(r) src(r)
2311 Converts register src to number, and puts the result
2314 int dst = vPC[1].u.operand;
2315 int src = vPC[2].u.operand;
2317 JSValue srcVal = callFrame->r(src).jsValue();
2319 if (LIKELY(srcVal.isNumber()))
2320 callFrame->uncheckedR(dst) = callFrame->r(src);
2322 double number = srcVal.toNumber(callFrame);
2323 CHECK_FOR_EXCEPTION();
2324 callFrame->uncheckedR(dst) = jsNumber(number);
2327 vPC += OPCODE_LENGTH(op_to_jsnumber);
2330 DEFINE_OPCODE(op_negate) {
2331 /* negate dst(r) src(r)
2333 Converts register src to number, negates it, and puts the
2334 result in register dst.
2336 int dst = vPC[1].u.operand;
2337 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
2338 if (src.isInt32() && (src.asInt32() & 0x7fffffff)) // non-zero and no overflow
2339 callFrame->uncheckedR(dst) = jsNumber(-src.asInt32());
2341 JSValue result = jsNumber(-src.toNumber(callFrame));
2342 CHECK_FOR_EXCEPTION();
2343 callFrame->uncheckedR(dst) = result;
2346 vPC += OPCODE_LENGTH(op_negate);
2349 DEFINE_OPCODE(op_add) {
2350 /* add dst(r) src1(r) src2(r)
2352 Adds register src1 and register src2, and puts the result
2353 in register dst. (JS add may be string concatenation or
2354 numeric add, depending on the types of the operands.)
2356 int dst = vPC[1].u.operand;
2357 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2358 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2359 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
2360 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() + src2.asInt32());
2362 JSValue result = jsAdd(callFrame, src1, src2);
2363 CHECK_FOR_EXCEPTION();
2364 callFrame->uncheckedR(dst) = result;
2366 vPC += OPCODE_LENGTH(op_add);
2369 DEFINE_OPCODE(op_mul) {
2370 /* mul dst(r) src1(r) src2(r)
2372 Multiplies register src1 and register src2 (converted to
2373 numbers), and puts the product in register dst.
2375 int dst = vPC[1].u.operand;
2376 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2377 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2378 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
2379 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() * src2.asInt32());
2381 JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame));
2382 CHECK_FOR_EXCEPTION();
2383 callFrame->uncheckedR(dst) = result;
2386 vPC += OPCODE_LENGTH(op_mul);
2389 DEFINE_OPCODE(op_div) {
2390 /* div dst(r) dividend(r) divisor(r)
2392 Divides register dividend (converted to number) by the
2393 register divisor (converted to number), and puts the
2394 quotient in register dst.
2396 int dst = vPC[1].u.operand;
2397 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
2398 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
2400 JSValue result = jsNumber(dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
2401 CHECK_FOR_EXCEPTION();
2402 callFrame->uncheckedR(dst) = result;
2404 vPC += OPCODE_LENGTH(op_div);
2407 DEFINE_OPCODE(op_mod) {
2408 /* mod dst(r) dividend(r) divisor(r)
2410 Divides register dividend (converted to number) by
2411 register divisor (converted to number), and puts the
2412 remainder in register dst.
2414 int dst = vPC[1].u.operand;
2415 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
2416 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
2418 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
2419 JSValue result = jsNumber(dividend.asInt32() % divisor.asInt32());
2421 callFrame->uncheckedR(dst) = result;
2422 vPC += OPCODE_LENGTH(op_mod);
2426 // Conversion to double must happen outside the call to fmod since the
2427 // order of argument evaluation is not guaranteed.
2428 double d1 = dividend.toNumber(callFrame);
2429 double d2 = divisor.toNumber(callFrame);
2430 JSValue result = jsNumber(fmod(d1, d2));
2431 CHECK_FOR_EXCEPTION();
2432 callFrame->uncheckedR(dst) = result;
2433 vPC += OPCODE_LENGTH(op_mod);
2436 DEFINE_OPCODE(op_sub) {
2437 /* sub dst(r) src1(r) src2(r)
2439 Subtracts register src2 (converted to number) from register
2440 src1 (converted to number), and puts the difference in
2443 int dst = vPC[1].u.operand;
2444 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2445 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2446 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
2447 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() - src2.asInt32());
2449 JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame));
2450 CHECK_FOR_EXCEPTION();
2451 callFrame->uncheckedR(dst) = result;
2453 vPC += OPCODE_LENGTH(op_sub);
2456 DEFINE_OPCODE(op_lshift) {
2457 /* lshift dst(r) val(r) shift(r)
2459 Performs left shift of register val (converted to int32) by
2460 register shift (converted to uint32), and puts the result
2463 int dst = vPC[1].u.operand;
2464 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
2465 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
2467 if (val.isInt32() && shift.isInt32())
2468 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() << (shift.asInt32() & 0x1f));
2470 JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
2471 CHECK_FOR_EXCEPTION();
2472 callFrame->uncheckedR(dst) = result;
2475 vPC += OPCODE_LENGTH(op_lshift);
2478 DEFINE_OPCODE(op_rshift) {
2479 /* rshift dst(r) val(r) shift(r)
2481 Performs arithmetic right shift of register val (converted
2482 to int32) by register shift (converted to
2483 uint32), and puts the result in register dst.
2485 int dst = vPC[1].u.operand;
2486 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
2487 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
2489 if (val.isInt32() && shift.isInt32())
2490 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
2492 JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2493 CHECK_FOR_EXCEPTION();
2494 callFrame->uncheckedR(dst) = result;
2497 vPC += OPCODE_LENGTH(op_rshift);
2500 DEFINE_OPCODE(op_urshift) {
2501 /* rshift dst(r) val(r) shift(r)
2503 Performs logical right shift of register val (converted
2504 to uint32) by register shift (converted to
2505 uint32), and puts the result in register dst.
2507 int dst = vPC[1].u.operand;
2508 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
2509 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
2510 if (val.isUInt32() && shift.isInt32())
2511 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
2513 JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2514 CHECK_FOR_EXCEPTION();
2515 callFrame->uncheckedR(dst) = result;
2518 vPC += OPCODE_LENGTH(op_urshift);
2521 DEFINE_OPCODE(op_bitand) {
2522 /* bitand dst(r) src1(r) src2(r)
2524 Computes bitwise AND of register src1 (converted to int32)
2525 and register src2 (converted to int32), and puts the result
2528 int dst = vPC[1].u.operand;
2529 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2530 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2531 if (src1.isInt32() && src2.isInt32())
2532 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() & src2.asInt32());
2534 JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame));
2535 CHECK_FOR_EXCEPTION();
2536 callFrame->uncheckedR(dst) = result;
2539 vPC += OPCODE_LENGTH(op_bitand);
2542 DEFINE_OPCODE(op_bitxor) {
2543 /* bitxor dst(r) src1(r) src2(r)
2545 Computes bitwise XOR of register src1 (converted to int32)
2546 and register src2 (converted to int32), and puts the result
2549 int dst = vPC[1].u.operand;
2550 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2551 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2552 if (src1.isInt32() && src2.isInt32())
2553 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() ^ src2.asInt32());
2555 JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
2556 CHECK_FOR_EXCEPTION();
2557 callFrame->uncheckedR(dst) = result;
2560 vPC += OPCODE_LENGTH(op_bitxor);
2563 DEFINE_OPCODE(op_bitor) {
2564 /* bitor dst(r) src1(r) src2(r)
2566 Computes bitwise OR of register src1 (converted to int32)
2567 and register src2 (converted to int32), and puts the
2568 result in register dst.
2570 int dst = vPC[1].u.operand;
2571 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2572 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2573 if (src1.isInt32() && src2.isInt32())
2574 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() | src2.asInt32());
2576 JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));
2577 CHECK_FOR_EXCEPTION();
2578 callFrame->uncheckedR(dst) = result;
2581 vPC += OPCODE_LENGTH(op_bitor);
2584 DEFINE_OPCODE(op_not) {
2585 /* not dst(r) src(r)
2587 Computes logical NOT of register src (converted to
2588 boolean), and puts the result in register dst.
2590 int dst = vPC[1].u.operand;
2591 int src = vPC[2].u.operand;
2592 JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));
2593 CHECK_FOR_EXCEPTION();
2594 callFrame->uncheckedR(dst) = result;
2596 vPC += OPCODE_LENGTH(op_not);
2599 DEFINE_OPCODE(op_check_has_instance) {
2600 /* check_has_instance constructor(r)
2602 Check 'constructor' is an object with the internal property
2603 [HasInstance] (i.e. is a function ... *shakes head sadly at
2604 JSC API*). Raises an exception if register constructor is not
2605 an valid parameter for instanceof.
2607 int base = vPC[1].u.operand;
2608 JSValue baseVal = callFrame->r(base).jsValue();
2610 if (isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue))
2613 vPC += OPCODE_LENGTH(op_check_has_instance);
2616 DEFINE_OPCODE(op_instanceof) {
2617 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2619 Tests whether register value is an instance of register
2620 constructor, and puts the boolean result in register
2621 dst. Register constructorProto must contain the "prototype"
2622 property (not the actual prototype) of the object in
2623 register constructor. This lookup is separated so that
2624 polymorphic inline caching can apply.
2626 Raises an exception if register constructor is not an
2629 int dst = vPC[1].u.operand;
2630 int value = vPC[2].u.operand;
2631 int base = vPC[3].u.operand;
2632 int baseProto = vPC[4].u.operand;
2634 JSValue baseVal = callFrame->r(base).jsValue();
2636 ASSERT(!isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue));
2638 bool result = asObject(baseVal)->methodTable()->hasInstance(asObject(baseVal), callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
2639 CHECK_FOR_EXCEPTION();
2640 callFrame->uncheckedR(dst) = jsBoolean(result);
2642 vPC += OPCODE_LENGTH(op_instanceof);
2645 DEFINE_OPCODE(op_typeof) {
2646 /* typeof dst(r) src(r)
2648 Determines the type string for src according to ECMAScript
2649 rules, and puts the result in register dst.
2651 int dst = vPC[1].u.operand;
2652 int src = vPC[2].u.operand;
2653 callFrame->uncheckedR(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
2655 vPC += OPCODE_LENGTH(op_typeof);
2658 DEFINE_OPCODE(op_is_undefined) {
2659 /* is_undefined dst(r) src(r)
2661 Determines whether the type string for src according to
2662 the ECMAScript rules is "undefined", and puts the result
2665 int dst = vPC[1].u.operand;
2666 int src = vPC[2].u.operand;
2667 JSValue v = callFrame->r(src).jsValue();
2668 callFrame->uncheckedR(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
2670 vPC += OPCODE_LENGTH(op_is_undefined);
2673 DEFINE_OPCODE(op_is_boolean) {
2674 /* is_boolean dst(r) src(r)
2676 Determines whether the type string for src according to
2677 the ECMAScript rules is "boolean", and puts the result
2680 int dst = vPC[1].u.operand;
2681 int src = vPC[2].u.operand;
2682 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
2684 vPC += OPCODE_LENGTH(op_is_boolean);
2687 DEFINE_OPCODE(op_is_number) {
2688 /* is_number dst(r) src(r)
2690 Determines whether the type string for src according to
2691 the ECMAScript rules is "number", and puts the result
2694 int dst = vPC[1].u.operand;
2695 int src = vPC[2].u.operand;
2696 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
2698 vPC += OPCODE_LENGTH(op_is_number);
2701 DEFINE_OPCODE(op_is_string) {
2702 /* is_string dst(r) src(r)
2704 Determines whether the type string for src according to
2705 the ECMAScript rules is "string", and puts the result
2708 int dst = vPC[1].u.operand;
2709 int src = vPC[2].u.operand;
2710 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
2712 vPC += OPCODE_LENGTH(op_is_string);
2715 DEFINE_OPCODE(op_is_object) {
2716 /* is_object dst(r) src(r)
2718 Determines whether the type string for src according to
2719 the ECMAScript rules is "object", and puts the result
2722 int dst = vPC[1].u.operand;
2723 int src = vPC[2].u.operand;
2724 callFrame->uncheckedR(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
2726 vPC += OPCODE_LENGTH(op_is_object);
2729 DEFINE_OPCODE(op_is_function) {
2730 /* is_function dst(r) src(r)
2732 Determines whether the type string for src according to
2733 the ECMAScript rules is "function", and puts the result
2736 int dst = vPC[1].u.operand;
2737 int src = vPC[2].u.operand;
2738 callFrame->uncheckedR(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
2740 vPC += OPCODE_LENGTH(op_is_function);
2743 DEFINE_OPCODE(op_in) {
2744 /* in dst(r) property(r) base(r)
2746 Tests whether register base has a property named register
2747 property, and puts the boolean result in register dst.
2749 Raises an exception if register constructor is not an
2752 int dst = vPC[1].u.operand;
2753 int property = vPC[2].u.operand;
2754 int base = vPC[3].u.operand;
2756 JSValue baseVal = callFrame->r(base).jsValue();
2757 if (isInvalidParamForIn(callFrame, baseVal, exceptionValue))
2760 JSObject* baseObj = asObject(baseVal);
2762 JSValue propName = callFrame->r(property).jsValue();
2765 if (propName.getUInt32(i))
2766 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
2768 Identifier property(callFrame, propName.toString(callFrame)->value(callFrame));
2769 CHECK_FOR_EXCEPTION();
2770 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
2773 vPC += OPCODE_LENGTH(op_in);
2776 DEFINE_OPCODE(op_resolve) {
2777 /* resolve dst(r) property(id)
2779 Looks up the property named by identifier property in the
2780 scope chain, and writes the resulting value to register
2781 dst. If the property is not found, raises an exception.
2783 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
2786 vPC += OPCODE_LENGTH(op_resolve);
2789 DEFINE_OPCODE(op_resolve_skip) {
2790 /* resolve_skip dst(r) property(id) skip(n)
2792 Looks up the property named by identifier property in the
2793 scope chain skipping the top 'skip' levels, and writes the resulting
2794 value to register dst. If the property is not found, raises an exception.
2796 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
2799 vPC += OPCODE_LENGTH(op_resolve_skip);
2803 DEFINE_OPCODE(op_resolve_global) {
2804 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
2806 Performs a dynamic property lookup for the given property, on the provided
2807 global object. If structure matches the Structure of the global then perform
2808 a fast lookup using the case offset, otherwise fall back to a full resolve and
2809 cache the new structure and offset
2811 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
2814 vPC += OPCODE_LENGTH(op_resolve_global);
2818 DEFINE_OPCODE(op_resolve_global_dynamic) {
2819 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n), depth(n)
2821 Performs a dynamic property lookup for the given property, on the provided
2822 global object. If structure matches the Structure of the global then perform
2823 a fast lookup using the case offset, otherwise fall back to a full resolve and
2824 cache the new structure and offset.
2826 This walks through n levels of the scope chain to verify that none of those levels
2827 in the scope chain include dynamically added properties.
2829 if (UNLIKELY(!resolveGlobalDynamic(callFrame, vPC, exceptionValue)))
2832 vPC += OPCODE_LENGTH(op_resolve_global_dynamic);
2836 DEFINE_OPCODE(op_get_global_var) {
2837 /* get_global_var dst(r) globalObject(c) index(n)
2839 Gets the global var at global slot index and places it in register dst.
2841 int dst = vPC[1].u.operand;
2842 JSGlobalObject* scope = codeBlock->globalObject();
2843 ASSERT(scope->isGlobalObject());
2844 int index = vPC[2].u.operand;
2846 callFrame->uncheckedR(dst) = scope->registerAt(index).get();
2847 vPC += OPCODE_LENGTH(op_get_global_var);
2850 DEFINE_OPCODE(op_put_global_var) {
2851 /* put_global_var globalObject(c) index(n) value(r)
2853 Puts value into global slot index.
2855 JSGlobalObject* scope = codeBlock->globalObject();
2856 ASSERT(scope->isGlobalObject());
2857 int index = vPC[1].u.operand;
2858 int value = vPC[2].u.operand;
2860 scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
2861 vPC += OPCODE_LENGTH(op_put_global_var);
2864 DEFINE_OPCODE(op_get_scoped_var) {
2865 /* get_scoped_var dst(r) index(n) skip(n)
2867 Loads the contents of the index-th local from the scope skip nodes from
2868 the top of the scope chain, and places it in register dst.
2870 int dst = vPC[1].u.operand;
2871 int index = vPC[2].u.operand;
2872 int skip = vPC[3].u.operand;
2874 ScopeChainNode* scopeChain = callFrame->scopeChain();
2875 ScopeChainIterator iter = scopeChain->begin();
2876 ScopeChainIterator end = scopeChain->end();
2877 ASSERT_UNUSED(end, iter != end);
2878 ASSERT(codeBlock == callFrame->codeBlock());
2879 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
2880 ASSERT(skip || !checkTopLevel);
2881 if (checkTopLevel && skip--) {
2882 if (callFrame->r(codeBlock->activationRegister()).jsValue())
2887 ASSERT_UNUSED(end, iter != end);
2889 ASSERT((*iter)->isVariableObject());
2890 JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
2891 callFrame->uncheckedR(dst) = scope->registerAt(index).get();
2892 ASSERT(callFrame->r(dst).jsValue());
2893 vPC += OPCODE_LENGTH(op_get_scoped_var);
2896 DEFINE_OPCODE(op_put_scoped_var) {
2897 /* put_scoped_var index(n) skip(n) value(r)
2900 int index = vPC[1].u.operand;
2901 int skip = vPC[2].u.operand;
2902 int value = vPC[3].u.operand;
2904 ScopeChainNode* scopeChain = callFrame->scopeChain();
2905 ScopeChainIterator iter = scopeChain->begin();
2906 ScopeChainIterator end = scopeChain->end();
2907 ASSERT(codeBlock == callFrame->codeBlock());
2908 ASSERT_UNUSED(end, iter != end);
2909 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
2910 ASSERT(skip || !checkTopLevel);
2911 if (checkTopLevel && skip--) {
2912 if (callFrame->r(codeBlock->activationRegister()).jsValue())
2917 ASSERT_UNUSED(end, iter != end);
2920 ASSERT((*iter)->isVariableObject());
2921 JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
2922 ASSERT(callFrame->r(value).jsValue());
2923 scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
2924 vPC += OPCODE_LENGTH(op_put_scoped_var);
2927 DEFINE_OPCODE(op_resolve_base) {
2928 /* resolve_base dst(r) property(id) isStrict(bool)
2930 Searches the scope chain for an object containing
2931 identifier property, and if one is found, writes it to
2932 register dst. If none is found and isStrict is false, the
2933 outermost scope (which will be the global object) is
2934 stored in register dst.
2936 resolveBase(callFrame, vPC);
2937 CHECK_FOR_EXCEPTION();
2939 vPC += OPCODE_LENGTH(op_resolve_base);
2942 DEFINE_OPCODE(op_ensure_property_exists) {
2943 /* ensure_property_exists base(r) property(id)
2945 Throws an exception if property does not exist on base
2947 int base = vPC[1].u.operand;
2948 int property = vPC[2].u.operand;
2949 Identifier& ident = codeBlock->identifier(property);
2951 JSValue baseVal = callFrame->r(base).jsValue();
2952 JSObject* baseObject = asObject(baseVal);
2953 PropertySlot slot(baseVal);
2954 if (!baseObject->getPropertySlot(callFrame, ident, slot)) {
2955 exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
2959 vPC += OPCODE_LENGTH(op_ensure_property_exists);
2962 DEFINE_OPCODE(op_resolve_with_base) {
2963 /* resolve_with_base baseDst(r) propDst(r) property(id)
2965 Searches the scope chain for an object containing
2966 identifier property, and if one is found, writes it to
2967 register srcDst, and the retrieved property value to register
2968 propDst. If the property is not found, raises an exception.
2970 This is more efficient than doing resolve_base followed by
2971 resolve, or resolve_base followed by get_by_id, as it
2972 avoids duplicate hash lookups.
2974 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
2977 vPC += OPCODE_LENGTH(op_resolve_with_base);
2980 DEFINE_OPCODE(op_resolve_with_this) {
2981 /* resolve_with_this thisDst(r) propDst(r) property(id)
2983 Searches the scope chain for an object containing
2984 identifier property, and if one is found, writes the
2985 retrieved property value to register propDst, and the
2986 this object to pass in a call to thisDst.
2988 If the property is not found, raises an exception.
2990 if (UNLIKELY(!resolveThisAndProperty(callFrame, vPC, exceptionValue)))
2993 vPC += OPCODE_LENGTH(op_resolve_with_this);
2996 DEFINE_OPCODE(op_get_by_id) {
2997 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2999 Generic property access: Gets the property named by identifier
3000 property from the value base, and puts the result in register dst.
3002 int dst = vPC[1].u.operand;
3003 int base = vPC[2].u.operand;
3004 int property = vPC[3].u.operand;
3006 Identifier& ident = codeBlock->identifier(property);
3007 JSValue baseValue = callFrame->r(base).jsValue();
3008 PropertySlot slot(baseValue);
3009 JSValue result = baseValue.get(callFrame, ident, slot);
3010 CHECK_FOR_EXCEPTION();
3012 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
3014 callFrame->uncheckedR(dst) = result;
3015 vPC += OPCODE_LENGTH(op_get_by_id);
3018 DEFINE_OPCODE(op_get_by_id_self) {
3019 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
3021 Cached property access: Attempts to get a cached property from the
3022 value base. If the cache misses, op_get_by_id_self reverts to
3025 int base = vPC[2].u.operand;
3026 JSValue baseValue = callFrame->r(base).jsValue();
3028 if (LIKELY(baseValue.isCell())) {
3029 JSCell* baseCell = baseValue.asCell();
3030 Structure* structure = vPC[4].u.structure.get();
3032 if (LIKELY(baseCell->structure() == structure)) {
3033 ASSERT(baseCell->isObject());
3034 JSObject* baseObject = asObject(baseCell);
3035 int dst = vPC[1].u.operand;
3036 int offset = vPC[5].u.operand;
3038 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
3039 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
3041 vPC += OPCODE_LENGTH(op_get_by_id_self);
3046 uncacheGetByID(codeBlock, vPC);
3049 DEFINE_OPCODE(op_get_by_id_proto) {
3050 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
3052 Cached property access: Attempts to get a cached property from the
3053 value base's prototype. If the cache misses, op_get_by_id_proto
3054 reverts to op_get_by_id.
3056 int base = vPC[2].u.operand;
3057 JSValue baseValue = callFrame->r(base).jsValue();
3059 if (LIKELY(baseValue.isCell())) {
3060 JSCell* baseCell = baseValue.asCell();
3061 Structure* structure = vPC[4].u.structure.get();
3063 if (LIKELY(baseCell->structure() == structure)) {
3064 ASSERT(structure->prototypeForLookup(callFrame).isObject());
3065 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
3066 Structure* prototypeStructure = vPC[5].u.structure.get();
3068 if (LIKELY(protoObject->structure() == prototypeStructure)) {
3069 int dst = vPC[1].u.operand;
3070 int offset = vPC[6].u.operand;
3072 ASSERT(protoObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
3073 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
3074 callFrame->uncheckedR(dst) = JSValue(protoObject->getDirectOffset(offset));
3076 vPC += OPCODE_LENGTH(op_get_by_id_proto);
3082 uncacheGetByID(codeBlock, vPC);
3085 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3086 goto *(&&skip_id_getter_proto);
3088 DEFINE_OPCODE(op_get_by_id_getter_proto) {
3089 /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
3091 Cached property access: Attempts to get a cached getter property from the
3092 value base's prototype. If the cache misses, op_get_by_id_getter_proto
3093 reverts to op_get_by_id.
3095 int base = vPC[2].u.operand;
3096 JSValue baseValue = callFrame->r(base).jsValue();
3098 if (LIKELY(baseValue.isCell())) {
3099 JSCell* baseCell = baseValue.asCell();
3100 Structure* structure = vPC[4].u.structure.get();
3102 if (LIKELY(baseCell->structure() == structure)) {
3103 ASSERT(structure->prototypeForLookup(callFrame).isObject());
3104 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
3105 Structure* prototypeStructure = vPC[5].u.structure.get();
3107 if (LIKELY(protoObject->structure() == prototypeStructure)) {
3108 int dst = vPC[1].u.operand;
3109 int offset = vPC[6].u.operand;
3110 if (GetterSetter* getterSetter = asGetterSetter(protoObject->getDirectOffset(offset).asCell())) {
3111 JSObject* getter = getterSetter->getter();
3113 CallType callType = getter->methodTable()->getCallData(getter, callData);
3114 JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
3115 CHECK_FOR_EXCEPTION();
3116 callFrame->uncheckedR(dst) = result;
3118 callFrame->uncheckedR(dst) = jsUndefined();
3119 vPC += OPCODE_LENGTH(op_get_by_id_getter_proto);
3124 uncacheGetByID(codeBlock, vPC);
3127 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3128 skip_id_getter_proto:
3130 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3131 goto *(&&skip_id_custom_proto);
3133 DEFINE_OPCODE(op_get_by_id_custom_proto) {
3134 /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
3136 Cached property access: Attempts to use a cached named property getter
3137 from the value base's prototype. If the cache misses, op_get_by_id_custom_proto
3138 reverts to op_get_by_id.
3140 int base = vPC[2].u.operand;
3141 JSValue baseValue = callFrame->r(base).jsValue();
3143 if (LIKELY(baseValue.isCell())) {
3144 JSCell* baseCell = baseValue.asCell();
3145 Structure* structure = vPC[4].u.structure.get();
3147 if (LIKELY(baseCell->structure() == structure)) {
3148 ASSERT(structure->prototypeForLookup(callFrame).isObject());
3149 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
3150 Structure* prototypeStructure = vPC[5].u.structure.get();
3152 if (LIKELY(protoObject->structure() == prototypeStructure)) {
3153 int dst = vPC[1].u.operand;
3154 int property = vPC[3].u.operand;
3155 Identifier& ident = codeBlock->identifier(property);
3157 PropertySlot::GetValueFunc getter = vPC[6].u.getterFunc;
3158 JSValue result = getter(callFrame, protoObject, ident);
3159 CHECK_FOR_EXCEPTION();
3160 callFrame->uncheckedR(dst) = result;
3161 vPC += OPCODE_LENGTH(op_get_by_id_custom_proto);
3166 uncacheGetByID(codeBlock, vPC);
3169 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3170 skip_id_custom_proto:
3172 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3173 goto *(&&skip_get_by_id_chain);
3175 DEFINE_OPCODE(op_get_by_id_chain) {
3176 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
3178 Cached property access: Attempts to get a cached property from the
3179 value base's prototype chain. If the cache misses, op_get_by_id_chain
3180 reverts to op_get_by_id.
3182 int base = vPC[2].u.operand;
3183 JSValue baseValue = callFrame->r(base).jsValue();
3185 if (LIKELY(baseValue.isCell())) {
3186 JSCell* baseCell = baseValue.asCell();
3187 Structure* structure = vPC[4].u.structure.get();
3189 if (LIKELY(baseCell->structure() == structure)) {
3190 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
3191 size_t count = vPC[6].u.operand;
3192 WriteBarrier<Structure>* end = it + count;
3195 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
3197 if (UNLIKELY(baseObject->structure() != (*it).get()))
3201 int dst = vPC[1].u.operand;
3202 int offset = vPC[7].u.operand;
3204 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
3205 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
3206 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));