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 "JSByteArray.h"
48 #include "JSFunction.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 "UStringConcatenate.h"
66 #include <wtf/Threading.h>
72 #define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(COMPUTED_GOTO_INTERPRETER) && !defined(__llvm__))
78 // Returns the depth of the scope chain within a given call frame.
79 static int depth(CodeBlock* codeBlock, ScopeChainNode* sc)
81 if (!codeBlock->needsFullScopeChain())
83 return sc->localDepth();
86 #if ENABLE(INTERPRETER)
87 static NEVER_INLINE JSValue concatenateStrings(ExecState* exec, Register* strings, unsigned count)
89 return jsString(exec, strings, count);
92 NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
94 int dst = vPC[1].u.operand;
95 int property = vPC[2].u.operand;
97 ScopeChainNode* scopeChain = callFrame->scopeChain();
98 ScopeChainIterator iter = scopeChain->begin();
99 ScopeChainIterator end = scopeChain->end();
102 CodeBlock* codeBlock = callFrame->codeBlock();
103 Identifier& ident = codeBlock->identifier(property);
105 JSObject* o = iter->get();
106 PropertySlot slot(o);
107 if (o->getPropertySlot(callFrame, ident, slot)) {
108 JSValue result = slot.getValue(callFrame, ident);
109 exceptionValue = callFrame->globalData().exception;
112 callFrame->uncheckedR(dst) = JSValue(result);
115 } while (++iter != end);
116 exceptionValue = createUndefinedVariableError(callFrame, ident);
120 NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
122 CodeBlock* codeBlock = callFrame->codeBlock();
124 int dst = vPC[1].u.operand;
125 int property = vPC[2].u.operand;
126 int skip = vPC[3].u.operand;
128 ScopeChainNode* scopeChain = callFrame->scopeChain();
129 ScopeChainIterator iter = scopeChain->begin();
130 ScopeChainIterator end = scopeChain->end();
132 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
133 ASSERT(skip || !checkTopLevel);
134 if (checkTopLevel && skip--) {
135 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
142 Identifier& ident = codeBlock->identifier(property);
144 JSObject* o = iter->get();
145 PropertySlot slot(o);
146 if (o->getPropertySlot(callFrame, ident, slot)) {
147 JSValue result = slot.getValue(callFrame, ident);
148 exceptionValue = callFrame->globalData().exception;
152 callFrame->uncheckedR(dst) = JSValue(result);
155 } while (++iter != end);
156 exceptionValue = createUndefinedVariableError(callFrame, ident);
160 NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
162 int dst = vPC[1].u.operand;
163 CodeBlock* codeBlock = callFrame->codeBlock();
164 JSGlobalObject* globalObject = codeBlock->globalObject();
165 ASSERT(globalObject->isGlobalObject());
166 int property = vPC[2].u.operand;
167 Structure* structure = vPC[3].u.structure.get();
168 int offset = vPC[4].u.operand;
170 if (structure == globalObject->structure()) {
171 callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
175 Identifier& ident = codeBlock->identifier(property);
176 PropertySlot slot(globalObject);
177 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
178 JSValue result = slot.getValue(callFrame, ident);
179 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
180 vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
181 vPC[4] = slot.cachedOffset();
182 callFrame->uncheckedR(dst) = JSValue(result);
186 exceptionValue = callFrame->globalData().exception;
189 callFrame->uncheckedR(dst) = JSValue(result);
193 exceptionValue = createUndefinedVariableError(callFrame, ident);
197 NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
199 int dst = vPC[1].u.operand;
200 CodeBlock* codeBlock = callFrame->codeBlock();
201 JSGlobalObject* globalObject = codeBlock->globalObject();
202 ASSERT(globalObject->isGlobalObject());
203 int property = vPC[2].u.operand;
204 Structure* structure = vPC[3].u.structure.get();
205 int offset = vPC[4].u.operand;
206 int skip = vPC[5].u.operand;
208 ScopeChainNode* scopeChain = callFrame->scopeChain();
209 ScopeChainIterator iter = scopeChain->begin();
210 ScopeChainIterator end = scopeChain->end();
212 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
213 ASSERT(skip || !checkTopLevel);
214 if (checkTopLevel && skip--) {
215 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
219 JSObject* o = iter->get();
220 if (o->hasCustomProperties()) {
221 Identifier& ident = codeBlock->identifier(property);
223 PropertySlot slot(o);
224 if (o->getPropertySlot(callFrame, ident, slot)) {
225 JSValue result = slot.getValue(callFrame, ident);
226 exceptionValue = callFrame->globalData().exception;
230 callFrame->uncheckedR(dst) = JSValue(result);
238 exceptionValue = createUndefinedVariableError(callFrame, ident);
244 if (structure == globalObject->structure()) {
245 callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
246 ASSERT(callFrame->uncheckedR(dst).jsValue());
250 Identifier& ident = codeBlock->identifier(property);
251 PropertySlot slot(globalObject);
252 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
253 JSValue result = slot.getValue(callFrame, ident);
254 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
255 vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
256 vPC[4] = slot.cachedOffset();
258 callFrame->uncheckedR(dst) = JSValue(result);
262 exceptionValue = callFrame->globalData().exception;
266 callFrame->uncheckedR(dst) = JSValue(result);
270 exceptionValue = createUndefinedVariableError(callFrame, ident);
274 NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
276 int dst = vPC[1].u.operand;
277 int property = vPC[2].u.operand;
278 bool isStrictPut = vPC[3].u.operand;
279 Identifier ident = callFrame->codeBlock()->identifier(property);
280 JSValue result = JSC::resolveBase(callFrame, ident, callFrame->scopeChain(), isStrictPut);
282 callFrame->uncheckedR(dst) = result;
283 ASSERT(callFrame->uncheckedR(dst).jsValue());
285 callFrame->globalData().exception = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
288 NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
290 int baseDst = vPC[1].u.operand;
291 int propDst = vPC[2].u.operand;
292 int property = vPC[3].u.operand;
294 ScopeChainNode* scopeChain = callFrame->scopeChain();
295 ScopeChainIterator iter = scopeChain->begin();
296 ScopeChainIterator end = scopeChain->end();
298 // FIXME: add scopeDepthIsZero optimization
302 CodeBlock* codeBlock = callFrame->codeBlock();
303 Identifier& ident = codeBlock->identifier(property);
307 PropertySlot slot(base);
308 if (base->getPropertySlot(callFrame, ident, slot)) {
309 JSValue result = slot.getValue(callFrame, ident);
310 exceptionValue = callFrame->globalData().exception;
313 callFrame->uncheckedR(propDst) = JSValue(result);
314 callFrame->uncheckedR(baseDst) = JSValue(base);
318 } while (iter != end);
320 exceptionValue = createUndefinedVariableError(callFrame, ident);
324 NEVER_INLINE bool Interpreter::resolveThisAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
326 int thisDst = vPC[1].u.operand;
327 int propDst = vPC[2].u.operand;
328 int property = vPC[3].u.operand;
330 ScopeChainNode* scopeChain = callFrame->scopeChain();
331 ScopeChainIterator iter = scopeChain->begin();
332 ScopeChainIterator end = scopeChain->end();
334 // FIXME: add scopeDepthIsZero optimization
338 CodeBlock* codeBlock = callFrame->codeBlock();
339 Identifier& ident = codeBlock->identifier(property);
344 PropertySlot slot(base);
345 if (base->getPropertySlot(callFrame, ident, slot)) {
346 JSValue result = slot.getValue(callFrame, ident);
347 exceptionValue = callFrame->globalData().exception;
350 callFrame->uncheckedR(propDst) = JSValue(result);
351 // All entries on the scope chain should be EnvironmentRecords (activations etc),
352 // other then 'with' object, which are directly referenced from the scope chain,
353 // and the global object. If we hit either an EnvironmentRecord or a global
354 // object at the end of the scope chain, this is undefined. If we hit a non-
355 // EnvironmentRecord within the scope chain, pass the base as the this value.
356 if (iter == end || base->structure()->typeInfo().isEnvironmentRecord())
357 callFrame->uncheckedR(thisDst) = jsUndefined();
359 callFrame->uncheckedR(thisDst) = JSValue(base);
362 } while (iter != end);
364 exceptionValue = createUndefinedVariableError(callFrame, ident);
368 #endif // ENABLE(INTERPRETER)
370 ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
372 Register* r = callFrame->registers();
373 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters;
375 if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments
376 if (UNLIKELY(!registerFile->grow(newEnd)))
379 } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks
380 size_t omittedArgCount = newCodeBlock->m_numParameters - argc;
381 registerOffset += omittedArgCount;
382 newEnd += omittedArgCount;
383 if (!registerFile->grow(newEnd))
387 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
388 for (size_t i = 0; i < omittedArgCount; ++i)
389 argv[i] = jsUndefined();
390 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
391 size_t numParameters = newCodeBlock->m_numParameters;
392 registerOffset += numParameters;
393 newEnd += numParameters;
395 if (!registerFile->grow(newEnd))
399 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
400 for (size_t i = 0; i < numParameters; ++i)
401 argv[i + argc] = argv[i];
404 return CallFrame::create(r);
407 #if ENABLE(INTERPRETER)
408 static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
410 if (value.isObject())
412 exceptionData = createInvalidParamError(callFrame, "in" , value);
416 static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
418 if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
420 exceptionData = createInvalidParamError(callFrame, "instanceof" , value);
425 NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset)
428 return jsUndefined();
430 JSValue program = argv[1].jsValue();
432 if (!program.isString())
435 UString programSource = asString(program)->value(callFrame);
436 if (callFrame->hadException())
439 CodeBlock* codeBlock = callFrame->codeBlock();
441 ScopeChainNode* scopeChain = callFrame->scopeChain();
442 EvalExecutable* eval = codeBlock->evalCodeCache().tryGet(codeBlock->isStrictMode(), programSource, scopeChain);
445 if (!codeBlock->isStrictMode()) {
446 // FIXME: We can use the preparser in strict mode, we just need additional logic
447 // to prevent duplicates.
448 LiteralParser preparser(callFrame, programSource.characters(), programSource.length(), LiteralParser::NonStrictJSON);
449 if (JSValue parsedObject = preparser.tryLiteralParse())
453 JSValue exceptionValue;
454 eval = codeBlock->evalCodeCache().getSlow(callFrame, codeBlock->ownerExecutable(), codeBlock->isStrictMode(), programSource, scopeChain, exceptionValue);
456 ASSERT(!eval == exceptionValue);
458 return throwError(callFrame, exceptionValue);
461 JSValue thisValue = callFrame->uncheckedR(codeBlock->thisRegister()).jsValue();
462 ASSERT(isValidThisObject(thisValue, callFrame));
463 return callFrame->globalData().interpreter->execute(eval, callFrame, thisValue, callFrame->registers() - registerFile->begin() + registerOffset, scopeChain);
466 Interpreter::Interpreter()
467 : m_sampleEntryDepth(0)
470 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
471 privateExecute(InitializeAndReturn, 0, 0);
473 for (int i = 0; i < numOpcodeIDs; ++i)
474 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
475 #endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
477 #if ENABLE(OPCODE_SAMPLING)
484 void Interpreter::dumpCallFrame(CallFrame* callFrame)
486 callFrame->codeBlock()->dump(callFrame);
487 dumpRegisters(callFrame);
490 void Interpreter::dumpRegisters(CallFrame* callFrame)
492 printf("Register frame: \n\n");
493 printf("-----------------------------------------------------------------------------\n");
494 printf(" use | address | value \n");
495 printf("-----------------------------------------------------------------------------\n");
497 CodeBlock* codeBlock = callFrame->codeBlock();
502 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters;
504 #if USE(JSVALUE32_64)
505 printf("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it;
507 printf("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it;
509 end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this"
513 #if USE(JSVALUE32_64)
514 printf("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
516 printf("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
521 printf("-----------------------------------------------------------------------------\n");
522 printf("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it;
523 printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
524 printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
525 printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
526 printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
527 printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it;
528 printf("-----------------------------------------------------------------------------\n");
530 int registerCount = 0;
532 end = it + codeBlock->m_numVars;
536 #if USE(JSVALUE32_64)
537 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
539 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
545 printf("-----------------------------------------------------------------------------\n");
547 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
551 #if USE(JSVALUE32_64)
552 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
554 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
560 printf("-----------------------------------------------------------------------------\n");
565 bool Interpreter::isOpcode(Opcode opcode)
567 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
568 return opcode != HashTraits<Opcode>::emptyValue()
569 && !HashTraits<Opcode>::isDeletedValue(opcode)
570 && m_opcodeIDTable.contains(opcode);
572 return opcode >= 0 && opcode <= op_end;
576 NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
578 CodeBlock* oldCodeBlock = codeBlock;
579 ScopeChainNode* scopeChain = callFrame->scopeChain();
581 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
582 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
583 if (callFrame->callee())
584 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
586 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
589 // If this call frame created an activation or an 'arguments' object, tear it off.
590 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
591 if (!callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue()) {
592 oldCodeBlock->createActivation(callFrame);
593 scopeChain = callFrame->scopeChain();
595 while (!scopeChain->object->inherits(&JSActivation::s_info))
596 scopeChain = scopeChain->pop();
598 callFrame->setScopeChain(scopeChain);
599 JSActivation* activation = asActivation(scopeChain->object.get());
600 activation->copyRegisters(*scopeChain->globalData);
601 if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) {
602 if (!oldCodeBlock->isStrictMode())
603 asArguments(arguments)->setActivation(callFrame->globalData(), activation);
605 } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) {
606 if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
607 asArguments(arguments)->copyRegisters(callFrame->globalData());
610 CallFrame* callerFrame = callFrame->callerFrame();
611 callFrame->globalData().topCallFrame = callerFrame;
612 if (callerFrame->hasHostCallFrameFlag())
615 codeBlock = callerFrame->codeBlock();
617 // Because of how the JIT records call site->bytecode offset
618 // information the JIT reports the bytecodeOffset for the returnPC
619 // to be at the beginning of the opcode that has caused the call.
620 // In the interpreter we have an actual return address, which is
621 // the beginning of next instruction to execute. To get an offset
622 // inside the call instruction that triggered the exception we
623 // have to subtract 1.
624 #if ENABLE(JIT) && ENABLE(INTERPRETER)
625 if (callerFrame->globalData().canUseJIT())
626 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
628 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1;
630 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
632 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1;
635 callFrame = callerFrame;
639 static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
641 exception->clearAppendSourceToMessage();
643 if (!callFrame->codeBlock()->hasExpressionInfo())
650 CodeBlock* codeBlock = callFrame->codeBlock();
651 codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset);
653 int expressionStart = divotPoint - startOffset;
654 int expressionStop = divotPoint + endOffset;
656 if (!expressionStop || expressionStart > codeBlock->source()->length())
659 JSGlobalData* globalData = &callFrame->globalData();
660 JSValue jsMessage = exception->getDirect(*globalData, globalData->propertyNames->message);
661 if (!jsMessage || !jsMessage.isString())
664 UString message = asString(jsMessage)->value(callFrame);
666 if (expressionStart < expressionStop)
667 message = makeUString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')");
669 // No range information, so give a few characters of context
670 const UChar* data = codeBlock->source()->data();
671 int dataLength = codeBlock->source()->length();
672 int start = expressionStart;
673 int stop = expressionStart;
674 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
675 // then strip whitespace.
676 while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
678 while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
680 while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
682 while (stop > expressionStart && isStrWhiteSpace(data[stop - 1]))
684 message = makeUString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')");
687 exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message));
690 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
692 CodeBlock* codeBlock = callFrame->codeBlock();
693 bool isInterrupt = false;
695 // Set up the exception object
696 if (exceptionValue.isObject()) {
697 JSObject* exception = asObject(exceptionValue);
699 if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage())
700 appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset);
702 // Using hasExpressionInfo to imply we are interested in rich exception info.
703 if (codeBlock->hasExpressionInfo() && !hasErrorInfo(callFrame, exception)) {
704 ASSERT(codeBlock->hasLineInfo());
706 // FIXME: should only really be adding these properties to VM generated exceptions,
707 // but the inspector currently requires these for all thrown objects.
708 addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source());
711 isInterrupt = isInterruptedExecutionException(exception) || isTerminatedExecutionException(exception);
714 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
715 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
716 bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
717 debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), hasHandler);
720 // Calculate an exception handler vPC, unwinding call frames as necessary.
721 HandlerInfo* handler = 0;
722 while (isInterrupt || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
723 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
724 if (Profiler* profiler = *Profiler::enabledProfilerReference())
725 profiler->exceptionUnwind(callFrame);
730 if (Profiler* profiler = *Profiler::enabledProfilerReference())
731 profiler->exceptionUnwind(callFrame);
733 // Shrink the JS stack, in case stack overflow made it huge.
734 Register* highWaterMark = 0;
735 for (CallFrame* callerFrame = callFrame; callerFrame; callerFrame = callerFrame->callerFrame()->removeHostCallFrameFlag()) {
736 CodeBlock* codeBlock = callerFrame->codeBlock();
739 Register* callerHighWaterMark = callerFrame->registers() + codeBlock->m_numCalleeRegisters;
740 highWaterMark = max(highWaterMark, callerHighWaterMark);
742 m_registerFile.shrink(highWaterMark);
744 // Unwind the scope chain within the exception handler's call frame.
745 ScopeChainNode* scopeChain = callFrame->scopeChain();
747 if (!codeBlock->needsFullScopeChain() || codeBlock->codeType() != FunctionCode
748 || callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
749 scopeDelta = depth(codeBlock, scopeChain) - handler->scopeDepth;
750 ASSERT(scopeDelta >= 0);
752 scopeChain = scopeChain->pop();
753 callFrame->setScopeChain(scopeChain);
758 static inline JSValue checkedReturn(JSValue returnValue)
764 static inline JSObject* checkedReturn(JSObject* returnValue)
770 JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
772 ASSERT(isValidThisObject(thisObj, callFrame));
773 ASSERT(!scopeChain->globalData->exception);
774 ASSERT(!callFrame->globalData().isCollectorBusy());
775 if (callFrame->globalData().isCollectorBusy())
778 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
779 return checkedReturn(throwStackOverflowError(callFrame));
781 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
782 LiteralParser literalParser(callFrame, program->source().data(), program->source().length(), LiteralParser::JSONP);
783 Vector<LiteralParser::JSONPData> JSONPData;
784 if (literalParser.tryJSONPParse(JSONPData, scopeChain->globalObject->supportsRichSourceInfo())) {
785 JSGlobalObject* globalObject = scopeChain->globalObject.get();
787 for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
788 Vector<LiteralParser::JSONPPathEntry> JSONPPath;
789 JSONPPath.swap(JSONPData[entry].m_path);
790 JSValue JSONPValue = JSONPData[entry].m_value.get();
791 if (JSONPPath.size() == 1 && JSONPPath[0].m_type == LiteralParser::JSONPPathEntryTypeDeclare) {
792 if (globalObject->hasProperty(callFrame, JSONPPath[0].m_pathEntryName)) {
793 PutPropertySlot slot;
794 globalObject->put(callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
796 globalObject->putWithAttributes(callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, DontEnum | DontDelete);
797 // var declarations return undefined
798 result = jsUndefined();
801 JSValue baseObject(globalObject);
802 for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
803 ASSERT(JSONPPath[i].m_type != LiteralParser::JSONPPathEntryTypeDeclare);
804 switch (JSONPPath[i].m_type) {
805 case LiteralParser::JSONPPathEntryTypeDot: {
807 PropertySlot slot(globalObject);
808 if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) {
810 return throwError(callFrame, createUndefinedVariableError(globalObject->globalExec(), JSONPPath[i].m_pathEntryName));
813 baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);
815 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName);
816 if (callFrame->hadException())
817 return jsUndefined();
820 case LiteralParser::JSONPPathEntryTypeLookup: {
821 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathIndex);
822 if (callFrame->hadException())
823 return jsUndefined();
827 ASSERT_NOT_REACHED();
828 return jsUndefined();
831 PutPropertySlot slot;
832 switch (JSONPPath.last().m_type) {
833 case LiteralParser::JSONPPathEntryTypeCall: {
834 JSValue function = baseObject.get(callFrame, JSONPPath.last().m_pathEntryName);
835 if (callFrame->hadException())
836 return jsUndefined();
838 CallType callType = getCallData(function, callData);
839 if (callType == CallTypeNone)
840 return throwError(callFrame, createNotAFunctionError(callFrame, function));
841 MarkedArgumentBuffer jsonArg;
842 jsonArg.append(JSONPValue);
843 JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined(): baseObject;
844 JSONPValue = JSC::call(callFrame, function, callType, callData, thisValue, jsonArg);
845 if (callFrame->hadException())
846 return jsUndefined();
849 case LiteralParser::JSONPPathEntryTypeDot: {
850 baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
851 if (callFrame->hadException())
852 return jsUndefined();
855 case LiteralParser::JSONPPathEntryTypeLookup: {
856 baseObject.put(callFrame, JSONPPath.last().m_pathIndex, JSONPValue);
857 if (callFrame->hadException())
858 return jsUndefined();
862 ASSERT_NOT_REACHED();
863 return jsUndefined();
870 JSObject* error = program->compile(callFrame, scopeChain);
872 return checkedReturn(throwError(callFrame, error));
873 CodeBlock* codeBlock = &program->generatedBytecode();
875 Register* oldEnd = m_registerFile.end();
876 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
877 if (!m_registerFile.grow(newEnd))
878 return checkedReturn(throwStackOverflowError(callFrame));
880 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
881 ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
882 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), codeBlock->m_numParameters, 0);
883 newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
884 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
886 Profiler** profiler = Profiler::enabledProfilerReference();
888 (*profiler)->willExecute(callFrame, program->sourceURL(), program->lineNo());
892 SamplingTool::CallRecord callRecord(m_sampler.get());
896 if (callFrame->globalData().canUseJIT())
897 result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
900 result = privateExecute(Normal, &m_registerFile, newCallFrame);
906 (*profiler)->didExecute(callFrame, program->sourceURL(), program->lineNo());
908 m_registerFile.shrink(oldEnd);
910 return checkedReturn(result);
913 JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
915 ASSERT(isValidThisObject(thisValue, callFrame));
916 ASSERT(!callFrame->hadException());
917 ASSERT(!callFrame->globalData().isCollectorBusy());
918 if (callFrame->globalData().isCollectorBusy())
921 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
922 return checkedReturn(throwStackOverflowError(callFrame));
924 Register* oldEnd = m_registerFile.end();
925 int argCount = 1 + args.size(); // implicit "this" parameter
926 size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
928 if (!m_registerFile.grow(oldEnd + registerOffset))
929 return checkedReturn(throwStackOverflowError(callFrame));
931 CallFrame* newCallFrame = CallFrame::create(oldEnd);
933 newCallFrame->uncheckedR(0) = thisValue;
934 ArgList::const_iterator end = args.end();
935 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
936 newCallFrame->uncheckedR(++dst) = *it;
938 if (callType == CallTypeJS) {
939 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
941 DynamicGlobalObjectScope globalObjectScope(*callDataScopeChain->globalData, callDataScopeChain->globalObject.get());
943 JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
944 if (UNLIKELY(!!compileError)) {
945 m_registerFile.shrink(oldEnd);
946 return checkedReturn(throwError(callFrame, compileError));
949 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
950 newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
951 if (UNLIKELY(!newCallFrame)) {
952 m_registerFile.shrink(oldEnd);
953 return checkedReturn(throwStackOverflowError(callFrame));
956 newCallFrame->init(newCodeBlock, 0, callDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
958 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
960 Profiler** profiler = Profiler::enabledProfilerReference();
962 (*profiler)->willExecute(callFrame, function);
966 SamplingTool::CallRecord callRecord(m_sampler.get());
970 if (callFrame->globalData().canUseJIT())
971 result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScopeChain->globalData);
974 result = privateExecute(Normal, &m_registerFile, newCallFrame);
979 (*profiler)->didExecute(callFrame, function);
981 m_registerFile.shrink(oldEnd);
982 return checkedReturn(result);
985 ASSERT(callType == CallTypeHost);
986 ScopeChainNode* scopeChain = callFrame->scopeChain();
987 newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
988 newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
990 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
992 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
994 Profiler** profiler = Profiler::enabledProfilerReference();
996 (*profiler)->willExecute(callFrame, function);
1000 SamplingTool::HostCallRecord callRecord(m_sampler.get());
1001 result = JSValue::decode(callData.native.function(newCallFrame));
1005 (*profiler)->didExecute(callFrame, function);
1007 m_registerFile.shrink(oldEnd);
1008 return checkedReturn(result);
1011 JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
1013 ASSERT(!callFrame->hadException());
1014 ASSERT(!callFrame->globalData().isCollectorBusy());
1015 // We throw in this case because we have to return something "valid" but we're
1016 // already in an invalid state.
1017 if (callFrame->globalData().isCollectorBusy())
1018 return checkedReturn(throwStackOverflowError(callFrame));
1020 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
1021 return checkedReturn(throwStackOverflowError(callFrame));
1023 Register* oldEnd = m_registerFile.end();
1024 int argCount = 1 + args.size(); // implicit "this" parameter
1025 size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
1027 if (!m_registerFile.grow(oldEnd + registerOffset))
1028 return checkedReturn(throwStackOverflowError(callFrame));
1030 CallFrame* newCallFrame = CallFrame::create(oldEnd);
1032 ArgList::const_iterator end = args.end();
1033 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
1034 newCallFrame->uncheckedR(++dst) = *it;
1036 if (constructType == ConstructTypeJS) {
1037 ScopeChainNode* constructDataScopeChain = constructData.js.scopeChain;
1039 DynamicGlobalObjectScope globalObjectScope(*constructDataScopeChain->globalData, constructDataScopeChain->globalObject.get());
1041 JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, constructDataScopeChain);
1042 if (UNLIKELY(!!compileError)) {
1043 m_registerFile.shrink(oldEnd);
1044 return checkedReturn(throwError(callFrame, compileError));
1047 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
1048 newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
1049 if (UNLIKELY(!newCallFrame)) {
1050 m_registerFile.shrink(oldEnd);
1051 return checkedReturn(throwStackOverflowError(callFrame));
1054 newCallFrame->init(newCodeBlock, 0, constructDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
1056 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
1058 Profiler** profiler = Profiler::enabledProfilerReference();
1060 (*profiler)->willExecute(callFrame, constructor);
1064 SamplingTool::CallRecord callRecord(m_sampler.get());
1068 if (callFrame->globalData().canUseJIT())
1069 result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScopeChain->globalData);
1072 result = privateExecute(Normal, &m_registerFile, newCallFrame);
1077 (*profiler)->didExecute(callFrame, constructor);
1079 m_registerFile.shrink(oldEnd);
1080 if (callFrame->hadException())
1082 ASSERT(result.isObject());
1083 return checkedReturn(asObject(result));
1086 ASSERT(constructType == ConstructTypeHost);
1087 ScopeChainNode* scopeChain = callFrame->scopeChain();
1088 newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
1089 newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
1091 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
1093 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
1095 Profiler** profiler = Profiler::enabledProfilerReference();
1097 (*profiler)->willExecute(callFrame, constructor);
1101 SamplingTool::HostCallRecord callRecord(m_sampler.get());
1102 result = JSValue::decode(constructData.native.function(newCallFrame));
1106 (*profiler)->didExecute(callFrame, constructor);
1108 m_registerFile.shrink(oldEnd);
1109 if (callFrame->hadException())
1111 ASSERT(result.isObject());
1112 return checkedReturn(asObject(result));
1115 CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain)
1117 ASSERT(!scopeChain->globalData->exception);
1119 if (m_reentryDepth >= MaxSmallThreadReentryDepth) {
1120 if (m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
1121 throwStackOverflowError(callFrame);
1122 return CallFrameClosure();
1126 Register* oldEnd = m_registerFile.end();
1127 int argc = 1 + argCount; // implicit "this" parameter
1129 if (!m_registerFile.grow(oldEnd + argc)) {
1130 throwStackOverflowError(callFrame);
1131 return CallFrameClosure();
1134 CallFrame* newCallFrame = CallFrame::create(oldEnd);
1135 // We initialise |this| unnecessarily here for the sake of code clarity
1137 for (int i = 0; i < argc; ++i)
1138 newCallFrame->uncheckedR(dst++) = jsUndefined();
1140 JSObject* error = FunctionExecutable->compileForCall(callFrame, scopeChain);
1142 throwError(callFrame, error);
1143 m_registerFile.shrink(oldEnd);
1144 return CallFrameClosure();
1146 CodeBlock* codeBlock = &FunctionExecutable->generatedBytecodeForCall();
1148 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
1149 if (UNLIKELY(!newCallFrame)) {
1150 throwStackOverflowError(callFrame);
1151 m_registerFile.shrink(oldEnd);
1152 return CallFrameClosure();
1154 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), argc, function);
1155 scopeChain->globalData->topCallFrame = newCallFrame;
1156 CallFrameClosure result = { callFrame, newCallFrame, function, FunctionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc };
1160 JSValue Interpreter::execute(CallFrameClosure& closure)
1162 ASSERT(!closure.oldCallFrame->globalData().isCollectorBusy());
1163 if (closure.oldCallFrame->globalData().isCollectorBusy())
1165 closure.resetCallFrame();
1166 Profiler** profiler = Profiler::enabledProfilerReference();
1168 (*profiler)->willExecute(closure.oldCallFrame, closure.function);
1170 TopCallFrameSetter topCallFrame(*closure.globalData, closure.newCallFrame);
1174 SamplingTool::CallRecord callRecord(m_sampler.get());
1178 #if ENABLE(INTERPRETER)
1179 if (closure.newCallFrame->globalData().canUseJIT())
1181 result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, closure.newCallFrame, closure.globalData);
1182 #if ENABLE(INTERPRETER)
1186 #if ENABLE(INTERPRETER)
1187 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame);
1193 (*profiler)->didExecute(closure.oldCallFrame, closure.function);
1194 return checkedReturn(result);
1197 void Interpreter::endRepeatCall(CallFrameClosure& closure)
1199 closure.globalData->topCallFrame = closure.oldCallFrame;
1200 m_registerFile.shrink(closure.oldEnd);
1203 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, ScopeChainNode* scopeChain)
1205 JSObject* compileError = eval->compile(callFrame, scopeChain);
1206 if (UNLIKELY(!!compileError))
1207 return checkedReturn(throwError(callFrame, compileError));
1208 return execute(eval, callFrame, thisValue, m_registerFile.size() + eval->generatedBytecode().m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain);
1211 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, int globalRegisterOffset, ScopeChainNode* scopeChain)
1213 ASSERT(isValidThisObject(thisValue, callFrame));
1214 ASSERT(!scopeChain->globalData->exception);
1215 ASSERT(!callFrame->globalData().isCollectorBusy());
1216 if (callFrame->globalData().isCollectorBusy())
1219 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
1221 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
1222 return checkedReturn(throwStackOverflowError(callFrame));
1224 JSObject* compileError = eval->compile(callFrame, scopeChain);
1225 if (UNLIKELY(!!compileError))
1226 return checkedReturn(throwError(callFrame, compileError));
1227 EvalCodeBlock* codeBlock = &eval->generatedBytecode();
1229 JSObject* variableObject;
1230 for (ScopeChainNode* node = scopeChain; ; node = node->next.get()) {
1232 if (node->object->isVariableObject()) {
1233 variableObject = static_cast<JSVariableObject*>(node->object.get());
1238 unsigned numVariables = codeBlock->numVariables();
1239 int numFunctions = codeBlock->numberOfFunctionDecls();
1240 bool pushedScope = false;
1241 if (numVariables || numFunctions) {
1242 if (codeBlock->isStrictMode()) {
1243 variableObject = StrictEvalActivation::create(callFrame);
1244 scopeChain = scopeChain->push(variableObject);
1247 // Scope for BatchedTransitionOptimizer
1248 BatchedTransitionOptimizer optimizer(callFrame->globalData(), variableObject);
1250 for (unsigned i = 0; i < numVariables; ++i) {
1251 const Identifier& ident = codeBlock->variable(i);
1252 if (!variableObject->hasProperty(callFrame, ident)) {
1253 PutPropertySlot slot;
1254 variableObject->put(callFrame, ident, jsUndefined(), slot);
1258 for (int i = 0; i < numFunctions; ++i) {
1259 FunctionExecutable* function = codeBlock->functionDecl(i);
1260 PutPropertySlot slot;
1261 variableObject->put(callFrame, function->name(), function->make(callFrame, scopeChain), slot);
1265 Register* oldEnd = m_registerFile.end();
1266 Register* newEnd = m_registerFile.begin() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
1267 if (!m_registerFile.grow(newEnd)) {
1270 return checkedReturn(throwStackOverflowError(callFrame));
1273 CallFrame* newCallFrame = CallFrame::create(m_registerFile.begin() + globalRegisterOffset);
1275 ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
1276 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->m_numParameters, 0);
1277 newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = thisValue;
1279 TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame);
1281 Profiler** profiler = Profiler::enabledProfilerReference();
1283 (*profiler)->willExecute(callFrame, eval->sourceURL(), eval->lineNo());
1287 SamplingTool::CallRecord callRecord(m_sampler.get());
1292 #if ENABLE(INTERPRETER)
1293 if (callFrame->globalData().canUseJIT())
1295 result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
1296 #if ENABLE(INTERPRETER)
1300 #if ENABLE(INTERPRETER)
1301 result = privateExecute(Normal, &m_registerFile, newCallFrame);
1307 (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
1309 m_registerFile.shrink(oldEnd);
1312 return checkedReturn(result);
1315 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
1317 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
1321 switch (debugHookID) {
1322 case DidEnterCallFrame:
1323 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
1325 case WillLeaveCallFrame:
1326 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
1328 case WillExecuteStatement:
1329 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
1331 case WillExecuteProgram:
1332 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
1334 case DidExecuteProgram:
1335 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
1337 case DidReachBreakpoint:
1338 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
1343 #if ENABLE(INTERPRETER)
1344 NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
1346 int dst = vPC[1].u.operand;
1347 CodeBlock* codeBlock = callFrame->codeBlock();
1348 Identifier& property = codeBlock->identifier(vPC[2].u.operand);
1349 JSValue value = callFrame->r(vPC[3].u.operand).jsValue();
1350 JSObject* scope = JSStaticScopeObject::create(callFrame, property, value, DontDelete);
1351 callFrame->uncheckedR(dst) = JSValue(scope);
1353 return callFrame->scopeChain()->push(scope);
1356 NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot)
1358 // Recursive invocation may already have specialized this instruction.
1359 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1362 if (!baseValue.isCell())
1365 // Uncacheable: give up.
1366 if (!slot.isCacheable()) {
1367 vPC[0] = getOpcode(op_put_by_id_generic);
1371 JSCell* baseCell = baseValue.asCell();
1372 Structure* structure = baseCell->structure();
1374 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
1375 vPC[0] = getOpcode(op_put_by_id_generic);
1379 // Cache miss: record Structure to compare against next time.
1380 Structure* lastStructure = vPC[4].u.structure.get();
1381 if (structure != lastStructure) {
1382 // First miss: record Structure to compare against next time.
1383 if (!lastStructure) {
1384 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1388 // Second miss: give up.
1389 vPC[0] = getOpcode(op_put_by_id_generic);
1393 // Cache hit: Specialize instruction and ref Structures.
1395 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1396 if (baseCell != slot.base()) {
1397 vPC[0] = getOpcode(op_put_by_id_generic);
1401 // Structure transition, cache transition info
1402 if (slot.type() == PutPropertySlot::NewProperty) {
1403 if (structure->isDictionary()) {
1404 vPC[0] = getOpcode(op_put_by_id_generic);
1408 // put_by_id_transition checks the prototype chain for setters.
1409 normalizePrototypeChain(callFrame, baseCell);
1410 JSCell* owner = codeBlock->ownerExecutable();
1411 JSGlobalData& globalData = callFrame->globalData();
1412 // Get the prototype here because the call to prototypeChain could cause a
1413 // GC allocation, which we don't want to happen while we're in the middle of
1414 // initializing the union.
1415 StructureChain* prototypeChain = structure->prototypeChain(callFrame);
1416 vPC[0] = getOpcode(op_put_by_id_transition);
1417 vPC[4].u.structure.set(globalData, owner, structure->previousID());
1418 vPC[5].u.structure.set(globalData, owner, structure);
1419 vPC[6].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), prototypeChain);
1420 ASSERT(vPC[6].u.structureChain);
1421 vPC[7] = slot.cachedOffset();
1425 vPC[0] = getOpcode(op_put_by_id_replace);
1426 vPC[5] = slot.cachedOffset();
1429 NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock*, Instruction* vPC)
1431 vPC[0] = getOpcode(op_put_by_id);
1435 NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)
1437 // Recursive invocation may already have specialized this instruction.
1438 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1441 // FIXME: Cache property access for immediates.
1442 if (!baseValue.isCell()) {
1443 vPC[0] = getOpcode(op_get_by_id_generic);
1447 JSGlobalData* globalData = &callFrame->globalData();
1448 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
1449 vPC[0] = getOpcode(op_get_array_length);
1453 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
1454 vPC[0] = getOpcode(op_get_string_length);
1458 // Uncacheable: give up.
1459 if (!slot.isCacheable()) {
1460 vPC[0] = getOpcode(op_get_by_id_generic);
1464 Structure* structure = baseValue.asCell()->structure();
1466 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
1467 vPC[0] = getOpcode(op_get_by_id_generic);
1472 Structure* lastStructure = vPC[4].u.structure.get();
1473 if (structure != lastStructure) {
1474 // First miss: record Structure to compare against next time.
1475 if (!lastStructure) {
1476 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1480 // Second miss: give up.
1481 vPC[0] = getOpcode(op_get_by_id_generic);
1485 // Cache hit: Specialize instruction and ref Structures.
1487 if (slot.slotBase() == baseValue) {
1488 switch (slot.cachedPropertyType()) {
1489 case PropertySlot::Getter:
1490 vPC[0] = getOpcode(op_get_by_id_getter_self);
1491 vPC[5] = slot.cachedOffset();
1493 case PropertySlot::Custom:
1494 vPC[0] = getOpcode(op_get_by_id_custom_self);
1495 vPC[5] = slot.customGetter();
1498 vPC[0] = getOpcode(op_get_by_id_self);
1499 vPC[5] = slot.cachedOffset();
1505 if (structure->isDictionary()) {
1506 vPC[0] = getOpcode(op_get_by_id_generic);
1510 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
1511 ASSERT(slot.slotBase().isObject());
1513 JSObject* baseObject = asObject(slot.slotBase());
1514 size_t offset = slot.cachedOffset();
1516 // Since we're accessing a prototype in a loop, it's a good bet that it
1517 // should not be treated as a dictionary.
1518 if (baseObject->structure()->isDictionary()) {
1519 baseObject->flattenDictionaryObject(callFrame->globalData());
1520 offset = baseObject->structure()->get(callFrame->globalData(), propertyName);
1523 ASSERT(!baseObject->structure()->isUncacheableDictionary());
1525 switch (slot.cachedPropertyType()) {
1526 case PropertySlot::Getter:
1527 vPC[0] = getOpcode(op_get_by_id_getter_proto);
1530 case PropertySlot::Custom:
1531 vPC[0] = getOpcode(op_get_by_id_custom_proto);
1532 vPC[6] = slot.customGetter();
1535 vPC[0] = getOpcode(op_get_by_id_proto);
1539 vPC[5].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), baseObject->structure());
1543 size_t offset = slot.cachedOffset();
1544 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
1546 vPC[0] = getOpcode(op_get_by_id_generic);
1551 switch (slot.cachedPropertyType()) {
1552 case PropertySlot::Getter:
1553 vPC[0] = getOpcode(op_get_by_id_getter_chain);
1556 case PropertySlot::Custom:
1557 vPC[0] = getOpcode(op_get_by_id_custom_chain);
1558 vPC[7] = slot.customGetter();
1561 vPC[0] = getOpcode(op_get_by_id_chain);
1565 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1566 vPC[5].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure->prototypeChain(callFrame));
1570 NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock*, Instruction* vPC)
1572 vPC[0] = getOpcode(op_get_by_id);
1576 #endif // ENABLE(INTERPRETER)
1578 JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame)
1580 // One-time initialization of our address tables. We have to put this code
1581 // here because our labels are only in scope inside this function.
1582 if (UNLIKELY(flag == InitializeAndReturn)) {
1583 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
1584 #define LIST_OPCODE_LABEL(id, length) &&id,
1585 static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) };
1586 for (size_t i = 0; i < WTF_ARRAY_LENGTH(labels); ++i)
1587 m_opcodeTable[i] = labels[i];
1588 #undef LIST_OPCODE_LABEL
1589 #endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
1594 #if ENABLE(INTERPRETER)
1595 // Mixing Interpreter + JIT is not supported.
1596 if (callFrame->globalData().canUseJIT())
1598 ASSERT_NOT_REACHED();
1601 #if !ENABLE(INTERPRETER)
1602 UNUSED_PARAM(registerFile);
1603 UNUSED_PARAM(callFrame);
1607 ASSERT(callFrame->globalData().topCallFrame == callFrame);
1609 JSGlobalData* globalData = &callFrame->globalData();
1610 JSValue exceptionValue;
1611 HandlerInfo* handler = 0;
1612 CallFrame** topCallFrameSlot = &globalData->topCallFrame;
1614 CodeBlock* codeBlock = callFrame->codeBlock();
1615 Instruction* vPC = codeBlock->instructions().begin();
1616 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1617 unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();
1618 JSValue functionReturnValue;
1620 #define CHECK_FOR_EXCEPTION() \
1622 if (UNLIKELY(globalData->exception != JSValue())) { \
1623 exceptionValue = globalData->exception; \
1628 #if ENABLE(OPCODE_STATS)
1629 OpcodeStats::resetLastInstruction();
1632 #define CHECK_FOR_TIMEOUT() \
1633 if (!--tickCount) { \
1634 if (globalData->terminator.shouldTerminate() || globalData->timeoutChecker.didTimeOut(callFrame)) { \
1635 exceptionValue = jsNull(); \
1638 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1641 #if ENABLE(OPCODE_SAMPLING)
1642 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1644 #define SAMPLE(codeBlock, vPC)
1647 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
1648 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode
1649 #if ENABLE(OPCODE_STATS)
1650 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1652 #define DEFINE_OPCODE(opcode) opcode:
1656 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart
1657 #if ENABLE(OPCODE_STATS)
1658 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1660 #define DEFINE_OPCODE(opcode) case opcode:
1662 while (1) { // iterator loop begins
1663 interpreterLoopStart:;
1664 switch (vPC->u.opcode)
1667 DEFINE_OPCODE(op_new_object) {
1668 /* new_object dst(r)
1670 Constructs a new empty Object instance using the original
1671 constructor, and puts the result in register dst.
1673 int dst = vPC[1].u.operand;
1674 callFrame->uncheckedR(dst) = JSValue(constructEmptyObject(callFrame));
1676 vPC += OPCODE_LENGTH(op_new_object);
1679 DEFINE_OPCODE(op_new_array) {
1680 /* new_array dst(r) firstArg(r) argCount(n)
1682 Constructs a new Array instance using the original
1683 constructor, and puts the result in register dst.
1684 The array will contain argCount elements with values
1685 taken from registers starting at register firstArg.
1687 int dst = vPC[1].u.operand;
1688 int firstArg = vPC[2].u.operand;
1689 int argCount = vPC[3].u.operand;
1690 ArgList args(callFrame->registers() + firstArg, argCount);
1691 callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, args));
1693 vPC += OPCODE_LENGTH(op_new_array);
1696 DEFINE_OPCODE(op_new_array_buffer) {
1697 /* new_array_buffer dst(r) index(n) argCount(n)
1699 Constructs a new Array instance using the original
1700 constructor, and puts the result in register dst.
1701 The array be initialized with the values from constantBuffer[index]
1703 int dst = vPC[1].u.operand;
1704 int firstArg = vPC[2].u.operand;
1705 int argCount = vPC[3].u.operand;
1706 ArgList args(codeBlock->constantBuffer(firstArg), argCount);
1707 callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, args));
1709 vPC += OPCODE_LENGTH(op_new_array);
1712 DEFINE_OPCODE(op_new_regexp) {
1713 /* new_regexp dst(r) regExp(re)
1715 Constructs a new RegExp instance using the original
1716 constructor from regexp regExp, and puts the result in
1719 int dst = vPC[1].u.operand;
1720 RegExp* regExp = codeBlock->regexp(vPC[2].u.operand);
1721 if (!regExp->isValid()) {
1722 exceptionValue = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor.");
1725 callFrame->uncheckedR(dst) = JSValue(RegExpObject::create(*globalData, callFrame->lexicalGlobalObject(), callFrame->scopeChain()->globalObject->regExpStructure(), regExp));
1727 vPC += OPCODE_LENGTH(op_new_regexp);
1730 DEFINE_OPCODE(op_mov) {
1731 /* mov dst(r) src(r)
1733 Copies register src to register dst.
1735 int dst = vPC[1].u.operand;
1736 int src = vPC[2].u.operand;
1738 callFrame->uncheckedR(dst) = callFrame->r(src);
1740 vPC += OPCODE_LENGTH(op_mov);
1743 DEFINE_OPCODE(op_eq) {
1744 /* eq dst(r) src1(r) src2(r)
1746 Checks whether register src1 and register src2 are equal,
1747 as with the ECMAScript '==' operator, and puts the result
1748 as a boolean in register dst.
1750 int dst = vPC[1].u.operand;
1751 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1752 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1753 if (src1.isInt32() && src2.isInt32())
1754 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
1756 JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));
1757 CHECK_FOR_EXCEPTION();
1758 callFrame->uncheckedR(dst) = result;
1761 vPC += OPCODE_LENGTH(op_eq);
1764 DEFINE_OPCODE(op_eq_null) {
1765 /* eq_null dst(r) src(r)
1767 Checks whether register src is null, as with the ECMAScript '!='
1768 operator, and puts the result as a boolean in register dst.
1770 int dst = vPC[1].u.operand;
1771 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1773 if (src.isUndefinedOrNull()) {
1774 callFrame->uncheckedR(dst) = jsBoolean(true);
1775 vPC += OPCODE_LENGTH(op_eq_null);
1779 callFrame->uncheckedR(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1780 vPC += OPCODE_LENGTH(op_eq_null);
1783 DEFINE_OPCODE(op_neq) {
1784 /* neq dst(r) src1(r) src2(r)
1786 Checks whether register src1 and register src2 are not
1787 equal, as with the ECMAScript '!=' operator, and puts the
1788 result as a boolean in register dst.
1790 int dst = vPC[1].u.operand;
1791 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1792 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1793 if (src1.isInt32() && src2.isInt32())
1794 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
1796 JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));
1797 CHECK_FOR_EXCEPTION();
1798 callFrame->uncheckedR(dst) = result;
1801 vPC += OPCODE_LENGTH(op_neq);
1804 DEFINE_OPCODE(op_neq_null) {
1805 /* neq_null dst(r) src(r)
1807 Checks whether register src is not null, as with the ECMAScript '!='
1808 operator, and puts the result as a boolean in register dst.
1810 int dst = vPC[1].u.operand;
1811 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1813 if (src.isUndefinedOrNull()) {
1814 callFrame->uncheckedR(dst) = jsBoolean(false);
1815 vPC += OPCODE_LENGTH(op_neq_null);
1819 callFrame->uncheckedR(dst) = jsBoolean(!src.isCell() || !src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1820 vPC += OPCODE_LENGTH(op_neq_null);
1823 DEFINE_OPCODE(op_stricteq) {
1824 /* stricteq dst(r) src1(r) src2(r)
1826 Checks whether register src1 and register src2 are strictly
1827 equal, as with the ECMAScript '===' operator, and puts the
1828 result as a boolean in register dst.
1830 int dst = vPC[1].u.operand;
1831 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1832 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1833 bool result = JSValue::strictEqual(callFrame, src1, src2);
1834 CHECK_FOR_EXCEPTION();
1835 callFrame->uncheckedR(dst) = jsBoolean(result);
1837 vPC += OPCODE_LENGTH(op_stricteq);
1840 DEFINE_OPCODE(op_nstricteq) {
1841 /* nstricteq dst(r) src1(r) src2(r)
1843 Checks whether register src1 and register src2 are not
1844 strictly equal, as with the ECMAScript '!==' operator, and
1845 puts the result as a boolean in register dst.
1847 int dst = vPC[1].u.operand;
1848 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1849 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1850 bool result = !JSValue::strictEqual(callFrame, src1, src2);
1851 CHECK_FOR_EXCEPTION();
1852 callFrame->uncheckedR(dst) = jsBoolean(result);
1854 vPC += OPCODE_LENGTH(op_nstricteq);
1857 DEFINE_OPCODE(op_less) {
1858 /* less dst(r) src1(r) src2(r)
1860 Checks whether register src1 is less than register src2, as
1861 with the ECMAScript '<' operator, and puts the result as
1862 a boolean in register dst.
1864 int dst = vPC[1].u.operand;
1865 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1866 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1867 JSValue result = jsBoolean(jsLess<true>(callFrame, src1, src2));
1868 CHECK_FOR_EXCEPTION();
1869 callFrame->uncheckedR(dst) = result;
1871 vPC += OPCODE_LENGTH(op_less);
1874 DEFINE_OPCODE(op_lesseq) {
1875 /* lesseq dst(r) src1(r) src2(r)
1877 Checks whether register src1 is less than or equal to
1878 register src2, as with the ECMAScript '<=' operator, and
1879 puts the result as a boolean in register dst.
1881 int dst = vPC[1].u.operand;
1882 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1883 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1884 JSValue result = jsBoolean(jsLessEq<true>(callFrame, src1, src2));
1885 CHECK_FOR_EXCEPTION();
1886 callFrame->uncheckedR(dst) = result;
1888 vPC += OPCODE_LENGTH(op_lesseq);
1891 DEFINE_OPCODE(op_greater) {
1892 /* greater dst(r) src1(r) src2(r)
1894 Checks whether register src1 is greater than register src2, as
1895 with the ECMAScript '>' operator, and puts the result as
1896 a boolean in register dst.
1898 int dst = vPC[1].u.operand;
1899 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1900 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1901 JSValue result = jsBoolean(jsLess<false>(callFrame, src2, src1));
1902 CHECK_FOR_EXCEPTION();
1903 callFrame->uncheckedR(dst) = result;
1905 vPC += OPCODE_LENGTH(op_greater);
1908 DEFINE_OPCODE(op_greatereq) {
1909 /* greatereq dst(r) src1(r) src2(r)
1911 Checks whether register src1 is greater than or equal to
1912 register src2, as with the ECMAScript '>=' operator, and
1913 puts the result as a boolean in register dst.
1915 int dst = vPC[1].u.operand;
1916 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1917 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1918 JSValue result = jsBoolean(jsLessEq<false>(callFrame, src2, src1));
1919 CHECK_FOR_EXCEPTION();
1920 callFrame->uncheckedR(dst) = result;
1922 vPC += OPCODE_LENGTH(op_greatereq);
1925 DEFINE_OPCODE(op_pre_inc) {
1926 /* pre_inc srcDst(r)
1928 Converts register srcDst to number, adds one, and puts the result
1929 back in register srcDst.
1931 int srcDst = vPC[1].u.operand;
1932 JSValue v = callFrame->r(srcDst).jsValue();
1933 if (v.isInt32() && v.asInt32() < INT_MAX)
1934 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
1936 JSValue result = jsNumber(v.toNumber(callFrame) + 1);
1937 CHECK_FOR_EXCEPTION();
1938 callFrame->uncheckedR(srcDst) = result;
1941 vPC += OPCODE_LENGTH(op_pre_inc);
1944 DEFINE_OPCODE(op_pre_dec) {
1945 /* pre_dec srcDst(r)
1947 Converts register srcDst to number, subtracts one, and puts the result
1948 back in register srcDst.
1950 int srcDst = vPC[1].u.operand;
1951 JSValue v = callFrame->r(srcDst).jsValue();
1952 if (v.isInt32() && v.asInt32() > INT_MIN)
1953 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
1955 JSValue result = jsNumber(v.toNumber(callFrame) - 1);
1956 CHECK_FOR_EXCEPTION();
1957 callFrame->uncheckedR(srcDst) = result;
1960 vPC += OPCODE_LENGTH(op_pre_dec);
1963 DEFINE_OPCODE(op_post_inc) {
1964 /* post_inc dst(r) srcDst(r)
1966 Converts register srcDst to number. The number itself is
1967 written to register dst, and the number plus one is written
1968 back to register srcDst.
1970 int dst = vPC[1].u.operand;
1971 int srcDst = vPC[2].u.operand;
1972 JSValue v = callFrame->r(srcDst).jsValue();
1973 if (v.isInt32() && v.asInt32() < INT_MAX) {
1974 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
1975 callFrame->uncheckedR(dst) = v;
1977 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
1978 CHECK_FOR_EXCEPTION();
1979 callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() + 1);
1980 callFrame->uncheckedR(dst) = number;
1983 vPC += OPCODE_LENGTH(op_post_inc);
1986 DEFINE_OPCODE(op_post_dec) {
1987 /* post_dec dst(r) srcDst(r)
1989 Converts register srcDst to number. The number itself is
1990 written to register dst, and the number minus one is written
1991 back to register srcDst.
1993 int dst = vPC[1].u.operand;
1994 int srcDst = vPC[2].u.operand;
1995 JSValue v = callFrame->r(srcDst).jsValue();
1996 if (v.isInt32() && v.asInt32() > INT_MIN) {
1997 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
1998 callFrame->uncheckedR(dst) = v;
2000 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
2001 CHECK_FOR_EXCEPTION();
2002 callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() - 1);
2003 callFrame->uncheckedR(dst) = number;
2006 vPC += OPCODE_LENGTH(op_post_dec);
2009 DEFINE_OPCODE(op_to_jsnumber) {
2010 /* to_jsnumber dst(r) src(r)
2012 Converts register src to number, and puts the result
2015 int dst = vPC[1].u.operand;
2016 int src = vPC[2].u.operand;
2018 JSValue srcVal = callFrame->r(src).jsValue();
2020 if (LIKELY(srcVal.isNumber()))
2021 callFrame->uncheckedR(dst) = callFrame->r(src);
2023 JSValue result = srcVal.toJSNumber(callFrame);
2024 CHECK_FOR_EXCEPTION();
2025 callFrame->uncheckedR(dst) = result;
2028 vPC += OPCODE_LENGTH(op_to_jsnumber);
2031 DEFINE_OPCODE(op_negate) {
2032 /* negate dst(r) src(r)
2034 Converts register src to number, negates it, and puts the
2035 result in register dst.
2037 int dst = vPC[1].u.operand;
2038 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
2039 if (src.isInt32() && (src.asInt32() & 0x7fffffff)) // non-zero and no overflow
2040 callFrame->uncheckedR(dst) = jsNumber(-src.asInt32());
2042 JSValue result = jsNumber(-src.toNumber(callFrame));
2043 CHECK_FOR_EXCEPTION();
2044 callFrame->uncheckedR(dst) = result;
2047 vPC += OPCODE_LENGTH(op_negate);
2050 DEFINE_OPCODE(op_add) {
2051 /* add dst(r) src1(r) src2(r)
2053 Adds register src1 and register src2, and puts the result
2054 in register dst. (JS add may be string concatenation or
2055 numeric add, depending on the types of the operands.)
2057 int dst = vPC[1].u.operand;
2058 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2059 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2060 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
2061 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() + src2.asInt32());
2063 JSValue result = jsAdd(callFrame, src1, src2);
2064 CHECK_FOR_EXCEPTION();
2065 callFrame->uncheckedR(dst) = result;
2067 vPC += OPCODE_LENGTH(op_add);
2070 DEFINE_OPCODE(op_mul) {
2071 /* mul dst(r) src1(r) src2(r)
2073 Multiplies register src1 and register src2 (converted to
2074 numbers), and puts the product in register dst.
2076 int dst = vPC[1].u.operand;
2077 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2078 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2079 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
2080 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() * src2.asInt32());
2082 JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame));
2083 CHECK_FOR_EXCEPTION();
2084 callFrame->uncheckedR(dst) = result;
2087 vPC += OPCODE_LENGTH(op_mul);
2090 DEFINE_OPCODE(op_div) {
2091 /* div dst(r) dividend(r) divisor(r)
2093 Divides register dividend (converted to number) by the
2094 register divisor (converted to number), and puts the
2095 quotient in register dst.
2097 int dst = vPC[1].u.operand;
2098 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
2099 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
2101 JSValue result = jsNumber(dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
2102 CHECK_FOR_EXCEPTION();
2103 callFrame->uncheckedR(dst) = result;
2105 vPC += OPCODE_LENGTH(op_div);
2108 DEFINE_OPCODE(op_mod) {
2109 /* mod dst(r) dividend(r) divisor(r)
2111 Divides register dividend (converted to number) by
2112 register divisor (converted to number), and puts the
2113 remainder in register dst.
2115 int dst = vPC[1].u.operand;
2116 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
2117 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
2119 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
2120 JSValue result = jsNumber(dividend.asInt32() % divisor.asInt32());
2122 callFrame->uncheckedR(dst) = result;
2123 vPC += OPCODE_LENGTH(op_mod);
2127 // Conversion to double must happen outside the call to fmod since the
2128 // order of argument evaluation is not guaranteed.
2129 double d1 = dividend.toNumber(callFrame);
2130 double d2 = divisor.toNumber(callFrame);
2131 JSValue result = jsNumber(fmod(d1, d2));
2132 CHECK_FOR_EXCEPTION();
2133 callFrame->uncheckedR(dst) = result;
2134 vPC += OPCODE_LENGTH(op_mod);
2137 DEFINE_OPCODE(op_sub) {
2138 /* sub dst(r) src1(r) src2(r)
2140 Subtracts register src2 (converted to number) from register
2141 src1 (converted to number), and puts the difference in
2144 int dst = vPC[1].u.operand;
2145 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2146 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2147 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
2148 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() - src2.asInt32());
2150 JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame));
2151 CHECK_FOR_EXCEPTION();
2152 callFrame->uncheckedR(dst) = result;
2154 vPC += OPCODE_LENGTH(op_sub);
2157 DEFINE_OPCODE(op_lshift) {
2158 /* lshift dst(r) val(r) shift(r)
2160 Performs left shift of register val (converted to int32) by
2161 register shift (converted to uint32), and puts the result
2164 int dst = vPC[1].u.operand;
2165 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
2166 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
2168 if (val.isInt32() && shift.isInt32())
2169 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() << (shift.asInt32() & 0x1f));
2171 JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
2172 CHECK_FOR_EXCEPTION();
2173 callFrame->uncheckedR(dst) = result;
2176 vPC += OPCODE_LENGTH(op_lshift);
2179 DEFINE_OPCODE(op_rshift) {
2180 /* rshift dst(r) val(r) shift(r)
2182 Performs arithmetic right shift of register val (converted
2183 to int32) by register shift (converted to
2184 uint32), and puts the result in register dst.
2186 int dst = vPC[1].u.operand;
2187 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
2188 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
2190 if (val.isInt32() && shift.isInt32())
2191 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
2193 JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2194 CHECK_FOR_EXCEPTION();
2195 callFrame->uncheckedR(dst) = result;
2198 vPC += OPCODE_LENGTH(op_rshift);
2201 DEFINE_OPCODE(op_urshift) {
2202 /* rshift dst(r) val(r) shift(r)
2204 Performs logical right shift of register val (converted
2205 to uint32) by register shift (converted to
2206 uint32), and puts the result in register dst.
2208 int dst = vPC[1].u.operand;
2209 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
2210 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
2211 if (val.isUInt32() && shift.isInt32())
2212 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
2214 JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2215 CHECK_FOR_EXCEPTION();
2216 callFrame->uncheckedR(dst) = result;
2219 vPC += OPCODE_LENGTH(op_urshift);
2222 DEFINE_OPCODE(op_bitand) {
2223 /* bitand dst(r) src1(r) src2(r)
2225 Computes bitwise AND of register src1 (converted to int32)
2226 and register src2 (converted to int32), and puts the result
2229 int dst = vPC[1].u.operand;
2230 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2231 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2232 if (src1.isInt32() && src2.isInt32())
2233 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() & src2.asInt32());
2235 JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame));
2236 CHECK_FOR_EXCEPTION();
2237 callFrame->uncheckedR(dst) = result;
2240 vPC += OPCODE_LENGTH(op_bitand);
2243 DEFINE_OPCODE(op_bitxor) {
2244 /* bitxor dst(r) src1(r) src2(r)
2246 Computes bitwise XOR of register src1 (converted to int32)
2247 and register src2 (converted to int32), and puts the result
2250 int dst = vPC[1].u.operand;
2251 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2252 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2253 if (src1.isInt32() && src2.isInt32())
2254 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() ^ src2.asInt32());
2256 JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
2257 CHECK_FOR_EXCEPTION();
2258 callFrame->uncheckedR(dst) = result;
2261 vPC += OPCODE_LENGTH(op_bitxor);
2264 DEFINE_OPCODE(op_bitor) {
2265 /* bitor dst(r) src1(r) src2(r)
2267 Computes bitwise OR of register src1 (converted to int32)
2268 and register src2 (converted to int32), and puts the
2269 result in register dst.
2271 int dst = vPC[1].u.operand;
2272 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2273 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2274 if (src1.isInt32() && src2.isInt32())
2275 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() | src2.asInt32());
2277 JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));
2278 CHECK_FOR_EXCEPTION();
2279 callFrame->uncheckedR(dst) = result;
2282 vPC += OPCODE_LENGTH(op_bitor);
2285 DEFINE_OPCODE(op_bitnot) {
2286 /* bitnot dst(r) src(r)
2288 Computes bitwise NOT of register src1 (converted to int32),
2289 and puts the result in register dst.
2291 int dst = vPC[1].u.operand;
2292 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
2294 callFrame->uncheckedR(dst) = jsNumber(~src.asInt32());
2296 JSValue result = jsNumber(~src.toInt32(callFrame));
2297 CHECK_FOR_EXCEPTION();
2298 callFrame->uncheckedR(dst) = result;
2300 vPC += OPCODE_LENGTH(op_bitnot);
2303 DEFINE_OPCODE(op_not) {
2304 /* not dst(r) src(r)
2306 Computes logical NOT of register src (converted to
2307 boolean), and puts the result in register dst.
2309 int dst = vPC[1].u.operand;
2310 int src = vPC[2].u.operand;
2311 JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));
2312 CHECK_FOR_EXCEPTION();
2313 callFrame->uncheckedR(dst) = result;
2315 vPC += OPCODE_LENGTH(op_not);
2318 DEFINE_OPCODE(op_check_has_instance) {
2319 /* check_has_instance constructor(r)
2321 Check 'constructor' is an object with the internal property
2322 [HasInstance] (i.e. is a function ... *shakes head sadly at
2323 JSC API*). Raises an exception if register constructor is not
2324 an valid parameter for instanceof.
2326 int base = vPC[1].u.operand;
2327 JSValue baseVal = callFrame->r(base).jsValue();
2329 if (isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue))
2332 vPC += OPCODE_LENGTH(op_check_has_instance);
2335 DEFINE_OPCODE(op_instanceof) {
2336 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2338 Tests whether register value is an instance of register
2339 constructor, and puts the boolean result in register
2340 dst. Register constructorProto must contain the "prototype"
2341 property (not the actual prototype) of the object in
2342 register constructor. This lookup is separated so that
2343 polymorphic inline caching can apply.
2345 Raises an exception if register constructor is not an
2348 int dst = vPC[1].u.operand;
2349 int value = vPC[2].u.operand;
2350 int base = vPC[3].u.operand;
2351 int baseProto = vPC[4].u.operand;
2353 JSValue baseVal = callFrame->r(base).jsValue();
2355 ASSERT(!isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue));
2357 bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
2358 CHECK_FOR_EXCEPTION();
2359 callFrame->uncheckedR(dst) = jsBoolean(result);
2361 vPC += OPCODE_LENGTH(op_instanceof);
2364 DEFINE_OPCODE(op_typeof) {
2365 /* typeof dst(r) src(r)
2367 Determines the type string for src according to ECMAScript
2368 rules, and puts the result in register dst.
2370 int dst = vPC[1].u.operand;
2371 int src = vPC[2].u.operand;
2372 callFrame->uncheckedR(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
2374 vPC += OPCODE_LENGTH(op_typeof);
2377 DEFINE_OPCODE(op_is_undefined) {
2378 /* is_undefined dst(r) src(r)
2380 Determines whether the type string for src according to
2381 the ECMAScript rules is "undefined", and puts the result
2384 int dst = vPC[1].u.operand;
2385 int src = vPC[2].u.operand;
2386 JSValue v = callFrame->r(src).jsValue();
2387 callFrame->uncheckedR(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
2389 vPC += OPCODE_LENGTH(op_is_undefined);
2392 DEFINE_OPCODE(op_is_boolean) {
2393 /* is_boolean dst(r) src(r)
2395 Determines whether the type string for src according to
2396 the ECMAScript rules is "boolean", and puts the result
2399 int dst = vPC[1].u.operand;
2400 int src = vPC[2].u.operand;
2401 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
2403 vPC += OPCODE_LENGTH(op_is_boolean);
2406 DEFINE_OPCODE(op_is_number) {
2407 /* is_number dst(r) src(r)
2409 Determines whether the type string for src according to
2410 the ECMAScript rules is "number", and puts the result
2413 int dst = vPC[1].u.operand;
2414 int src = vPC[2].u.operand;
2415 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
2417 vPC += OPCODE_LENGTH(op_is_number);
2420 DEFINE_OPCODE(op_is_string) {
2421 /* is_string dst(r) src(r)
2423 Determines whether the type string for src according to
2424 the ECMAScript rules is "string", and puts the result
2427 int dst = vPC[1].u.operand;
2428 int src = vPC[2].u.operand;
2429 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
2431 vPC += OPCODE_LENGTH(op_is_string);
2434 DEFINE_OPCODE(op_is_object) {
2435 /* is_object dst(r) src(r)
2437 Determines whether the type string for src according to
2438 the ECMAScript rules is "object", and puts the result
2441 int dst = vPC[1].u.operand;
2442 int src = vPC[2].u.operand;
2443 callFrame->uncheckedR(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
2445 vPC += OPCODE_LENGTH(op_is_object);
2448 DEFINE_OPCODE(op_is_function) {
2449 /* is_function dst(r) src(r)
2451 Determines whether the type string for src according to
2452 the ECMAScript rules is "function", and puts the result
2455 int dst = vPC[1].u.operand;
2456 int src = vPC[2].u.operand;
2457 callFrame->uncheckedR(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
2459 vPC += OPCODE_LENGTH(op_is_function);
2462 DEFINE_OPCODE(op_in) {
2463 /* in dst(r) property(r) base(r)
2465 Tests whether register base has a property named register
2466 property, and puts the boolean result in register dst.
2468 Raises an exception if register constructor is not an
2471 int dst = vPC[1].u.operand;
2472 int property = vPC[2].u.operand;
2473 int base = vPC[3].u.operand;
2475 JSValue baseVal = callFrame->r(base).jsValue();
2476 if (isInvalidParamForIn(callFrame, baseVal, exceptionValue))
2479 JSObject* baseObj = asObject(baseVal);
2481 JSValue propName = callFrame->r(property).jsValue();
2484 if (propName.getUInt32(i))
2485 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
2487 Identifier property(callFrame, propName.toString(callFrame));
2488 CHECK_FOR_EXCEPTION();
2489 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
2492 vPC += OPCODE_LENGTH(op_in);
2495 DEFINE_OPCODE(op_resolve) {
2496 /* resolve dst(r) property(id)
2498 Looks up the property named by identifier property in the
2499 scope chain, and writes the resulting value to register
2500 dst. If the property is not found, raises an exception.
2502 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
2505 vPC += OPCODE_LENGTH(op_resolve);
2508 DEFINE_OPCODE(op_resolve_skip) {
2509 /* resolve_skip dst(r) property(id) skip(n)
2511 Looks up the property named by identifier property in the
2512 scope chain skipping the top 'skip' levels, and writes the resulting
2513 value to register dst. If the property is not found, raises an exception.
2515 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
2518 vPC += OPCODE_LENGTH(op_resolve_skip);
2522 DEFINE_OPCODE(op_resolve_global) {
2523 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
2525 Performs a dynamic property lookup for the given property, on the provided
2526 global object. If structure matches the Structure of the global then perform
2527 a fast lookup using the case offset, otherwise fall back to a full resolve and
2528 cache the new structure and offset
2530 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
2533 vPC += OPCODE_LENGTH(op_resolve_global);
2537 DEFINE_OPCODE(op_resolve_global_dynamic) {
2538 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n), depth(n)
2540 Performs a dynamic property lookup for the given property, on the provided
2541 global object. If structure matches the Structure of the global then perform
2542 a fast lookup using the case offset, otherwise fall back to a full resolve and
2543 cache the new structure and offset.
2545 This walks through n levels of the scope chain to verify that none of those levels
2546 in the scope chain include dynamically added properties.
2548 if (UNLIKELY(!resolveGlobalDynamic(callFrame, vPC, exceptionValue)))
2551 vPC += OPCODE_LENGTH(op_resolve_global_dynamic);
2555 DEFINE_OPCODE(op_get_global_var) {
2556 /* get_global_var dst(r) globalObject(c) index(n)
2558 Gets the global var at global slot index and places it in register dst.
2560 int dst = vPC[1].u.operand;
2561 JSGlobalObject* scope = codeBlock->globalObject();
2562 ASSERT(scope->isGlobalObject());
2563 int index = vPC[2].u.operand;
2565 callFrame->uncheckedR(dst) = scope->registerAt(index).get();
2566 vPC += OPCODE_LENGTH(op_get_global_var);
2569 DEFINE_OPCODE(op_put_global_var) {
2570 /* put_global_var globalObject(c) index(n) value(r)
2572 Puts value into global slot index.
2574 JSGlobalObject* scope = codeBlock->globalObject();
2575 ASSERT(scope->isGlobalObject());
2576 int index = vPC[1].u.operand;
2577 int value = vPC[2].u.operand;
2579 scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
2580 vPC += OPCODE_LENGTH(op_put_global_var);
2583 DEFINE_OPCODE(op_get_scoped_var) {
2584 /* get_scoped_var dst(r) index(n) skip(n)
2586 Loads the contents of the index-th local from the scope skip nodes from
2587 the top of the scope chain, and places it in register dst.
2589 int dst = vPC[1].u.operand;
2590 int index = vPC[2].u.operand;
2591 int skip = vPC[3].u.operand;
2593 ScopeChainNode* scopeChain = callFrame->scopeChain();
2594 ScopeChainIterator iter = scopeChain->begin();
2595 ScopeChainIterator end = scopeChain->end();
2596 ASSERT(iter != end);
2597 ASSERT(codeBlock == callFrame->codeBlock());
2598 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
2599 ASSERT(skip || !checkTopLevel);
2600 if (checkTopLevel && skip--) {
2601 if (callFrame->r(codeBlock->activationRegister()).jsValue())
2606 ASSERT(iter != end);
2608 ASSERT((*iter)->isVariableObject());
2609 JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
2610 callFrame->uncheckedR(dst) = scope->registerAt(index).get();
2611 ASSERT(callFrame->r(dst).jsValue());
2612 vPC += OPCODE_LENGTH(op_get_scoped_var);
2615 DEFINE_OPCODE(op_put_scoped_var) {
2616 /* put_scoped_var index(n) skip(n) value(r)
2619 int index = vPC[1].u.operand;
2620 int skip = vPC[2].u.operand;
2621 int value = vPC[3].u.operand;
2623 ScopeChainNode* scopeChain = callFrame->scopeChain();
2624 ScopeChainIterator iter = scopeChain->begin();
2625 ScopeChainIterator end = scopeChain->end();
2626 ASSERT(codeBlock == callFrame->codeBlock());
2627 ASSERT(iter != end);
2628 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
2629 ASSERT(skip || !checkTopLevel);
2630 if (checkTopLevel && skip--) {
2631 if (callFrame->r(codeBlock->activationRegister()).jsValue())
2636 ASSERT(iter != end);
2639 ASSERT((*iter)->isVariableObject());
2640 JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
2641 ASSERT(callFrame->r(value).jsValue());
2642 scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
2643 vPC += OPCODE_LENGTH(op_put_scoped_var);
2646 DEFINE_OPCODE(op_resolve_base) {
2647 /* resolve_base dst(r) property(id) isStrict(bool)
2649 Searches the scope chain for an object containing
2650 identifier property, and if one is found, writes it to
2651 register dst. If none is found and isStrict is false, the
2652 outermost scope (which will be the global object) is
2653 stored in register dst.
2655 resolveBase(callFrame, vPC);
2656 CHECK_FOR_EXCEPTION();
2658 vPC += OPCODE_LENGTH(op_resolve_base);
2661 DEFINE_OPCODE(op_ensure_property_exists) {
2662 /* ensure_property_exists base(r) property(id)
2664 Throws an exception if property does not exist on base
2666 int base = vPC[1].u.operand;
2667 int property = vPC[2].u.operand;
2668 Identifier& ident = codeBlock->identifier(property);
2670 JSValue baseVal = callFrame->r(base).jsValue();
2671 JSObject* baseObject = asObject(baseVal);
2672 PropertySlot slot(baseVal);
2673 if (!baseObject->getPropertySlot(callFrame, ident, slot)) {
2674 exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
2678 vPC += OPCODE_LENGTH(op_ensure_property_exists);
2681 DEFINE_OPCODE(op_resolve_with_base) {
2682 /* resolve_with_base baseDst(r) propDst(r) property(id)
2684 Searches the scope chain for an object containing
2685 identifier property, and if one is found, writes it to
2686 register srcDst, and the retrieved property value to register
2687 propDst. If the property is not found, raises an exception.
2689 This is more efficient than doing resolve_base followed by
2690 resolve, or resolve_base followed by get_by_id, as it
2691 avoids duplicate hash lookups.
2693 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
2696 vPC += OPCODE_LENGTH(op_resolve_with_base);
2699 DEFINE_OPCODE(op_resolve_with_this) {
2700 /* resolve_with_this thisDst(r) propDst(r) property(id)
2702 Searches the scope chain for an object containing
2703 identifier property, and if one is found, writes the
2704 retrieved property value to register propDst, and the
2705 this object to pass in a call to thisDst.
2707 If the property is not found, raises an exception.
2709 if (UNLIKELY(!resolveThisAndProperty(callFrame, vPC, exceptionValue)))
2712 vPC += OPCODE_LENGTH(op_resolve_with_this);
2715 DEFINE_OPCODE(op_get_by_id) {
2716 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2718 Generic property access: Gets the property named by identifier
2719 property from the value base, and puts the result in register dst.
2721 int dst = vPC[1].u.operand;
2722 int base = vPC[2].u.operand;
2723 int property = vPC[3].u.operand;
2725 Identifier& ident = codeBlock->identifier(property);
2726 JSValue baseValue = callFrame->r(base).jsValue();
2727 PropertySlot slot(baseValue);
2728 JSValue result = baseValue.get(callFrame, ident, slot);
2729 CHECK_FOR_EXCEPTION();
2731 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
2733 callFrame->uncheckedR(dst) = result;
2734 vPC += OPCODE_LENGTH(op_get_by_id);
2737 DEFINE_OPCODE(op_get_by_id_self) {
2738 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2740 Cached property access: Attempts to get a cached property from the
2741 value base. If the cache misses, op_get_by_id_self reverts to
2744 int base = vPC[2].u.operand;
2745 JSValue baseValue = callFrame->r(base).jsValue();
2747 if (LIKELY(baseValue.isCell())) {
2748 JSCell* baseCell = baseValue.asCell();
2749 Structure* structure = vPC[4].u.structure.get();
2751 if (LIKELY(baseCell->structure() == structure)) {
2752 ASSERT(baseCell->isObject());
2753 JSObject* baseObject = asObject(baseCell);
2754 int dst = vPC[1].u.operand;
2755 int offset = vPC[5].u.operand;
2757 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2758 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
2760 vPC += OPCODE_LENGTH(op_get_by_id_self);
2765 uncacheGetByID(codeBlock, vPC);
2768 DEFINE_OPCODE(op_get_by_id_proto) {
2769 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2771 Cached property access: Attempts to get a cached property from the
2772 value base's prototype. If the cache misses, op_get_by_id_proto
2773 reverts to op_get_by_id.
2775 int base = vPC[2].u.operand;
2776 JSValue baseValue = callFrame->r(base).jsValue();
2778 if (LIKELY(baseValue.isCell())) {
2779 JSCell* baseCell = baseValue.asCell();
2780 Structure* structure = vPC[4].u.structure.get();
2782 if (LIKELY(baseCell->structure() == structure)) {
2783 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2784 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2785 Structure* prototypeStructure = vPC[5].u.structure.get();
2787 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2788 int dst = vPC[1].u.operand;
2789 int offset = vPC[6].u.operand;
2791 ASSERT(protoObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2792 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2793 callFrame->uncheckedR(dst) = JSValue(protoObject->getDirectOffset(offset));
2795 vPC += OPCODE_LENGTH(op_get_by_id_proto);
2801 uncacheGetByID(codeBlock, vPC);
2804 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2805 goto *(&&skip_id_getter_proto);
2807 DEFINE_OPCODE(op_get_by_id_getter_proto) {
2808 /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2810 Cached property access: Attempts to get a cached getter property from the
2811 value base's prototype. If the cache misses, op_get_by_id_getter_proto
2812 reverts to op_get_by_id.
2814 int base = vPC[2].u.operand;
2815 JSValue baseValue = callFrame->r(base).jsValue();
2817 if (LIKELY(baseValue.isCell())) {
2818 JSCell* baseCell = baseValue.asCell();
2819 Structure* structure = vPC[4].u.structure.get();
2821 if (LIKELY(baseCell->structure() == structure)) {
2822 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2823 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2824 Structure* prototypeStructure = vPC[5].u.structure.get();
2826 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2827 int dst = vPC[1].u.operand;
2828 int offset = vPC[6].u.operand;
2829 if (GetterSetter* getterSetter = asGetterSetter(protoObject->getDirectOffset(offset).asCell())) {
2830 JSObject* getter = getterSetter->getter();
2832 CallType callType = getter->getCallData(callData);
2833 JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
2834 CHECK_FOR_EXCEPTION();
2835 callFrame->uncheckedR(dst) = result;
2837 callFrame->uncheckedR(dst) = jsUndefined();
2838 vPC += OPCODE_LENGTH(op_get_by_id_getter_proto);
2843 uncacheGetByID(codeBlock, vPC);
2846 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2847 skip_id_getter_proto:
2849 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2850 goto *(&&skip_id_custom_proto);
2852 DEFINE_OPCODE(op_get_by_id_custom_proto) {
2853 /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2855 Cached property access: Attempts to use a cached named property getter
2856 from the value base's prototype. If the cache misses, op_get_by_id_custom_proto
2857 reverts to op_get_by_id.
2859 int base = vPC[2].u.operand;
2860 JSValue baseValue = callFrame->r(base).jsValue();
2862 if (LIKELY(baseValue.isCell())) {
2863 JSCell* baseCell = baseValue.asCell();
2864 Structure* structure = vPC[4].u.structure.get();
2866 if (LIKELY(baseCell->structure() == structure)) {
2867 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2868 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2869 Structure* prototypeStructure = vPC[5].u.structure.get();
2871 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2872 int dst = vPC[1].u.operand;
2873 int property = vPC[3].u.operand;
2874 Identifier& ident = codeBlock->identifier(property);
2876 PropertySlot::GetValueFunc getter = vPC[6].u.getterFunc;
2877 JSValue result = getter(callFrame, protoObject, ident);
2878 CHECK_FOR_EXCEPTION();
2879 callFrame->uncheckedR(dst) = result;
2880 vPC += OPCODE_LENGTH(op_get_by_id_custom_proto);
2885 uncacheGetByID(codeBlock, vPC);
2888 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2889 skip_id_custom_proto:
2891 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2892 goto *(&&skip_get_by_id_chain);
2894 DEFINE_OPCODE(op_get_by_id_chain) {
2895 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2897 Cached property access: Attempts to get a cached property from the
2898 value base's prototype chain. If the cache misses, op_get_by_id_chain
2899 reverts to op_get_by_id.
2901 int base = vPC[2].u.operand;
2902 JSValue baseValue = callFrame->r(base).jsValue();
2904 if (LIKELY(baseValue.isCell())) {
2905 JSCell* baseCell = baseValue.asCell();
2906 Structure* structure = vPC[4].u.structure.get();
2908 if (LIKELY(baseCell->structure() == structure)) {
2909 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
2910 size_t count = vPC[6].u.operand;
2911 WriteBarrier<Structure>* end = it + count;
2914 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
2916 if (UNLIKELY(baseObject->structure() != (*it).get()))
2920 int dst = vPC[1].u.operand;
2921 int offset = vPC[7].u.operand;
2923 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2924 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2925 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
2927 vPC += OPCODE_LENGTH(op_get_by_id_chain);
2931 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2932 baseCell = baseObject;
2937 uncacheGetByID(codeBlock, vPC);
2940 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2941 skip_get_by_id_chain:
2942 goto *(&&skip_id_getter_self);
2944 DEFINE_OPCODE(op_get_by_id_getter_self) {
2945 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2947 Cached property access: Attempts to get a cached property from the
2948 value base. If the cache misses, op_get_by_id_getter_self reverts to
2951 int base = vPC[2].u.operand;
2952 JSValue baseValue = callFrame->r(base).jsValue();
2954 if (LIKELY(baseValue.isCell())) {
2955 JSCell* baseCell = baseValue.asCell();
2956 Structure* structure = vPC[4].u.structure.get();
2958 if (LIKELY(baseCell->structure() == structure)) {
2959 ASSERT(baseCell->isObject());
2960 JSObject* baseObject = asObject(baseCell);
2961 int dst = vPC[1].u.operand;
2962 int offset = vPC[5].u.operand;
2964 if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
2965 JSObject* getter = getterSetter->getter();
2967 CallType callType = getter->getCallData(callData);
2968 JSValue result = call(callFrame, getter, callType, callData, baseObject, ArgList());
2969 CHECK_FOR_EXCEPTION();
2970 callFrame->uncheckedR(dst) = result;
2972 callFrame->uncheckedR(dst) = jsUndefined();
2974 vPC += OPCODE_LENGTH(op_get_by_id_getter_self);
2978 uncacheGetByID(codeBlock, vPC);
2981 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2982 skip_id_getter_self:
2984 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2985 goto *(&&skip_id_custom_self);
2987 DEFINE_OPCODE(op_get_by_id_custom_self) {
2988 /* op_get_by_id_custom_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2990 Cached property access: Attempts to use a cached named property getter
2991 from the value base. If the cache misses, op_get_by_id_custom_self reverts to
2994 int base = vPC[2].u.operand;
2995 JSValue baseValue = callFrame->r(base).jsValue();
2997 if (LIKELY(baseValue.isCell())) {
2998 JSCell* baseCell = baseValue.asCell();
2999 Structure* structure = vPC[4].u.structure.get();
3001 if (LIKELY(baseCell->structure() == structure)) {
3002 ASSERT(baseCell->isObject());
3003 int dst = vPC[1].u.operand;
3004 int property = vPC[3].u.operand;
3005 Identifier& ident = codeBlock->identifier(property);
3007 PropertySlot::GetValueFunc getter = vPC[5].u.getterFunc;
3008 JSValue result = getter(callFrame, baseValue, ident);
3009 CHECK_FOR_EXCEPTION();
3010 callFrame->uncheckedR(dst) = result;
3011 vPC += OPCODE_LENGTH(op_get_by_id_custom_self);
3015 uncacheGetByID(codeBlock, vPC);
3018 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3019 skip_id_custom_self:
3021 DEFINE_OPCODE(op_get_by_id_generic) {
3022 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3024 Generic property access: Gets the property named by identifier
3025 property from the value base, and puts the result in register dst.
3027 int dst = vPC[1].u.operand;
3028 int base = vPC[2].u.operand;
3029 int property = vPC[3].u.operand;
3031 Identifier& ident = codeBlock->identifier(property);
3032 JSValue baseValue = callFrame->r(base).jsValue();
3033 PropertySlot slot(baseValue);
3034 JSValue result = baseValue.get(callFrame, ident, slot);
3035 CHECK_FOR_EXCEPTION();
3037 callFrame->uncheckedR(dst) = result;
3038 vPC += OPCODE_LENGTH(op_get_by_id_generic);
3041 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3042 goto *(&&skip_id_getter_chain);
3044 DEFINE_OPCODE(op_get_by_id_getter_chain) {
3045 /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
3047 Cached property access: Attempts to get a cached property from the
3048 value base's prototype chain. If the cache misses, op_get_by_id_getter_chain
3049 reverts to op_get_by_id.
3051 int base = vPC[2].u.operand;
3052 JSValue baseValue = callFrame->r(base).jsValue();
3054 if (LIKELY(baseValue.isCell())) {
3055 JSCell* baseCell = baseValue.asCell();
3056 Structure* structure = vPC[4].u.structure.get();
3058 if (LIKELY(baseCell->structure() == structure)) {
3059 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
3060 size_t count = vPC[6].u.operand;
3061 WriteBarrier<Structure>* end = it + count;
3064 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
3066 if (UNLIKELY(baseObject->structure() != (*it).get()))
3070 int dst = vPC[1].u.operand;
3071 int offset = vPC[7].u.operand;
3072 if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
3073 JSObject* getter = getterSetter->getter();
3075 CallType callType = getter->getCallData(callData);
3076 JSValue result = call(callFrame, getter, callType, callData, baseValue, ArgList());
3077 CHECK_FOR_EXCEPTION();
3078 callFrame->uncheckedR(dst) = result;
3080 callFrame->uncheckedR(dst) = jsUndefined();
3081 vPC += OPCODE_LENGTH(op_get_by_id_getter_chain);
3085 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
3086 baseCell = baseObject;
3090 uncacheGetByID(codeBlock, vPC);
3093 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3094 skip_id_getter_chain:
3096 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3097 goto *(&&skip_id_custom_chain);
3099 DEFINE_OPCODE(op_get_by_id_custom_chain) {
3100 /* op_get_by_id_custom_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
3102 Cached property access: Attempts to use a cached named property getter on the
3103 value base's prototype chain. If the cache misses, op_get_by_id_custom_chain
3104 reverts to op_get_by_id.
3106 int base = vPC[2].u.operand;
3107 JSValue baseValue = callFrame->r(base).jsValue();
3109 if (LIKELY(baseValue.isCell())) {
3110 JSCell* baseCell = baseValue.asCell();
3111 Structure* structure = vPC[4].u.structure.get();
3113 if (LIKELY(baseCell->structure() == structure)) {
3114 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
3115 size_t count = vPC[6].u.operand;
3116 WriteBarrier<Structure>* end = it + count;
3119 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
3121 if (UNLIKELY(baseObject->structure() != (*it).get()))
3125 int dst = vPC[1].u.operand;
3126 int property = vPC[3].u.operand;
3127 Identifier& ident = codeBlock->identifier(property);
3129 PropertySlot::GetValueFunc getter = vPC[7].u.getterFunc;
3130 JSValue result = getter(callFrame, baseObject, ident);
3131 CHECK_FOR_EXCEPTION();
3132 callFrame->uncheckedR(dst) = result;
3133 vPC += OPCODE_LENGTH(op_get_by_id_custom_chain);
3137 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
3138 baseCell = baseObject;
3142 uncacheGetByID(codeBlock, vPC);
3145 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3146 skip_id_custom_chain:
3147 goto *(&&skip_get_array_length);
3149 DEFINE_OPCODE(op_get_array_length) {
3150 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3152 Cached property access: Gets the length of the array in register base,
3153 and puts the result in register dst. If register base does not hold
3154 an array, op_get_array_length reverts to op_get_by_id.
3157 int base = vPC[2].u.operand;
3158 JSValue baseValue = callFrame->r(base).jsValue();
3159 if (LIKELY(isJSArray(globalData, baseValue))) {
3160 int dst = vPC[1].u.operand;
3161 callFrame->uncheckedR(dst) = jsNumber(asArray(baseValue)->length());
3162 vPC += OPCODE_LENGTH(op_get_array_length);
3166 uncacheGetByID(codeBlock, vPC);
3169 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3170 skip_get_array_length:
3171 goto *(&&skip_get_string_length);
3173 DEFINE_OPCODE(op_get_string_length) {
3174 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3176 Cached property access: Gets the length of the string in register base,
3177 and puts the result in register dst. If register base does not hold
3178 a string, op_get_string_length reverts to op_get_by_id.
3181 int base = vPC[2].u.operand;
3182 JSValue baseValue = callFrame->r(base).jsValue();
3183 if (LIKELY(isJSString(globalData, baseValue))) {
3184 int dst = vPC[1].u.operand;
3185 callFrame->uncheckedR(dst) = jsNumber(asString(baseValue)->length());
3186 vPC += OPCODE_LENGTH(op_get_string_length);
3190 uncacheGetByID(codeBlock, vPC);
3193 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3194 skip_get_string_length:
3195 goto *(&&skip_put_by_id);
3197 DEFINE_OPCODE(op_put_by_id) {
3198 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
3200 Generic property access: Sets the property named by identifier
3201 property, belonging to register base, to register value.
3203 Unlike many opcodes, this one does not write any output to
3206 The "direct" flag should only be set this put_by_id is to initialize
3210 int base = vPC[1].u.operand;
3211 int property = vPC[2].u.operand;
3212 int value = vPC[3].u.operand;
3213 int direct = vPC[8].u.operand;
3215 JSValue baseValue = callFrame->r(base).jsValue();
3216 Identifier& ident = codeBlock->identifier(property);
3217 PutPropertySlot slot(codeBlock->isStrictMode());
3219 baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
3220 ASSERT(slot.base() == baseValue);
3222 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
3223 CHECK_FOR_EXCEPTION();
3225 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
3227 vPC += OPCODE_LENGTH(op_put_by_id);
3230 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3233 DEFINE_OPCODE(op_put_by_id_transition) {
3234 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b)
3236 Cached property access: Attempts to set a new property with a cached transition
3237 property named by identifier property, belonging to register base,
3238 to register value. If the cache misses, op_put_by_id_transition
3239 reverts to op_put_by_id_generic.
3241 Unlike many opcodes, this one does not write any output to
3244 int base = vPC[1].u.operand;
3245 JSValue baseValue = callFrame->r(base).jsValue();
3247 if (LIKELY(baseValue.isCell())) {
3248 JSCell* baseCell = baseValue.asCell();
3249 Structure* oldStructure = vPC[4].u.structure.get();
3250 Structure* newStructure = vPC[5].u.structure.get();
3252 if (LIKELY(baseCell->structure() == oldStructure)) {
3253 ASSERT(baseCell->isObject());
3254 JSObject* baseObject = asObject(baseCell);
3255 int direct = vPC[8].u.operand;
3258 WriteBarrier<Structure>* it = vPC[6].u.structureChain->head();
3260 JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);
3261 while (!proto.isNull()) {
3262 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
3263 uncachePutByID(codeBlock, vPC);
3267 proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
3270 baseObject->transitionTo(*globalData, newStructure);
3272 int value = vPC[3].u.operand;
3273 unsigned offset = vPC[7].u.operand;
3274 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
3275 baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
3277 vPC += OPCODE_LENGTH(op_put_by_id_transition);
3282 uncachePutByID(codeBlock, vPC);
3285 DEFINE_OPCODE(op_put_by_id_replace) {
3286 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n) direct(b)
3288 Cached property access: Attempts to set a pre-existing, cached
3289 property named by identifier property, belonging to register base,
3290 to register value. If the cache misses, op_put_by_id_replace
3291 reverts to op_put_by_id.
3293 Unlike many opcodes, this one does not write any output to
3296 int base = vPC[1].u.operand;
3297 JSValue baseValue = callFrame->r(base).jsValue();
3299 if (LIKELY(baseValue.isCell())) {
3300 JSCell* baseCell = baseValue.asCell();
3301 Structure* structure = vPC[4].u.structure.get();
3303 if (LIKELY(baseCell->structure() == structure)) {
3304 ASSERT(baseCell->isObject());
3305 JSObject* baseObject = asObject(baseCell);
3306 int value = vPC[3].u.operand;
3307 unsigned offset = vPC[5].u.operand;
3309 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
3310 baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
3312 vPC += OPCODE_LENGTH(op_put_by_id_replace);
3317 uncachePutByID(codeBlock, vPC);
3320 DEFINE_OPCODE(op_put_by_id_generic) {
3321 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
3323 Generic property access: Sets the property named by identifier
3324 property, belonging to register base, to register value.
3326 Unlike many opcodes, this one does not write any output to
3329 int base = vPC[1].u.operand;
3330 int property = vPC[2].u.operand;
3331 int value = vPC[3].u.operand;
3332 int direct = vPC[8].u.operand;
3334 JSValue baseValue = callFrame->r(base).jsValue();
3335 Identifier& ident = codeBlock->identifier(property);
3336 PutPropertySlot slot(codeBlock->isStrictMode());
3338 baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
3339 ASSERT(slot.base() == baseValue);
3341 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
3342 CHECK_FOR_EXCEPTION();
3344 vPC += OPCODE_LENGTH(op_put_by_id_generic);
3347 DEFINE_OPCODE(op_del_by_id) {
3348 /* del_by_id dst(r) base(r) property(id)
3350 Converts register base to Object, deletes the property
3351 named by identifier property from the object, and writes a
3352 boolean indicating success (if true) or failure (if false)
3355 int dst = vPC[1].u.operand;
3356 int base = vPC[2].u.operand;
3357 int property = vPC[3].u.operand;
3359 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);
3360 Identifier& ident = codeBlock->identifier(property);
3361 bool result = baseObj->deleteProperty(callFrame, ident);
3362 if (!result && codeBlock->isStrictMode()) {
3363 exceptionValue = createTypeError(callFrame, "Unable to delete property.");
3366 CHECK_FOR_EXCEPTION();
3367 callFrame->uncheckedR(dst) = jsBoolean(result);
3368 vPC += OPCODE_LENGTH(op_del_by_id);
3371 DEFINE_OPCODE(op_get_by_pname) {
3372 int dst = vPC[1].u.operand;
3373 int base = vPC[2].u.operand;
3374 int property = vPC[3].u.operand;
3375 int expected = vPC[4].u.operand;
3376 int iter = vPC[5].u.operand;
3377 int i = vPC[6].u.operand;
3379 JSValue baseValue = callFrame->r(base).jsValue();
3380 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
3381 JSValue subscript = callFrame->r(property).jsValue();
3382 JSValue expectedSubscript = callFrame->r(expected).jsValue();
3383 int index = callFrame->r(i).i() - 1;
3386 if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {
3387 callFrame->uncheckedR(dst) = JSValue(asObject(baseValue)->getDirectOffset(offset));
3388 vPC += OPCODE_LENGTH(op_get_by_pname);
3392 Identifier propertyName(callFrame, subscript.toString(callFrame));
3393 result = baseValue.get(callFrame, propertyName);
3395 CHECK_FOR_EXCEPTION();
3396 callFrame->uncheckedR(dst) = result;
3397 vPC += OPCODE_LENGTH(op_get_by_pname);
3400 DEFINE_OPCODE(op_get_arguments_length) {
3401 int dst = vPC[1].u.operand;
3402 int argumentsRegister = vPC[2].u.operand;
3403 int property = vPC[3].u.operand;
3404 JSValue arguments = callFrame->r(argumentsRegister).jsValue();
3406 Identifier& ident = codeBlock->identifier(property);
3407 PropertySlot slot(arguments);
3408 JSValue result = arguments.get(callFrame, ident, slot);
3409 CHECK_FOR_EXCEPTION();
3410 callFrame->uncheckedR(dst) = result;
3412 callFrame->uncheckedR(dst) = jsNumber(callFrame->argumentCount());
3414 vPC += OPCODE_LENGTH(op_get_arguments_length);
3417 DEFINE_OPCODE(op_get_argument_by_val) {
3418 int dst = vPC[1].u.operand;
3419 int argumentsRegister = vPC[2].u.operand;
3420 int property = vPC[3].u.operand;
3421 JSValue arguments = callFrame->r(argumentsRegister).jsValue();
3422 JSValue subscript = callFrame->r(property).jsValue();
3423 if (!arguments && subscript.isUInt32() && subscript.asUInt32() < callFrame->argumentCount()) {
3424 unsigned arg = subscript.asUInt32() + 1;
3425 unsigned numParameters = callFrame->codeBlock()->m_numParameters;
3426 if (arg < numParameters)
3427 callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters);
3429 callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters - callFrame->argumentCount() - 1);
3430 vPC += OPCODE_LENGTH(op_get_argument_by_val);
3434 Arguments* arguments = Arguments::create(*globalData, callFrame);
3435 callFrame->uncheckedR(argumentsRegister) = JSValue(arguments);
3436 callFrame->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister)) = JSValue(arguments);
3440 DEFINE_OPCODE(op_get_by_val) {
3441 /* get_by_val dst(r) base(r) property(r)
3443 Converts register base to Object, gets the property named
3444 by register property from the object, and puts the result
3445 in register dst. property is nominally converted to string
3446 but numbers are treated more efficiently.
3448 int dst = vPC[1].u.operand;
3449 int base = vPC[2].u.operand;
3450 int property = vPC[3].u.operand;
3452 JSValue baseValue = callFrame->r(base).jsValue();
3453 JSValue subscript = callFrame->r(property).jsValue();
3457 if (LIKELY(subscript.isUInt32())) {
3458 uint32_t i = subscript.asUInt32();
3459 if (isJSArray(globalData, baseValue)) {
3460 JSArray* jsArray = asArray(baseValue);
3461 if (jsArray->canGetIndex(i))
3462 result = jsArray->getIndex(i);
3464 result = jsArray->JSArray::get(callFrame, i);
3465 } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
3466 result = asString(baseValue)->getIndex(callFrame, i);
3467 else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i))
3468 result = asByteArray(baseValue)->getIndex(callFrame, i);
3470 result = baseValue.get(callFrame, i);
3472 Identifier property(callFrame, subscript.toString(callFrame));
3473 result = baseValue.get(callFrame, property);
3476 CHECK_FOR_EXCEPTION();
3477 callFrame->uncheckedR(dst) = result;
3478 vPC += OPCODE_LENGTH(op_get_by_val);
3481 DEFINE_OPCODE(op_put_by_val) {
3482 /* put_by_val base(r) property(r) value(r)
3484 Sets register value on register base as the property named
3485 by register property. Base is converted to object
3486 first. register property is nominally converted to string
3487 but numbers are treated more efficiently.
3489 Unlike many opcodes, this one does not write any output to
3492 int base = vPC[1].u.operand;
3493 int property = vPC[2].u.operand;
3494 int value = vPC[3].u.operand;
3496 JSValue baseValue = callFrame->r(base).jsValue();
3497 JSValue subscript = callFrame->r(property).jsValue();
3499 if (LIKELY(subscript.isUInt32())) {
3500 uint32_t i = subscript.asUInt32();
3501 if (isJSArray(globalData, baseValue)) {
3502 JSArray* jsArray = asArray(baseValue);
3503 if (jsArray->canSetIndex(i))
3504 jsArray->setIndex(*globalData, i, callFrame->r(value).jsValue());
3506 jsArray->JSArray::put(callFrame, i, callFrame->r(value).jsValue());
3507 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
3508 JSByteArray* jsByteArray = asByteArray(baseValue);
3510 JSValue jsValue = callFrame->r(value).jsValue();
3511 if (jsValue.isInt32())
3512 jsByteArray->setIndex(i, jsValue.asInt32());
3513 else if (jsValue.getNumber(dValue))
3514 jsByteArray->setIndex(i, dValue);
3516 baseValue.put(callFrame, i, jsValue);
3518 baseValue.put(callFrame, i, callFrame->r(value).jsValue());
3520 Identifier property(callFrame, subscript.toString(callFrame));
3521 if (!globalData->exception) { // Don't put to an object if toString threw an exception.
3522 PutPropertySlot slot(codeBlock->isStrictMode());
3523 baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot);
3527 CHECK_FOR_EXCEPTION();
3528 vPC += OPCODE_LENGTH(op_put_by_val);
3531 DEFINE_OPCODE(op_del_by_val) {
3532 /* del_by_val dst(r) base(r) property(r)
3534 Converts register base to Object, deletes the property
3535 named by register property from the object, and writes a
3536 boolean indicating success (if true) or failure (if false)
3539 int dst = vPC[1].u.operand;
3540 int base = vPC[2].u.operand;
3541 int property = vPC[3].u.operand;
3543 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw
3545 JSValue subscript = callFrame->r(property).jsValue();
3548 if (subscript.getUInt32(i))
3549 result = baseObj->deleteProperty(callFrame, i);
3551 CHECK_FOR_EXCEPTION();
3552 Identifier property(callFrame, subscript.toString(callFrame));
3553 CHECK_FOR_EXCEPTION();
3554 result = baseObj->deleteProperty(callFrame, property);
3556 if (!result && codeBlock->isStrictMode()) {
3557 exceptionValue = createTypeError(callFrame, "Unable to delete property.");
3560 CHECK_FOR_EXCEPTION();
3561 callFrame->uncheckedR(dst) = jsBoolean(result);
3562 vPC += OPCODE_LENGTH(op_del_by_val);
3565 DEFINE_OPCODE(op_put_by_index) {
3566 /* put_by_index base(r) property(n) value(r)
3568 Sets register value on register base as the property named
3569 by the immediate number property. Base is converted to
3572 Unlike many opcodes, this one does not write any output to
3575 This opcode is mainly used to initialize array literals.
3577 int base = vPC[1].u.operand;
3578 unsigned property = vPC[2].u.operand;
3579 int value = vPC[3].u.operand;
3581 callFrame->r(base).jsValue().put(callFrame, property, callFrame->r(value).jsValue());
3583 vPC += OPCODE_LENGTH(op_put_by_index);
3586 DEFINE_OPCODE(op_loop) {
3587 /* loop target(offset)
3589 Jumps unconditionally to offset target from the current
3592 Additionally this loop instruction may terminate JS execution is
3593 the JS timeout is reached.
3595 #if ENABLE(OPCODE_STATS)
3596 OpcodeStats::resetLastInstruction();
3598 int target = vPC[1].u.operand;
3599 CHECK_FOR_TIMEOUT();
3603 DEFINE_OPCODE(op_jmp) {
3604 /* jmp target(offset)
3606 Jumps unconditionally to offset target from the current
3609 #if ENABLE(OPCODE_STATS)
3610 OpcodeStats::resetLastInstruction();
3612 int target = vPC[1].u.operand;
3617 DEFINE_OPCODE(op_loop_hint) {
3618 // This is a no-op unless we intend on doing OSR from the interpreter.
3621 DEFINE_OPCODE(op_loop_if_true) {
3622 /* loop_if_true cond(r) target(offset)
3624 Jumps to offset target from the current instruction, if and
3625 only if register cond converts to boolean as true.
3627 Additionally this loop instruction may terminate JS execution is
3628 the JS timeout is reached.
3630 int cond = vPC[1].u.operand;
3631 int target = vPC[2].u.operand;
3632 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
3634 CHECK_FOR_TIMEOUT();
3638 vPC += OPCODE_LENGTH(op_loop_if_true);
3641 DEFINE_OPCODE(op_loop_if_false) {
3642 /* loop_if_true cond(r) target(offset)
3644 Jumps to offset target from the current instruction, if and
3645 only if register cond converts to boolean as false.
3647 Additionally this loop instruction may terminate JS execution is
3648 the JS timeout is reached.
3650 int cond = vPC[1].u.operand;
3651 int target = vPC[2].u.operand;
3652 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
3654 CHECK_FOR_TIMEOUT();
3658 vPC += OPCODE_LENGTH(op_loop_if_true);
3661 DEFINE_OPCODE(op_jtrue) {
3662 /* jtrue cond(r) target(offset)
3664 Jumps to offset target from the current instruction, if and
3665 only if register cond converts to boolean as true.
3667 int cond = vPC[1].u.operand;
3668 int target = vPC[2].u.operand;
3669 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
3674 vPC += OPCODE_LENGTH(op_jtrue);
3677 DEFINE_OPCODE(op_jfalse) {
3678 /* jfalse cond(r) target(offset)
3680 Jumps to offset target from the current instruction, if and
3681 only if register cond converts to boolean as false.
3683 int cond = vPC[1].u.operand;
3684 int target = vPC[2].u.operand;
3685 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
3690 vPC += OPCODE_LENGTH(op_jfalse);
3693 DEFINE_OPCODE(op_jeq_null) {
3694 /* jeq_null src(r) target(offset)
3696 Jumps to offset target from the current instruction, if and
3697 only if register src is null.
3699 int src = vPC[1].u.operand;
3700 int target = vPC[2].u.operand;
3701 JSValue srcValue = callFrame->r(src).jsValue();
3703 if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
3708 vPC += OPCODE_LENGTH(op_jeq_null);
3711 DEFINE_OPCODE(op_jneq_null) {
3712 /* jneq_null src(r) target(offset)
3714 Jumps to offset target from the current instruction, if and
3715 only if register src is not null.
3717 int src = vPC[1].u.operand;
3718 int target = vPC[2].u.operand;
3719 JSValue srcValue = callFrame->r(src).jsValue();
3721 if (!srcValue.isUndefinedOrNull() && (!srcValue.isCell() || !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
3726 vPC += OPCODE_LENGTH(op_jneq_null);
3729 DEFINE_OPCODE(op_jneq_ptr) {
3730 /* jneq_ptr src(r) ptr(jsCell) target(offset)
3732 Jumps to offset target from the current instruction, if the value r is equal
3733 to ptr, using pointer equality.
3735 int src = vPC[1].u.operand;
3736 int target = vPC[3].u.operand;
3737 JSValue srcValue = callFrame->r(src).jsValue();
3738 if (srcValue != vPC[2].u.jsCell.get()) {
3743 vPC += OPCODE_LENGTH(op_jneq_ptr);
3746 DEFINE_OPCODE(op_loop_if_less) {
3747 /* loop_if_less src1(r) src2(r) target(offset)
3749 Checks whether register src1 is less than register src2, as
3750 with the ECMAScript '<' operator, and then jumps to offset
3751 target from the current instruction, if and only if the
3752 result of the comparison is true.
3754 Additionally this loop instruction may terminate JS execution is
3755 the JS timeout is reached.
3757 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3758 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3759 int target = vPC[3].u.operand;
3761 bool result = jsLess<true>(callFrame, src1, src2);
3762 CHECK_FOR_EXCEPTION();
3766 CHECK_FOR_TIMEOUT();
3770 vPC += OPCODE_LENGTH(op_loop_if_less);
3773 DEFINE_OPCODE(op_loop_if_lesseq) {
3774 /* loop_if_lesseq src1(r) src2(r) target(offset)
3776 Checks whether register src1 is less than or equal to register
3777 src2, as with the ECMAScript '<=' operator, and then jumps to
3778 offset target from the current instruction, if and only if the
3779 result of the comparison is true.
3781 Additionally this loop instruction may terminate JS execution is
3782 the JS timeout is reached.
3784 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3785 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3786 int target = vPC[3].u.operand;
3788 bool result = jsLessEq<true>(callFrame, src1, src2);
3789 CHECK_FOR_EXCEPTION();
3793 CHECK_FOR_TIMEOUT();
3797 vPC += OPCODE_LENGTH(op_loop_if_lesseq);
3800 DEFINE_OPCODE(op_loop_if_greater) {
3801 /* loop_if_greater src1(r) src2(r) target(offset)
3803 Checks whether register src1 is greater than register src2, as
3804 with the ECMAScript '>' operator, and then jumps to offset
3805 target from the current instruction, if and only if the
3806 result of the comparison is true.
3808 Additionally this loop instruction may terminate JS execution is
3809 the JS timeout is reached.
3811 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3812 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3813 int target = vPC[3].u.operand;
3815 bool result = jsLess<false>(callFrame, src2, src1);
3816 CHECK_FOR_EXCEPTION();
3820 CHECK_FOR_TIMEOUT();
3824 vPC += OPCODE_LENGTH(op_loop_if_greater);
3827 DEFINE_OPCODE(op_loop_if_greatereq) {
3828 /* loop_if_greatereq src1(r) src2(r) target(offset)
3830 Checks whether register src1 is greater than or equal to register
3831 src2, as with the ECMAScript '>=' operator, and then jumps to
3832 offset target from the current instruction, if and only if the
3833 result of the comparison is true.
3835 Additionally this loop instruction may terminate JS execution is
3836 the JS timeout is reached.
3838 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3839 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3840 int target = vPC[3].u.operand;
3842 bool result = jsLessEq<false>(callFrame, src2, src1);
3843 CHECK_FOR_EXCEPTION();
3847 CHECK_FOR_TIMEOUT();
3851 vPC += OPCODE_LENGTH(op_loop_if_greatereq);
3854 DEFINE_OPCODE(op_jless) {
3855 /* jless src1(r) src2(r) target(offset)
3857 Checks whether register src1 is less than register src2, as
3858 with the ECMAScript '<' operator, and then jumps to offset
3859 target from the current instruction, if and only if the
3860 result of the comparison is true.
3862 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3863 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3864 int target = vPC[3].u.operand;
3866 bool result = jsLess<true>(callFrame, src1, src2);
3867 CHECK_FOR_EXCEPTION();
3874 vPC += OPCODE_LENGTH(op_jless);
3877 DEFINE_OPCODE(op_jlesseq) {
3878 /* jlesseq src1(r) src2(r) target(offset)
3880 Checks whether register src1 is less than or equal to
3881 register src2, as with the ECMAScript '<=' operator,
3882 and then jumps to offset target from the current instruction,
3883 if and only if the result of the comparison is true.
3885 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3886 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3887 int target = vPC[3].u.operand;
3889 bool result = jsLessEq<true>(callFrame, src1, src2);
3890 CHECK_FOR_EXCEPTION();
3897 vPC += OPCODE_LENGTH(op_jlesseq);
3900 DEFINE_OPCODE(op_jgreater) {
3901 /* jgreater src1(r) src2(r) target(offset)
3903 Checks whether register src1 is greater than register src2, as
3904 with the ECMAScript '>' operator, and then jumps to offset
3905 target from the current instruction, if and only if the
3906 result of the comparison is true.
3908 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3909 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3910 int target = vPC[3].u.operand;
3912 bool result = jsLess<false>(callFrame, src2, src1);
3913 CHECK_FOR_EXCEPTION();
3920 vPC += OPCODE_LENGTH(op_jgreater);
3923 DEFINE_OPCODE(op_jgreatereq) {
3924 /* jgreatereq src1(r) src2(r) target(offset)
3926 Checks whether register src1 is greater than or equal to
3927 register src2, as with the ECMAScript '>=' operator,
3928 and then jumps to offset target from the current instruction,
3929 if and only if the result of the comparison is true.
3931 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3932 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3933 int target = vPC[3].u.operand;
3935 bool result = jsLessEq<false>(callFrame, src2, src1);
3936 CHECK_FOR_EXCEPTION();
3943 vPC += OPCODE_LENGTH(op_jgreatereq);
3946 DEFINE_OPCODE(op_jnless) {
3947 /* jnless src1(r) src2(r) target(offset)
3949 Checks whether register src1 is less than register src2, as
3950 with the ECMAScript '<' operator, and then jumps to offset
3951 target from the current instruction, if and only if the
3952 result of the comparison is false.
3954 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3955 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3956 int target = vPC[3].u.operand;
3958 bool result = jsLess<true>(callFrame, src1, src2);
3959 CHECK_FOR_EXCEPTION();
3966 vPC += OPCODE_LENGTH(op_jnless);
3969 DEFINE_OPCODE(op_jnlesseq) {
3970 /* jnlesseq src1(r) src2(r) target(offset)
3972 Checks whether register src1 is less than or equal to
3973 register src2, as with the ECMAScript '<=' operator,
3974 and then jumps to offset target from the current instruction,
3975 if and only if theresult of the comparison is false.
3977 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3978 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3979 int target = vPC[3].u.operand;
3981 bool result = jsLessEq<true>(callFrame, src1, src2);
3982 CHECK_FOR_EXCEPTION();
3989 vPC += OPCODE_LENGTH(op_jnlesseq);
3992 DEFINE_OPCODE(op_jngreater) {
3993 /* jngreater src1(r) src2(r) target(offset)
3995 Checks whether register src1 is greater than register src2, as
3996 with the ECMAScript '>' operator, and then jumps to offset
3997 target from the current instruction, if and only if the
3998 result of the comparison is false.
4000 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
4001 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
4002 int target = vPC[3].u.operand;
4004 bool result = jsLess<false>(callFrame, src2, src1);
4005 CHECK_FOR_EXCEPTION();
4012 vPC += OPCODE_LENGTH(op_jngreater);
4015 DEFINE_OPCODE(op_jngreatereq) {
4016 /* jngreatereq src1(r) src2(r) target(offset)
4018 Checks whether register src1 is greater than or equal to
4019 register src2, as with the ECMAScript '>=' operator,
4020 and then jumps to offset target from the current instruction,
4021 if and only if theresult of the comparison is false.
4023 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
4024 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
4025 int target = vPC[3].u.operand;
4027 bool result = jsLessEq<false>(callFrame, src2, src1);
4028 CHECK_FOR_EXCEPTION();
4035 vPC += OPCODE_LENGTH(op_jngreatereq);
4038 DEFINE_OPCODE(op_switch_imm) {
4039 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
4041 Performs a range checked switch on the scrutinee value, using
4042 the tableIndex-th immediate switch jump table. If the scrutinee value
4043 is an immediate number in the range covered by the referenced jump
4044 table, and the value at jumpTable[scrutinee value] is non-zero, then
4045 that value is used as the jump offset, otherwise defaultOffset is used.
4047 int tableIndex = vPC[1].u.operand;
4048 int defaultOffset = vPC[2].u.operand;
4049 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
4050 if (scrutinee.isInt32())
4051 vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
4055 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
4056 vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
4058 vPC += defaultOffset;
4062 DEFINE_OPCODE(op_switch_char) {
4063 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
4065 Performs a range checked switch on the scrutinee value, using
4066 the tableIndex-th character switch jump table. If the scrutinee value
4067 is a single character string in the range covered by the referenced jump
4068 table, and the value at jumpTable[scrutinee value] is non-zero, then
4069 that value is used as the jump offset, otherwise defaultOffset is used.
4071 int tableIndex = vPC[1].u.operand;
4072 int defaultOffset = vPC[2].u.operand;
4073 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
4074 if (!scrutinee.isString())
4075 vPC += defaultOffset;
4077 StringImpl* value = asString(scrutinee)->value(callFrame).impl();
4078 if (value->length() != 1)
4079 vPC += defaultOffset;
4081 vPC += codeBlock->characterSwitchJumpTable(tableIndex).offsetForValue((*value)[0], defaultOffset);
4085 DEFINE_OPCODE(op_switch_string) {
4086 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
4088 Performs a sparse hashmap based switch on the value in the scrutinee
4089 register, using the tableIndex-th string switch jump table. If the
4090 scrutinee value is a string that exists as a key in the referenced
4091 jump table, then the value associated with the string is used as the
4092 jump offset, otherwise defaultOffset is used.
4094 int tableIndex = vPC[1].u.operand;
4095 int defaultOffset = vPC[2].u.operand;
4096 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
4097 if (!scrutinee.isString())
4098 vPC += defaultOffset;
4100 vPC += codeBlock->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).impl(), defaultOffset);
4103 DEFINE_OPCODE(op_new_func) {
4104 /* new_func dst(r) func(f)
4106 Constructs a new Function instance from function func and
4107 the current scope chain using the original Function
4108 constructor, using the rules for function declarations, and
4109 puts the result in register dst.
4111 int dst = vPC[1].u.operand;
4112 int func = vPC[2].u.operand;
4113 int shouldCheck = vPC[3].u.operand;
4114 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
4115 if (!shouldCheck || !callFrame->r(dst).jsValue())
4116 callFrame->uncheckedR(dst) = JSValue(codeBlock->functionDecl(func)->make(callFrame, callFrame->scopeChain()));
4118 vPC += OPCODE_LENGTH(op_new_func);
4121 DEFINE_OPCODE(op_new_func_exp) {
4122 /* new_func_exp dst(r) func(f)
4124 Constructs a new Function instance from function func and
4125 the current scope chain using the original Function
4126 constructor, using the rules for function expressions, and
4127 puts the result in register dst.
4129 int dst = vPC[1].u.operand;
4130 int funcIndex = vPC[2].u.operand;
4132 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
4133 FunctionExecutable* function = codeBlock->functionExpr(funcIndex);
4134 JSFunction* func = function->make(callFrame, callFrame->scopeChain());
4137 The Identifier in a FunctionExpression can be referenced from inside
4138 the FunctionExpression's FunctionBody to allow the function to call
4139 itself recursively. However, unlike in a FunctionDeclaration, the
4140 Identifier in a FunctionExpression cannot be referenced from and
4141 does not affect the scope enclosing the FunctionExpression.
4143 if (!function->name().isNull()) {
4144 JSStaticScopeObject* functionScopeObject = JSStaticScopeObject::create(callFrame, function->name(), func, ReadOnly | DontDelete);
4145 func->setScope(*globalData, func->scope()->push(functionScopeObject));
4148 callFrame->uncheckedR(dst) = JSValue(func);
4150 vPC += OPCODE_LENGTH(op_new_func_exp);
4153 DEFINE_OPCODE(op_call_eval) {
4154 /* call_eval func(r) argCount(n) registerOffset(n)
4156 Call a function named "eval" with no explicit "this" value
4157 (which may therefore be the eval operator). If register
4158 thisVal is the global object, and register func contains
4159 that global object's original global eval function, then
4160 perform the eval operator in local scope (interpreting
4161 the argument registers as for the "call"
4162 opcode). Otherwise, act exactly as the "call" opcode would.
4165 int func = vPC[1].u.operand;
4166 int argCount = vPC[2].u.operand;
4167 int registerOffset = vPC[3].u.operand;
4169 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
4170 JSValue funcVal = callFrame->r(func).jsValue();
4172 if (isHostFunction(callFrame->globalData(), funcVal, globalFuncEval)) {
4173 Register* newCallFrame = callFrame->registers() + registerOffset;
4174 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
4176 JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset);
4177 if ((exceptionValue = globalData->exception))
4179 functionReturnValue = result;
4181 vPC += OPCODE_LENGTH(op_call_eval);
4185 // We didn't find the blessed version of eval, so process this
4186 // instruction as a normal function call.
4187 // fall through to op_call
4189 DEFINE_OPCODE(op_call) {
4190 /* call func(r) argCount(n) registerOffset(n)
4192 Perform a function call.
4194 registerOffset is the distance the callFrame pointer should move
4195 before the VM initializes the new call frame's header.
4197 dst is where op_ret should store its result.
4200 int func = vPC[1].u.operand;
4201 int argCount = vPC[2].u.operand;
4202 int registerOffset = vPC[3].u.operand;
4204 JSValue v = callFrame->r(func).jsValue();
4207 CallType callType = getCallData(v, callData);
4209 if (callType == CallTypeJS) {
4210 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
4212 JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
4213 if (UNLIKELY(!!error)) {
4214 exceptionValue = error;
4218 CallFrame* previousCallFrame = callFrame;
4219 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
4220 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
4221 if (UNLIKELY(!callFrame)) {
4222 callFrame = previousCallFrame;
4223 exceptionValue = createStackOverflowError(callFrame);
4227 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
4228 codeBlock = newCodeBlock;
4229 ASSERT(codeBlock == callFrame->codeBlock());
4230 *topCallFrameSlot = callFrame;
4231 vPC = newCodeBlock->instructions().begin();
4233 #if ENABLE(OPCODE_STATS)
4234 OpcodeStats::resetLastInstruction();
4240 if (callType == CallTypeHost) {
4241 ScopeChainNode* scopeChain = callFrame->scopeChain();
4242 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
4243 if (!registerFile->grow(newCallFrame->registers())) {
4244 exceptionValue = createStackOverflowError(callFrame);
4248 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call), scopeChain, callFrame, argCount, asObject(v));
4249 JSValue returnValue;
4251 *topCallFrameSlot = newCallFrame;
4252 SamplingTool::HostCallRecord callRecord(m_sampler.get());
4253 returnValue = JSValue::decode(callData.native.function(newCallFrame));
4254 *topCallFrameSlot = callFrame;
4256 CHECK_FOR_EXCEPTION();
4258 functionReturnValue = returnValue;
4260 vPC += OPCODE_LENGTH(op_call);
4264 ASSERT(callType == CallTypeNone);
4266 exceptionValue = createNotAFunctionError(callFrame, v);
4269 DEFINE_OPCODE(op_load_varargs) {
4270 int argCountDst = vPC[1].u.operand;
4271 int argsOffset = vPC[2].u.operand;
4273 JSValue arguments = callFrame->r(argsOffset).jsValue();
4274 uint32_t argCount = 0;
4276 argCount = (uint32_t)(callFrame->argumentCount());
4277 if (argCount > Arguments::MaxArguments) {
4278 exceptionValue = createStackOverflowError(callFrame);
4281 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
4282 Register* newEnd = callFrame->registers() + sizeDelta;
4283 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
4284 exceptionValue = createStackOverflowError(callFrame);
4287 ASSERT(!asFunction(callFrame->callee())->isHostFunction());
4288 int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount();
4289 int32_t inplaceArgs = min(static_cast<int32_t>(argCount), expectedParams);
4291 Register* argStore = callFrame->registers() + argsOffset;
4293 // First step is to copy the "expected" parameters from their normal location relative to the callframe
4294 for (; i < inplaceArgs; i++)
4295 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
4296 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
4297 for (; i < static_cast<int32_t>(argCount); i++)
4298 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - static_cast<int32_t>(argCount) - 1];
4299 } else if (!arguments.isUndefinedOrNull()) {
4300 if (!arguments.isObject()) {
4301 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
4304 if (asObject(arguments)->classInfo() == &Arguments::s_info) {
4305 Arguments* args = asArguments(arguments);
4306 argCount = args->numProvidedArguments(callFrame);
4307 if (argCount > Arguments::MaxArguments) {
4308 exceptionValue = createStackOverflowError(callFrame);
4311 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
4312 Register* newEnd = callFrame->registers() + sizeDelta;
4313 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
4314 exceptionValue = createStackOverflowError(callFrame);
4317 args->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
4318 } else if (isJSArray(&callFrame->globalData(), arguments)) {
4319 JSArray* array = asArray(arguments);
4320 argCount = array->length();
4321 if (argCount > Arguments::MaxArguments) {
4322 exceptionValue = createStackOverflowError(callFrame);
4325 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
4326 Register* newEnd = callFrame->registers() + sizeDelta;
4327 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
4328 exceptionValue = createStackOverflowError(callFrame);
4331 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
4333 JSObject* argObject = asObject(arguments);
4334 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
4335 if (argCount > Arguments::MaxArguments) {
4336 exceptionValue = createStackOverflowError(callFrame);
4339 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
4340 Register* newEnd = callFrame->registers() + sizeDelta;
4341 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
4342 exceptionValue = createStackOverflowError(callFrame);
4345 Register* argsBuffer = callFrame->registers() + argsOffset;
4346 for (uint32_t i = 0; i < argCount; ++i) {
4347 argsBuffer[i] = asObject(arguments)->get(callFrame, i);
4348 CHECK_FOR_EXCEPTION();
4352 CHECK_FOR_EXCEPTION();
4353 callFrame->uncheckedR(argCountDst) = Register::withInt(argCount + 1);
4354 vPC += OPCODE_LENGTH(op_load_varargs);
4357 DEFINE_OPCODE(op_call_varargs) {
4358 /* call_varargs func(r) argCountReg(r) baseRegisterOffset(n)
4360 Perform a function call with a dynamic set of arguments.
4362 registerOffset is the distance the callFrame pointer should move
4363 before the VM initializes the new call frame's header, excluding
4364 space for arguments.
4366 dst is where op_ret should store its result.
4369 int func = vPC[1].u.operand;
4370 int argCountReg = vPC[2].u.operand;
4371 int registerOffset = vPC[3].u.operand;
4373 JSValue v = callFrame->r(func).jsValue();
4374 int argCount = callFrame->r(argCountReg).i();
4375 registerOffset += argCount;
4377 CallType callType = getCallData(v, callData);
4379 if (callType == CallTypeJS) {
4380 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
4382 JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
4383 if (UNLIKELY(!!error)) {
4384 exceptionValue = error;
4388 CallFrame* previousCallFrame = callFrame;
4389 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
4390 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
4391 if (UNLIKELY(!callFrame)) {
4392 callFrame = previousCallFrame;
4393 exceptionValue = createStackOverflowError(callFrame);
4397 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call_varargs), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
4398 codeBlock = newCodeBlock;
4399 ASSERT(codeBlock == callFrame->codeBlock());
4400 *topCallFrameSlot = callFrame;
4401 vPC = newCodeBlock->instructions().begin();
4403 #if ENABLE(OPCODE_STATS)
4404 OpcodeStats::resetLastInstruction();
4410 if (callType == CallTypeHost) {
4411 ScopeChainNode* scopeChain = callFrame->scopeChain();
4412 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
4413 if (!registerFile->grow(newCallFrame->registers())) {
4414 exceptionValue = createStackOverflowError(callFrame);
4417 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_varargs), scopeChain, callFrame, argCount, asObject(v));
4419 JSValue returnValue;
4421 *topCallFrameSlot = newCallFrame;
4422 SamplingTool::HostCallRecord callRecord(m_sampler.get());
4423 returnValue = JSValue::decode(callData.native.function(newCallFrame));
4424 *topCallFrameSlot = callFrame;
4426 CHECK_FOR_EXCEPTION();
4428 functionReturnValue = returnValue;
4430 vPC += OPCODE_LENGTH(op_call_varargs);
4434 ASSERT(callType == CallTypeNone);
4436 exceptionValue = createNotAFunctionError(callFrame, v);
4439 DEFINE_OPCODE(op_tear_off_activation) {
4440 /* tear_off_activation activation(r) arguments(r)
4442 Copy locals and named parameters from the register file to the heap.
4443 Point the bindings in 'activation' and 'arguments' to this new backing
4444 store. (Note that 'arguments' may not have been created. If created,
4445 'arguments' already holds a copy of any extra / unnamed parameters.)
4447 This opcode appears before op_ret in functions that require full scope chains.
4450 int activation = vPC[1].u.operand;
4451 int arguments = vPC[2].u.operand;
4452 ASSERT(codeBlock->needsFullScopeChain());
4453 JSValue activationValue = callFrame->r(activation).jsValue();
4454 if (activationValue) {
4455 asActivation(activationValue)->copyRegisters(*globalData);
4457 if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
4458 if (!codeBlock->isStrictMode())
4459 asArguments(argumentsValue)->setActivation(*globalData, asActivation(activationValue));
4461 } else if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
4462 if (!codeBlock->isStrictMode())
4463 asArguments(argumentsValue)->copyRegisters(*globalData);
4466 vPC += OPCODE_LENGTH(op_tear_off_activation);
4469 DEFINE_OPCODE(op_tear_off_arguments) {
4470 /* tear_off_arguments arguments(r)
4472 Copy named parameters from the register file to the heap. Point the
4473 bindings in 'arguments' to this new backing store. (Note that
4474 'arguments' may not have been created. If created, 'arguments' already
4475 holds a copy of any extra / unnamed parameters.)
4477 This opcode appears before op_ret in functions that don't require full
4478 scope chains, but do use 'arguments'.
4481 int src1 = vPC[1].u.operand;
4482 ASSERT(!codeBlock->needsFullScopeChain() && codeBlock->ownerExecutable()->usesArguments());
4484 if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(src1)).jsValue())
4485 asArguments(arguments)->copyRegisters(*globalData);
4487 vPC += OPCODE_LENGTH(op_tear_off_arguments);
4490 DEFINE_OPCODE(op_ret) {
4493 Return register result as the return value of the current
4494 function call, writing it into functionReturnValue.
4495 In addition, unwind one call frame and restore the scope
4496 chain, code block instruction pointer and register base
4497 to those of the calling function.
4500 int result = vPC[1].u.operand;
4502 JSValue returnValue = callFrame->r(result).jsValue();
4504 vPC = callFrame->returnVPC();
4505 callFrame = callFrame->callerFrame();
4507 if (callFrame->hasHostCallFrameFlag())
4510 *topCallFrameSlot = callFrame;
4511 functionReturnValue = returnValue;
4512 codeBlock = callFrame->codeBlock();
4513 ASSERT(codeBlock == callFrame->codeBlock());
4517 DEFINE_OPCODE(op_call_put_result) {
4518 /* op_call_put_result result(r)
4520 Move call result from functionReturnValue to caller's
4521 expected return value register.
4524 callFrame->uncheckedR(vPC[1].u.operand) = functionReturnValue;
4526 vPC += OPCODE_LENGTH(op_call_put_result);
4529 DEFINE_OPCODE(op_ret_object_or_this) {
4532 Return register result as the return value of the current
4533 function call, writing it into the caller's expected return
4534 value register. In addition, unwind one call frame and
4535 restore the scope chain, code block instruction pointer and
4536 register base to those of the calling function.
4539 int result = vPC[1].u.operand;
4541 JSValue returnValue = callFrame->r(result).jsValue();
4543 if (UNLIKELY(!returnValue.isObject()))
4544 returnValue = callFrame->r(vPC[2].u.operand).jsValue();
4546 vPC = callFrame->returnVPC();
4547 callFrame = callFrame->callerFrame();
4549 if (callFrame->hasHostCallFrameFlag())
4552 *topCallFrameSlot = callFrame;
4553 functionReturnValue = returnValue;
4554 codeBlock = callFrame->codeBlock();
4555 ASSERT(codeBlock == callFrame->codeBlock());
4559 DEFINE_OPCODE(op_enter) {
4562 Initializes local variables to undefined. If the code block requires
4563 an activation, enter_with_activation is used instead.
4565 This opcode appears only at the beginning of a code block.
4569 for (size_t count = codeBlock->m_numVars; i < count; ++i)
4570 callFrame->uncheckedR(i) = jsUndefined();
4572 vPC += OPCODE_LENGTH(op_enter);
4575 DEFINE_OPCODE(op_create_activation) {
4576 /* create_activation dst(r)
4578 If the activation object for this callframe has not yet been created,
4579 this creates it and writes it back to dst.
4582 int activationReg = vPC[1].u.operand;
4583 if (!callFrame->r(activationReg).jsValue()) {
4584 JSActivation* activation = JSActivation::create(*globalData, callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable()));
4585 callFrame->r(activationReg) = JSValue(activation);
4586 callFrame->setScopeChain(callFrame->scopeChain()->push(activation));
4588 vPC += OPCODE_LENGTH(op_create_activation);
4591 DEFINE_OPCODE(op_get_callee) {
4592 /* op_get_callee callee(r)
4594 Move callee into a register.
4597 callFrame->uncheckedR(vPC[1].u.operand) = JSValue(callFrame->callee());
4599 vPC += OPCODE_LENGTH(op_get_callee);
4602 DEFINE_OPCODE(op_create_this) {
4603 /* op_create_this this(r) proto(r)
4605 Allocate an object as 'this', fr use in construction.
4607 This opcode should only be used at the beginning of a code
4611 int thisRegister = vPC[1].u.operand;
4612 int protoRegister = vPC[2].u.operand;
4614 JSFunction* constructor = asFunction(callFrame->callee());
4615 #if !ASSERT_DISABLED
4616 ConstructData constructData;
4617 ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
4620 Structure* structure;
4621 JSValue proto = callFrame->r(protoRegister).jsValue();
4622 if (proto.isObject())
4623 structure = asObject(proto)->inheritorID(callFrame->globalData());
4625 structure = constructor->scope()->globalObject->emptyObjectStructure();
4626 callFrame->uncheckedR(thisRegister) = constructEmptyObject(callFrame, structure);
4628 vPC += OPCODE_LENGTH(op_create_this);
4631 DEFINE_OPCODE(op_convert_this) {
4632 /* convert_this this(r)
4634 Takes the value in the 'this' register, converts it to a
4635 value that is suitable for use as the 'this' value, and
4636 stores it in the 'this' register. This opcode is emitted
4637 to avoid doing the conversion in the caller unnecessarily.
4639 This opcode should only be used at the beginning of a code
4643 int thisRegister = vPC[1].u.operand;
4644 JSValue thisVal = callFrame->r(thisRegister).jsValue();
4645 if (thisVal.isPrimitive())
4646 callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
4648 vPC += OPCODE_LENGTH(op_convert_this);
4651 DEFINE_OPCODE(op_init_lazy_reg) {
4652 /* init_lazy_reg dst(r)
4654 Initialises dst(r) to JSValue().
4656 This opcode appears only at the beginning of a code block.
4658 int dst = vPC[1].u.operand;
4660 callFrame->uncheckedR(dst) = JSValue();
4661 vPC += OPCODE_LENGTH(op_init_lazy_reg);
4664 DEFINE_OPCODE(op_create_arguments) {
4665 /* create_arguments dst(r)
4667 Creates the 'arguments' object and places it in both the
4668 'arguments' call frame slot and the local 'arguments'
4669 register, if it has not already been initialised.
4672 int dst = vPC[1].u.operand;
4674 if (!callFrame->r(dst).jsValue()) {
4675 Arguments* arguments = Arguments::create(*globalData, callFrame);
4676 callFrame->uncheckedR(dst) = JSValue(arguments);
4677 callFrame->uncheckedR(unmodifiedArgumentsRegister(dst)) = JSValue(arguments);
4679 vPC += OPCODE_LENGTH(op_create_arguments);
4682 DEFINE_OPCODE(op_construct) {
4683 /* construct func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
4685 Invoke register "func" as a constructor. For JS
4686 functions, the calling convention is exactly as for the
4687 "call" opcode, except that the "this" value is a newly
4688 created Object. For native constructors, no "this"
4689 value is passed. In either case, the argCount and registerOffset
4690 registers are interpreted as for the "call" opcode.
4692 Register proto must contain the prototype property of
4693 register func. This is to enable polymorphic inline
4694 caching of this lookup.
4697 int func = vPC[1].u.operand;
4698 int argCount = vPC[2].u.operand;
4699 int registerOffset = vPC[3].u.operand;
4701 JSValue v = callFrame->r(func).jsValue();
4703 ConstructData constructData;
4704 ConstructType constructType = getConstructData(v, constructData);
4706 if (constructType == ConstructTypeJS) {
4707 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
4709 JSObject* error = constructData.js.functionExecutable->compileForConstruct(callFrame, callDataScopeChain);
4710 if (UNLIKELY(!!error)) {
4711 exceptionValue = error;
4715 CallFrame* previousCallFrame = callFrame;
4716 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
4717 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
4718 if (UNLIKELY(!callFrame)) {
4719 callFrame = previousCallFrame;
4720 exceptionValue = createStackOverflowError(callFrame);
4724 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_construct), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
4725 codeBlock = newCodeBlock;
4726 *topCallFrameSlot = callFrame;
4727 vPC = newCodeBlock->instructions().begin();
4728 #if ENABLE(OPCODE_STATS)
4729 OpcodeStats::resetLastInstruction();
4735 if (constructType == ConstructTypeHost) {
4736 ScopeChainNode* scopeChain = callFrame->scopeChain();
4737 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
4738 if (!registerFile->grow(newCallFrame->registers())) {
4739 exceptionValue = createStackOverflowError(callFrame);
4742 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_construct), scopeChain, callFrame, argCount, asObject(v));
4744 JSValue returnValue;
4746 *topCallFrameSlot = newCallFrame;
4747 SamplingTool::HostCallRecord callRecord(m_sampler.get());
4748 returnValue = JSValue::decode(constructData.native.function(newCallFrame));
4749 *topCallFrameSlot = callFrame;
4751 CHECK_FOR_EXCEPTION();
4752 functionReturnValue = returnValue;
4754 vPC += OPCODE_LENGTH(op_construct);
4758 ASSERT(constructType == ConstructTypeNone);
4760 exceptionValue = createNotAConstructorError(callFrame, v);
4763 DEFINE_OPCODE(op_strcat) {
4764 /* strcat dst(r) src(r) count(n)
4766 Construct a new String instance using the original
4767 constructor, and puts the result in register dst.
4768 The string will be the result of concatenating count
4769 strings with values taken from registers starting at
4772 int dst = vPC[1].u.operand;
4773 int src = vPC[2].u.operand;
4774 int count = vPC[3].u.operand;
4776 callFrame->uncheckedR(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
4777 CHECK_FOR_EXCEPTION();
4778 vPC += OPCODE_LENGTH(op_strcat);
4782 DEFINE_OPCODE(op_to_primitive) {
4783 int dst = vPC[1].u.operand;
4784 int src = vPC[2].u.operand;
4786 callFrame->uncheckedR(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);
4787 vPC += OPCODE_LENGTH(op_to_primitive);
4791 DEFINE_OPCODE(op_push_scope) {
4792 /* push_scope scope(r)
4794 Converts register scope to object, and pushes it onto the top
4795 of the current scope chain. The contents of the register scope
4796 are replaced by the result of toObject conversion of the scope.
4798 int scope = vPC[1].u.operand;
4799 JSValue v = callFrame->r(scope).jsValue();
4800 JSObject* o = v.toObject(callFrame);
4801 CHECK_FOR_EXCEPTION();
4803 callFrame->uncheckedR(scope) = JSValue(o);
4804 callFrame->setScopeChain(callFrame->scopeChain()->push(o));
4806 vPC += OPCODE_LENGTH(op_push_scope);
4809 DEFINE_OPCODE(op_pop_scope) {
4812 Removes the top item from the current scope chain.
4814 callFrame->setScopeChain(callFrame->scopeChain()->pop());
4816 vPC += OPCODE_LENGTH(op_pop_scope);
4819 DEFINE_OPCODE(op_get_pnames) {
4820 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
4822 Creates a property name list for register base and puts it
4823 in register dst, initializing i and size for iteration. If
4824 base is undefined or null, jumps to breakTarget.
4826 int dst = vPC[1].u.operand;
4827 int base = vPC[2].u.operand;
4828 int i = vPC[3].u.operand;
4829 int size = vPC[4].u.operand;
4830 int breakTarget = vPC[5].u.operand;
4832 JSValue v = callFrame->r(base).jsValue();
4833 if (v.isUndefinedOrNull()) {
4838 JSObject* o = v.toObject(callFrame);
4839 Structure* structure = o->structure();
4840 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
4841 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
4842 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
4844 callFrame->uncheckedR(dst) = jsPropertyNameIterator;
4845 callFrame->uncheckedR(base) = JSValue(o);
4846 callFrame->uncheckedR(i) = Register::withInt(0);
4847 callFrame->uncheckedR(size) = Register::withInt(jsPropertyNameIterator->size());
4848 vPC += OPCODE_LENGTH(op_get_pnames);
4851 DEFINE_OPCODE(op_next_pname) {
4852 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
4854 Copies the next name from the property name list in
4855 register iter to dst, then jumps to offset target. If there are no
4856 names left, invalidates the iterator and continues to the next
4859 int dst = vPC[1].u.operand;
4860 int base = vPC[2].u.operand;
4861 int i = vPC[3].u.operand;
4862 int size = vPC[4].u.operand;
4863 int iter = vPC[5].u.operand;
4864 int target = vPC[6].u.operand;
4866 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
4867 while (callFrame->r(i).i() != callFrame->r(size).i()) {
4868 JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());
4869 CHECK_FOR_EXCEPTION();
4870 callFrame->uncheckedR(i) = Register::withInt(callFrame->r(i).i() + 1);
4872 CHECK_FOR_TIMEOUT();
4873 callFrame->uncheckedR(dst) = key;
4879 vPC += OPCODE_LENGTH(op_next_pname);
4882 DEFINE_OPCODE(op_jmp_scopes) {
4883 /* jmp_scopes count(n) target(offset)
4885 Removes the a number of items from the current scope chain
4886 specified by immediate number count, then jumps to offset
4889 int count = vPC[1].u.operand;
4890 int target = vPC[2].u.operand;
4892 ScopeChainNode* tmp = callFrame->scopeChain();
4895 callFrame->setScopeChain(tmp);
4900 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
4902 goto *(&&skip_new_scope);
4904 DEFINE_OPCODE(op_push_new_scope) {
4905 /* new_scope dst(r) property(id) value(r)
4907 Constructs a new StaticScopeObject with property set to value. That scope
4908 object is then pushed onto the ScopeChain. The scope object is then stored
4911 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));
4913 vPC += OPCODE_LENGTH(op_push_new_scope);
4916 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
4919 DEFINE_OPCODE(op_catch) {
4922 Retrieves the VM's current exception and puts it in register
4923 ex. This is only valid after an exception has been raised,
4924 and usually forms the beginning of an exception handler.
4926 ASSERT(exceptionValue);
4927 ASSERT(!globalData->exception);
4928 int ex = vPC[1].u.operand;
4929 callFrame->uncheckedR(ex) = exceptionValue;
4930 exceptionValue = JSValue();
4932 vPC += OPCODE_LENGTH(op_catch);
4935 DEFINE_OPCODE(op_throw) {
4938 Throws register ex as an exception. This involves three
4939 steps: first, it is set as the current exception in the
4940 VM's internal state, then the stack is unwound until an
4941 exception handler or a native code boundary is found, and
4942 then control resumes at the exception handler if any or
4943 else the script returns control to the nearest native caller.
4946 int ex = vPC[1].u.operand;
4947 exceptionValue = callFrame->r(ex).jsValue();
4949 handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
4951 return throwError(callFrame, exceptionValue);
4953 codeBlock = callFrame->codeBlock();
4954 vPC = codeBlock->instructions().begin() + handler->target;
4957 DEFINE_OPCODE(op_throw_reference_error) {
4958 /* op_throw_reference_error message(k)
4960 Constructs a new reference Error instance using the
4961 original constructor, using constant message as the
4962 message string. The result is thrown.
4964 UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame);
4965 exceptionValue = JSValue(createReferenceError(callFrame, message));
4968 DEFINE_OPCODE(op_end) {
4971 Return register result as the value of a global or eval
4972 program. Return control to the calling native code.
4975 int result = vPC[1].u.operand;
4976 return callFrame->r(result).jsValue();
4978 DEFINE_OPCODE(op_put_getter) {
4979 /* put_getter base(r) property(id) function(r)
4981 Sets register function on register base as the getter named
4982 by identifier property. Base and function are assumed to be
4983 objects as this op should only be used for getters defined
4984 in object literal form.
4986 Unlike many opcodes, this one does not write any output to
4989 int base = vPC[1].u.operand;
4990 int property = vPC[2].u.operand;
4991 int function = vPC[3].u.operand;
4993 ASSERT(callFrame->r(base).jsValue().isObject());
4994 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
4995 Identifier& ident = codeBlock->identifier(property);
4996 ASSERT(callFrame->r(function).jsValue().isObject());
4997 baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue()));
4999 vPC += OPCODE_LENGTH(op_put_getter);
5002 DEFINE_OPCODE(op_put_setter) {
5003 /* put_setter base(r) property(id) function(r)
5005 Sets register function on register base as the setter named
5006 by identifier property. Base and function are assumed to be
5007 objects as this op should only be used for setters defined
5008 in object literal form.
5010 Unlike many opcodes, this one does not write any output to
5013 int base = vPC[1].u.operand;
5014 int property = vPC[2].u.operand;
5015 int function = vPC[3].u.operand;
5017 ASSERT(callFrame->r(base).jsValue().isObject());
5018 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
5019 Identifier& ident = codeBlock->identifier(property);
5020 ASSERT(callFrame->r(function).jsValue().isObject());
5021 baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
5023 vPC += OPCODE_LENGTH(op_put_setter);
5026 DEFINE_OPCODE(op_method_check) {
5030 DEFINE_OPCODE(op_jsr) {
5031 /* jsr retAddrDst(r) target(offset)
5033 Places the address of the next instruction into the retAddrDst
5034 register and jumps to offset target from the current instruction.
5036 int retAddrDst = vPC[1].u.operand;
5037 int target = vPC[2].u.operand;
5038 callFrame->r(retAddrDst) = vPC + OPCODE_LENGTH(op_jsr);
5043 DEFINE_OPCODE(op_sret) {
5044 /* sret retAddrSrc(r)
5046 Jumps to the address stored in the retAddrSrc register. This
5047 differs from op_jmp because the target address is stored in a
5048 register, not as an immediate.
5050 int retAddrSrc = vPC[1].u.operand;
5051 vPC = callFrame->r(retAddrSrc).vPC();
5054 DEFINE_OPCODE(op_debug) {
5055 /* debug debugHookID(n) firstLine(n) lastLine(n)
5057 Notifies the debugger of the current state of execution. This opcode
5058 is only generated while the debugger is attached.
5060 int debugHookID = vPC[1].u.operand;
5061 int firstLine = vPC[2].u.operand;
5062 int lastLine = vPC[3].u.operand;
5064 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
5066 vPC += OPCODE_LENGTH(op_debug);
5069 DEFINE_OPCODE(op_profile_will_call) {
5070 /* op_profile_will_call function(r)
5072 Notifies the profiler of the beginning of a function call. This opcode
5073 is only generated if developer tools are enabled.
5075 int function = vPC[1].u.operand;
5077 if (*enabledProfilerReference)
5078 (*enabledProfilerReference)->willExecute(callFrame, callFrame->r(function).jsValue());
5080 vPC += OPCODE_LENGTH(op_profile_will_call);
5083 DEFINE_OPCODE(op_profile_did_call) {
5084 /* op_profile_did_call function(r)
5086 Notifies the profiler of the end of a function call. This opcode
5087 is only generated if developer tools are enabled.
5089 int function = vPC[1].u.operand;
5091 if (*enabledProfilerReference)
5092 (*enabledProfilerReference)->didExecute(callFrame, callFrame->r(function).jsValue());
5094 vPC += OPCODE_LENGTH(op_profile_did_call);
5098 globalData->exception = JSValue();
5100 // The exceptionValue is a lie! (GCC produces bad code for reasons I
5101 // cannot fathom if we don't assign to the exceptionValue before branching)
5102 exceptionValue = createInterruptedExecutionException(globalData);
5104 JSGlobalObject* globalObject = callFrame->lexicalGlobalObject();
5105 handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
5107 // Can't use the callframe at this point as the scopechain, etc have
5109 return throwError(globalObject->globalExec(), exceptionValue);
5112 codeBlock = callFrame->codeBlock();
5113 vPC = codeBlock->instructions().begin() + handler->target;
5117 #if !ENABLE(COMPUTED_GOTO_INTERPRETER)
5118 } // iterator loop ends
5120 #undef NEXT_INSTRUCTION
5121 #undef DEFINE_OPCODE
5122 #undef CHECK_FOR_EXCEPTION
5123 #undef CHECK_FOR_TIMEOUT
5124 #endif // ENABLE(INTERPRETER)
5127 JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
5129 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
5130 if (!functionCallFrame)
5133 CodeBlock* codeBlock = functionCallFrame->codeBlock();
5134 if (codeBlock->usesArguments()) {
5135 ASSERT(codeBlock->codeType() == FunctionCode);
5136 int argumentsRegister = codeBlock->argumentsRegister();
5137 int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);
5138 if (JSValue arguments = functionCallFrame->uncheckedR(argumentsRegister).jsValue())
5140 JSValue arguments = JSValue(Arguments::create(callFrame->globalData(), functionCallFrame));
5141 functionCallFrame->r(argumentsRegister) = arguments;
5142 functionCallFrame->r(realArgumentsRegister) = arguments;
5146 Arguments* arguments = Arguments::create(functionCallFrame->globalData(), functionCallFrame);
5147 arguments->copyRegisters(functionCallFrame->globalData());
5151 JSValue Interpreter::retrieveCaller(CallFrame* callFrame, JSFunction* function) const
5153 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
5154 if (!functionCallFrame)
5157 CallFrame* callerFrame = functionCallFrame->callerFrame();
5158 if (callerFrame->hasHostCallFrameFlag())
5161 JSValue caller = callerFrame->callee();
5168 void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const
5170 function = JSValue();
5172 sourceURL = UString();
5174 CallFrame* callerFrame = callFrame->callerFrame();
5175 if (callerFrame->hasHostCallFrameFlag())
5178 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
5179 if (!callerCodeBlock)
5181 unsigned bytecodeOffset = 0;
5182 #if ENABLE(INTERPRETER)
5183 if (!callerFrame->globalData().canUseJIT())
5184 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());
5187 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
5190 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
5192 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);
5193 sourceID = callerCodeBlock->ownerExecutable()->sourceID();
5194 sourceURL = callerCodeBlock->ownerExecutable()->sourceURL();
5195 function = callerFrame->callee();
5198 CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, JSFunction* function)
5200 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
5201 if (candidate->callee() == function)
5207 void Interpreter::enableSampler()
5209 #if ENABLE(OPCODE_SAMPLING)
5211 m_sampler = adoptPtr(new SamplingTool(this));
5216 void Interpreter::dumpSampleData(ExecState* exec)
5218 #if ENABLE(OPCODE_SAMPLING)
5220 m_sampler->dump(exec);
5225 void Interpreter::startSampling()
5227 #if ENABLE(SAMPLING_THREAD)
5228 if (!m_sampleEntryDepth)
5229 SamplingThread::start();
5231 m_sampleEntryDepth++;
5234 void Interpreter::stopSampling()
5236 #if ENABLE(SAMPLING_THREAD)
5237 m_sampleEntryDepth--;
5238 if (!m_sampleEntryDepth)
5239 SamplingThread::stop();