2 * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "Interpreter.h"
33 #include "Arguments.h"
34 #include "BatchedTransitionOptimizer.h"
35 #include "CallFrame.h"
36 #include "CallFrameClosure.h"
37 #include "CodeBlock.h"
40 #include "DebuggerCallFrame.h"
41 #include "ErrorInstance.h"
42 #include "EvalCodeCache.h"
43 #include "ExceptionHelpers.h"
44 #include "GetterSetter.h"
45 #include "JSActivation.h"
47 #include "JSBoundFunction.h"
48 #include "JSNotAnObject.h"
49 #include "JSPropertyNameIterator.h"
50 #include "LiteralParser.h"
51 #include "JSStaticScopeObject.h"
53 #include "ObjectPrototype.h"
54 #include "Operations.h"
57 #include "RegExpObject.h"
58 #include "RegExpPrototype.h"
60 #include "SamplingTool.h"
61 #include "StrictEvalActivation.h"
62 #include "StrongInlines.h"
63 #include "UStringConcatenate.h"
66 #include <wtf/Threading.h>
67 #include <wtf/text/StringBuilder.h>
73 #define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND ((ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)) && !defined(__llvm__))
79 // Returns the depth of the scope chain within a given call frame.
80 static int depth(CodeBlock
* codeBlock
, ScopeChainNode
* sc
)
82 if (!codeBlock
->needsFullScopeChain())
84 return sc
->localDepth();
87 #if ENABLE(CLASSIC_INTERPRETER)
88 static NEVER_INLINE JSValue
concatenateStrings(ExecState
* exec
, Register
* strings
, unsigned count
)
90 return jsString(exec
, strings
, count
);
93 NEVER_INLINE
bool Interpreter::resolve(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
95 int dst
= vPC
[1].u
.operand
;
96 int property
= vPC
[2].u
.operand
;
98 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
99 ScopeChainIterator iter
= scopeChain
->begin();
100 ScopeChainIterator end
= scopeChain
->end();
103 CodeBlock
* codeBlock
= callFrame
->codeBlock();
104 Identifier
& ident
= codeBlock
->identifier(property
);
106 JSObject
* o
= iter
->get();
107 PropertySlot
slot(o
);
108 if (o
->getPropertySlot(callFrame
, ident
, slot
)) {
109 JSValue result
= slot
.getValue(callFrame
, ident
);
110 exceptionValue
= callFrame
->globalData().exception
;
113 callFrame
->uncheckedR(dst
) = JSValue(result
);
116 } while (++iter
!= end
);
117 exceptionValue
= createUndefinedVariableError(callFrame
, ident
);
121 NEVER_INLINE
bool Interpreter::resolveSkip(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
123 CodeBlock
* codeBlock
= callFrame
->codeBlock();
125 int dst
= vPC
[1].u
.operand
;
126 int property
= vPC
[2].u
.operand
;
127 int skip
= vPC
[3].u
.operand
;
129 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
130 ScopeChainIterator iter
= scopeChain
->begin();
131 ScopeChainIterator end
= scopeChain
->end();
133 bool checkTopLevel
= codeBlock
->codeType() == FunctionCode
&& codeBlock
->needsFullScopeChain();
134 ASSERT(skip
|| !checkTopLevel
);
135 if (checkTopLevel
&& skip
--) {
136 if (callFrame
->uncheckedR(codeBlock
->activationRegister()).jsValue())
143 Identifier
& ident
= codeBlock
->identifier(property
);
145 JSObject
* o
= iter
->get();
146 PropertySlot
slot(o
);
147 if (o
->getPropertySlot(callFrame
, ident
, slot
)) {
148 JSValue result
= slot
.getValue(callFrame
, ident
);
149 exceptionValue
= callFrame
->globalData().exception
;
153 callFrame
->uncheckedR(dst
) = JSValue(result
);
156 } while (++iter
!= end
);
157 exceptionValue
= createUndefinedVariableError(callFrame
, ident
);
161 NEVER_INLINE
bool Interpreter::resolveGlobal(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
163 int dst
= vPC
[1].u
.operand
;
164 CodeBlock
* codeBlock
= callFrame
->codeBlock();
165 JSGlobalObject
* globalObject
= codeBlock
->globalObject();
166 ASSERT(globalObject
->isGlobalObject());
167 int property
= vPC
[2].u
.operand
;
168 Structure
* structure
= vPC
[3].u
.structure
.get();
169 int offset
= vPC
[4].u
.operand
;
171 if (structure
== globalObject
->structure()) {
172 callFrame
->uncheckedR(dst
) = JSValue(globalObject
->getDirectOffset(offset
));
176 Identifier
& ident
= codeBlock
->identifier(property
);
177 PropertySlot
slot(globalObject
);
178 if (globalObject
->getPropertySlot(callFrame
, ident
, slot
)) {
179 JSValue result
= slot
.getValue(callFrame
, ident
);
180 if (slot
.isCacheableValue() && !globalObject
->structure()->isUncacheableDictionary() && slot
.slotBase() == globalObject
) {
181 vPC
[3].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), globalObject
->structure());
182 vPC
[4] = slot
.cachedOffset();
183 callFrame
->uncheckedR(dst
) = JSValue(result
);
187 exceptionValue
= callFrame
->globalData().exception
;
190 callFrame
->uncheckedR(dst
) = JSValue(result
);
194 exceptionValue
= createUndefinedVariableError(callFrame
, ident
);
198 NEVER_INLINE
bool Interpreter::resolveGlobalDynamic(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
200 int dst
= vPC
[1].u
.operand
;
201 CodeBlock
* codeBlock
= callFrame
->codeBlock();
202 JSGlobalObject
* globalObject
= codeBlock
->globalObject();
203 ASSERT(globalObject
->isGlobalObject());
204 int property
= vPC
[2].u
.operand
;
205 Structure
* structure
= vPC
[3].u
.structure
.get();
206 int offset
= vPC
[4].u
.operand
;
207 int skip
= vPC
[5].u
.operand
;
209 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
210 ScopeChainIterator iter
= scopeChain
->begin();
211 ScopeChainIterator end
= scopeChain
->end();
213 bool checkTopLevel
= codeBlock
->codeType() == FunctionCode
&& codeBlock
->needsFullScopeChain();
214 ASSERT(skip
|| !checkTopLevel
);
215 if (checkTopLevel
&& skip
--) {
216 if (callFrame
->uncheckedR(codeBlock
->activationRegister()).jsValue())
220 JSObject
* o
= iter
->get();
221 if (o
->hasCustomProperties()) {
222 Identifier
& ident
= codeBlock
->identifier(property
);
224 PropertySlot
slot(o
);
225 if (o
->getPropertySlot(callFrame
, ident
, slot
)) {
226 JSValue result
= slot
.getValue(callFrame
, ident
);
227 exceptionValue
= callFrame
->globalData().exception
;
231 callFrame
->uncheckedR(dst
) = JSValue(result
);
239 exceptionValue
= createUndefinedVariableError(callFrame
, ident
);
245 if (structure
== globalObject
->structure()) {
246 callFrame
->uncheckedR(dst
) = JSValue(globalObject
->getDirectOffset(offset
));
247 ASSERT(callFrame
->uncheckedR(dst
).jsValue());
251 Identifier
& ident
= codeBlock
->identifier(property
);
252 PropertySlot
slot(globalObject
);
253 if (globalObject
->getPropertySlot(callFrame
, ident
, slot
)) {
254 JSValue result
= slot
.getValue(callFrame
, ident
);
255 if (slot
.isCacheableValue() && !globalObject
->structure()->isUncacheableDictionary() && slot
.slotBase() == globalObject
) {
256 vPC
[3].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), globalObject
->structure());
257 vPC
[4] = slot
.cachedOffset();
259 callFrame
->uncheckedR(dst
) = JSValue(result
);
263 exceptionValue
= callFrame
->globalData().exception
;
267 callFrame
->uncheckedR(dst
) = JSValue(result
);
271 exceptionValue
= createUndefinedVariableError(callFrame
, ident
);
275 NEVER_INLINE
void Interpreter::resolveBase(CallFrame
* callFrame
, Instruction
* vPC
)
277 int dst
= vPC
[1].u
.operand
;
278 int property
= vPC
[2].u
.operand
;
279 bool isStrictPut
= vPC
[3].u
.operand
;
280 Identifier ident
= callFrame
->codeBlock()->identifier(property
);
281 JSValue result
= JSC::resolveBase(callFrame
, ident
, callFrame
->scopeChain(), isStrictPut
);
283 callFrame
->uncheckedR(dst
) = result
;
284 ASSERT(callFrame
->uncheckedR(dst
).jsValue());
286 callFrame
->globalData().exception
= createErrorForInvalidGlobalAssignment(callFrame
, ident
.ustring());
289 NEVER_INLINE
bool Interpreter::resolveBaseAndProperty(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
291 int baseDst
= vPC
[1].u
.operand
;
292 int propDst
= vPC
[2].u
.operand
;
293 int property
= vPC
[3].u
.operand
;
295 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
296 ScopeChainIterator iter
= scopeChain
->begin();
297 ScopeChainIterator end
= scopeChain
->end();
299 // FIXME: add scopeDepthIsZero optimization
303 CodeBlock
* codeBlock
= callFrame
->codeBlock();
304 Identifier
& ident
= codeBlock
->identifier(property
);
308 PropertySlot
slot(base
);
309 if (base
->getPropertySlot(callFrame
, ident
, slot
)) {
310 JSValue result
= slot
.getValue(callFrame
, ident
);
311 exceptionValue
= callFrame
->globalData().exception
;
314 callFrame
->uncheckedR(propDst
) = JSValue(result
);
315 callFrame
->uncheckedR(baseDst
) = JSValue(base
);
319 } while (iter
!= end
);
321 exceptionValue
= createUndefinedVariableError(callFrame
, ident
);
325 NEVER_INLINE
bool Interpreter::resolveThisAndProperty(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
327 int thisDst
= vPC
[1].u
.operand
;
328 int propDst
= vPC
[2].u
.operand
;
329 int property
= vPC
[3].u
.operand
;
331 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
332 ScopeChainIterator iter
= scopeChain
->begin();
333 ScopeChainIterator end
= scopeChain
->end();
335 // FIXME: add scopeDepthIsZero optimization
339 CodeBlock
* codeBlock
= callFrame
->codeBlock();
340 Identifier
& ident
= codeBlock
->identifier(property
);
345 PropertySlot
slot(base
);
346 if (base
->getPropertySlot(callFrame
, ident
, slot
)) {
347 JSValue result
= slot
.getValue(callFrame
, ident
);
348 exceptionValue
= callFrame
->globalData().exception
;
351 callFrame
->uncheckedR(propDst
) = JSValue(result
);
352 // All entries on the scope chain should be EnvironmentRecords (activations etc),
353 // other then 'with' object, which are directly referenced from the scope chain,
354 // and the global object. If we hit either an EnvironmentRecord or a global
355 // object at the end of the scope chain, this is undefined. If we hit a non-
356 // EnvironmentRecord within the scope chain, pass the base as the this value.
357 if (iter
== end
|| base
->structure()->typeInfo().isEnvironmentRecord())
358 callFrame
->uncheckedR(thisDst
) = jsUndefined();
360 callFrame
->uncheckedR(thisDst
) = JSValue(base
);
363 } while (iter
!= end
);
365 exceptionValue
= createUndefinedVariableError(callFrame
, ident
);
369 #endif // ENABLE(CLASSIC_INTERPRETER)
371 ALWAYS_INLINE CallFrame
* Interpreter::slideRegisterWindowForCall(CodeBlock
* newCodeBlock
, RegisterFile
* registerFile
, CallFrame
* callFrame
, size_t registerOffset
, int argumentCountIncludingThis
)
373 // This ensures enough space for the worst case scenario of zero arguments passed by the caller.
374 if (!registerFile
->grow(callFrame
->registers() + registerOffset
+ newCodeBlock
->numParameters() + newCodeBlock
->m_numCalleeRegisters
))
377 if (argumentCountIncludingThis
>= newCodeBlock
->numParameters()) {
378 Register
* newCallFrame
= callFrame
->registers() + registerOffset
;
379 return CallFrame::create(newCallFrame
);
382 // Too few arguments -- copy arguments, then fill in missing arguments with undefined.
383 size_t delta
= newCodeBlock
->numParameters() - argumentCountIncludingThis
;
384 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
+ delta
);
386 Register
* dst
= &newCallFrame
->uncheckedR(CallFrame::thisArgumentOffset());
387 Register
* end
= dst
- argumentCountIncludingThis
;
388 for ( ; dst
!= end
; --dst
)
389 *dst
= *(dst
- delta
);
392 for ( ; dst
!= end
; --dst
)
393 *dst
= jsUndefined();
398 #if ENABLE(CLASSIC_INTERPRETER)
399 static NEVER_INLINE
bool isInvalidParamForIn(CallFrame
* callFrame
, JSValue value
, JSValue
& exceptionData
)
401 if (value
.isObject())
403 exceptionData
= createInvalidParamError(callFrame
, "in" , value
);
407 static NEVER_INLINE
bool isInvalidParamForInstanceOf(CallFrame
* callFrame
, JSValue value
, JSValue
& exceptionData
)
409 if (value
.isObject() && asObject(value
)->structure()->typeInfo().implementsHasInstance())
411 exceptionData
= createInvalidParamError(callFrame
, "instanceof" , value
);
416 JSValue
eval(CallFrame
* callFrame
)
418 if (!callFrame
->argumentCount())
419 return jsUndefined();
421 JSValue program
= callFrame
->argument(0);
422 if (!program
.isString())
425 TopCallFrameSetter
topCallFrame(callFrame
->globalData(), callFrame
);
426 UString programSource
= asString(program
)->value(callFrame
);
427 if (callFrame
->hadException())
430 CallFrame
* callerFrame
= callFrame
->callerFrame();
431 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
432 ScopeChainNode
* callerScopeChain
= callerFrame
->scopeChain();
433 EvalExecutable
* eval
= callerCodeBlock
->evalCodeCache().tryGet(callerCodeBlock
->isStrictMode(), programSource
, callerScopeChain
);
436 if (!callerCodeBlock
->isStrictMode()) {
437 // FIXME: We can use the preparser in strict mode, we just need additional logic
438 // to prevent duplicates.
439 if (programSource
.is8Bit()) {
440 LiteralParser
<LChar
> preparser(callFrame
, programSource
.characters8(), programSource
.length(), NonStrictJSON
);
441 if (JSValue parsedObject
= preparser
.tryLiteralParse())
444 LiteralParser
<UChar
> preparser(callFrame
, programSource
.characters16(), programSource
.length(), NonStrictJSON
);
445 if (JSValue parsedObject
= preparser
.tryLiteralParse())
450 JSValue exceptionValue
;
451 eval
= callerCodeBlock
->evalCodeCache().getSlow(callFrame
, callerCodeBlock
->ownerExecutable(), callerCodeBlock
->isStrictMode(), programSource
, callerScopeChain
, exceptionValue
);
453 ASSERT(!eval
== exceptionValue
);
455 return throwError(callFrame
, exceptionValue
);
458 JSValue thisValue
= callerFrame
->thisValue();
459 ASSERT(isValidThisObject(thisValue
, callFrame
));
460 Interpreter
* interpreter
= callFrame
->globalData().interpreter
;
461 return interpreter
->execute(eval
, callFrame
, thisValue
, callerScopeChain
, callFrame
->registers() - interpreter
->registerFile().begin() + 1 + RegisterFile::CallFrameHeaderSize
);
464 CallFrame
* loadVarargs(CallFrame
* callFrame
, RegisterFile
* registerFile
, JSValue thisValue
, JSValue arguments
, int firstFreeRegister
)
466 if (!arguments
) { // f.apply(x, arguments), with arguments unmodified.
467 unsigned argumentCountIncludingThis
= callFrame
->argumentCountIncludingThis();
468 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ argumentCountIncludingThis
+ RegisterFile::CallFrameHeaderSize
);
469 if (argumentCountIncludingThis
> Arguments::MaxArguments
+ 1 || !registerFile
->grow(newCallFrame
->registers())) {
470 callFrame
->globalData().exception
= createStackOverflowError(callFrame
);
474 newCallFrame
->setArgumentCountIncludingThis(argumentCountIncludingThis
);
475 newCallFrame
->setThisValue(thisValue
);
476 for (size_t i
= 0; i
< callFrame
->argumentCount(); ++i
)
477 newCallFrame
->setArgument(i
, callFrame
->argument(i
));
481 if (arguments
.isUndefinedOrNull()) {
482 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ 1 + RegisterFile::CallFrameHeaderSize
);
483 if (!registerFile
->grow(newCallFrame
->registers())) {
484 callFrame
->globalData().exception
= createStackOverflowError(callFrame
);
487 newCallFrame
->setArgumentCountIncludingThis(1);
488 newCallFrame
->setThisValue(thisValue
);
492 if (!arguments
.isObject()) {
493 callFrame
->globalData().exception
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
);
497 if (asObject(arguments
)->classInfo() == &Arguments::s_info
) {
498 Arguments
* argsObject
= asArguments(arguments
);
499 unsigned argCount
= argsObject
->length(callFrame
);
500 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ CallFrame::offsetFor(argCount
+ 1));
501 if (argCount
> Arguments::MaxArguments
|| !registerFile
->grow(newCallFrame
->registers())) {
502 callFrame
->globalData().exception
= createStackOverflowError(callFrame
);
505 newCallFrame
->setArgumentCountIncludingThis(argCount
+ 1);
506 newCallFrame
->setThisValue(thisValue
);
507 argsObject
->copyToArguments(callFrame
, newCallFrame
, argCount
);
511 if (isJSArray(arguments
)) {
512 JSArray
* array
= asArray(arguments
);
513 unsigned argCount
= array
->length();
514 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ CallFrame::offsetFor(argCount
+ 1));
515 if (argCount
> Arguments::MaxArguments
|| !registerFile
->grow(newCallFrame
->registers())) {
516 callFrame
->globalData().exception
= createStackOverflowError(callFrame
);
519 newCallFrame
->setArgumentCountIncludingThis(argCount
+ 1);
520 newCallFrame
->setThisValue(thisValue
);
521 array
->copyToArguments(callFrame
, newCallFrame
, argCount
);
525 JSObject
* argObject
= asObject(arguments
);
526 unsigned argCount
= argObject
->get(callFrame
, callFrame
->propertyNames().length
).toUInt32(callFrame
);
527 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ CallFrame::offsetFor(argCount
+ 1));
528 if (argCount
> Arguments::MaxArguments
|| !registerFile
->grow(newCallFrame
->registers())) {
529 callFrame
->globalData().exception
= createStackOverflowError(callFrame
);
532 newCallFrame
->setArgumentCountIncludingThis(argCount
+ 1);
533 newCallFrame
->setThisValue(thisValue
);
534 for (size_t i
= 0; i
< argCount
; ++i
) {
535 newCallFrame
->setArgument(i
, asObject(arguments
)->get(callFrame
, i
));
536 if (UNLIKELY(callFrame
->globalData().exception
))
542 Interpreter::Interpreter()
543 : m_sampleEntryDepth(0)
546 , m_initialized(false)
548 , m_classicEnabled(false)
552 Interpreter::~Interpreter()
555 if (m_classicEnabled
)
556 delete[] m_opcodeTable
;
560 void Interpreter::initialize(LLInt::Data
* llintData
, bool canUseJIT
)
562 UNUSED_PARAM(llintData
);
563 UNUSED_PARAM(canUseJIT
);
565 // If we have LLInt, then we shouldn't be building any kind of classic interpreter.
566 #if ENABLE(LLINT) && ENABLE(CLASSIC_INTERPRETER)
567 #error "Building both LLInt and the Classic Interpreter is not supported because it doesn't make sense."
571 m_opcodeTable
= llintData
->opcodeMap();
572 for (int i
= 0; i
< numOpcodeIDs
; ++i
)
573 m_opcodeIDTable
.add(m_opcodeTable
[i
], static_cast<OpcodeID
>(i
));
574 m_classicEnabled
= false;
575 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
577 // If the JIT is present, don't use jump destinations for opcodes.
579 for (int i
= 0; i
< numOpcodeIDs
; ++i
) {
580 Opcode opcode
= bitwise_cast
<void*>(static_cast<uintptr_t>(i
));
581 m_opcodeTable
[i
] = opcode
;
583 m_classicEnabled
= false;
585 privateExecute(InitializeAndReturn
, 0, 0);
587 for (int i
= 0; i
< numOpcodeIDs
; ++i
)
588 m_opcodeIDTable
.add(m_opcodeTable
[i
], static_cast<OpcodeID
>(i
));
590 m_classicEnabled
= true;
593 #if ENABLE(CLASSIC_INTERPRETER)
594 m_classicEnabled
= true;
596 m_classicEnabled
= false;
598 #endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
600 m_initialized
= true;
603 #if ENABLE(OPCODE_SAMPLING)
610 void Interpreter::dumpCallFrame(CallFrame
* callFrame
)
612 callFrame
->codeBlock()->dump(callFrame
);
613 dumpRegisters(callFrame
);
616 void Interpreter::dumpRegisters(CallFrame
* callFrame
)
618 dataLog("Register frame: \n\n");
619 dataLog("-----------------------------------------------------------------------------\n");
620 dataLog(" use | address | value \n");
621 dataLog("-----------------------------------------------------------------------------\n");
623 CodeBlock
* codeBlock
= callFrame
->codeBlock();
628 it
= callFrame
->registers() - RegisterFile::CallFrameHeaderSize
- codeBlock
->numParameters();
630 #if USE(JSVALUE32_64)
631 dataLog("[this] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
)); ++it
;
633 dataLog("[this] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
)); ++it
;
635 end
= it
+ max(codeBlock
->numParameters() - 1, 0); // - 1 to skip "this"
639 #if USE(JSVALUE32_64)
640 dataLog("[param] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
));
642 dataLog("[param] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
));
647 dataLog("-----------------------------------------------------------------------------\n");
648 dataLog("[CodeBlock] | %10p | %p \n", it
, (*it
).codeBlock()); ++it
;
649 dataLog("[ScopeChain] | %10p | %p \n", it
, (*it
).scopeChain()); ++it
;
650 dataLog("[CallerRegisters] | %10p | %d \n", it
, (*it
).i()); ++it
;
651 dataLog("[ReturnPC] | %10p | %p \n", it
, (*it
).vPC()); ++it
;
652 dataLog("[ArgumentCount] | %10p | %d \n", it
, (*it
).i()); ++it
;
653 dataLog("[Callee] | %10p | %p \n", it
, (*it
).function()); ++it
;
654 dataLog("-----------------------------------------------------------------------------\n");
656 int registerCount
= 0;
658 end
= it
+ codeBlock
->m_numVars
;
662 #if USE(JSVALUE32_64)
663 dataLog("[r%2d] | %10p | %-16s 0x%llx \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
665 dataLog("[r%2d] | %10p | %-16s %p \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
671 dataLog("-----------------------------------------------------------------------------\n");
673 end
= it
+ codeBlock
->m_numCalleeRegisters
- codeBlock
->m_numVars
;
677 #if USE(JSVALUE32_64)
678 dataLog("[r%2d] | %10p | %-16s 0x%llx \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
680 dataLog("[r%2d] | %10p | %-16s %p \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
686 dataLog("-----------------------------------------------------------------------------\n");
691 bool Interpreter::isOpcode(Opcode opcode
)
693 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)
695 if (!m_classicEnabled
)
696 return opcode
>= 0 && static_cast<OpcodeID
>(bitwise_cast
<uintptr_t>(opcode
)) <= op_end
;
698 return opcode
!= HashTraits
<Opcode
>::emptyValue()
699 && !HashTraits
<Opcode
>::isDeletedValue(opcode
)
700 && m_opcodeIDTable
.contains(opcode
);
702 return opcode
>= 0 && opcode
<= op_end
;
706 NEVER_INLINE
bool Interpreter::unwindCallFrame(CallFrame
*& callFrame
, JSValue exceptionValue
, unsigned& bytecodeOffset
, CodeBlock
*& codeBlock
)
708 CodeBlock
* oldCodeBlock
= codeBlock
;
709 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
711 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
712 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
713 if (callFrame
->callee())
714 debugger
->returnEvent(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->lastLine());
716 debugger
->didExecuteProgram(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->lastLine());
719 // If this call frame created an activation or an 'arguments' object, tear it off.
720 if (oldCodeBlock
->codeType() == FunctionCode
&& oldCodeBlock
->needsFullScopeChain()) {
721 if (!callFrame
->uncheckedR(oldCodeBlock
->activationRegister()).jsValue()) {
722 oldCodeBlock
->createActivation(callFrame
);
723 scopeChain
= callFrame
->scopeChain();
725 while (!scopeChain
->object
->inherits(&JSActivation::s_info
))
726 scopeChain
= scopeChain
->pop();
728 callFrame
->setScopeChain(scopeChain
);
729 JSActivation
* activation
= asActivation(scopeChain
->object
.get());
730 activation
->tearOff(*scopeChain
->globalData
);
731 if (JSValue arguments
= callFrame
->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock
->argumentsRegister())).jsValue())
732 asArguments(arguments
)->didTearOffActivation(callFrame
->globalData(), activation
);
733 } else if (oldCodeBlock
->usesArguments() && !oldCodeBlock
->isStrictMode()) {
734 if (JSValue arguments
= callFrame
->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock
->argumentsRegister())).jsValue())
735 asArguments(arguments
)->tearOff(callFrame
);
738 CallFrame
* callerFrame
= callFrame
->callerFrame();
739 callFrame
->globalData().topCallFrame
= callerFrame
;
740 if (callerFrame
->hasHostCallFrameFlag())
743 codeBlock
= callerFrame
->codeBlock();
745 // Because of how the JIT records call site->bytecode offset
746 // information the JIT reports the bytecodeOffset for the returnPC
747 // to be at the beginning of the opcode that has caused the call.
748 // In the interpreter we have an actual return address, which is
749 // the beginning of next instruction to execute. To get an offset
750 // inside the call instruction that triggered the exception we
751 // have to subtract 1.
752 #if ENABLE(JIT) && ENABLE(CLASSIC_INTERPRETER)
753 if (callerFrame
->globalData().canUseJIT())
754 bytecodeOffset
= codeBlock
->bytecodeOffset(callerFrame
, callFrame
->returnPC());
756 bytecodeOffset
= codeBlock
->bytecodeOffset(callFrame
->returnVPC()) - 1;
758 bytecodeOffset
= codeBlock
->bytecodeOffset(callerFrame
, callFrame
->returnPC());
760 bytecodeOffset
= codeBlock
->bytecodeOffset(callFrame
->returnVPC()) - 1;
763 callFrame
= callerFrame
;
767 static void appendSourceToError(CallFrame
* callFrame
, ErrorInstance
* exception
, unsigned bytecodeOffset
)
769 exception
->clearAppendSourceToMessage();
771 if (!callFrame
->codeBlock()->hasExpressionInfo())
778 CodeBlock
* codeBlock
= callFrame
->codeBlock();
779 codeBlock
->expressionRangeForBytecodeOffset(bytecodeOffset
, divotPoint
, startOffset
, endOffset
);
781 int expressionStart
= divotPoint
- startOffset
;
782 int expressionStop
= divotPoint
+ endOffset
;
784 if (!expressionStop
|| expressionStart
> codeBlock
->source()->length())
787 JSGlobalData
* globalData
= &callFrame
->globalData();
788 JSValue jsMessage
= exception
->getDirect(*globalData
, globalData
->propertyNames
->message
);
789 if (!jsMessage
|| !jsMessage
.isString())
792 UString message
= asString(jsMessage
)->value(callFrame
);
794 if (expressionStart
< expressionStop
)
795 message
= makeUString(message
, " (evaluating '", codeBlock
->source()->getRange(expressionStart
, expressionStop
), "')");
797 // No range information, so give a few characters of context
798 const StringImpl
* data
= codeBlock
->source()->data();
799 int dataLength
= codeBlock
->source()->length();
800 int start
= expressionStart
;
801 int stop
= expressionStart
;
802 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
803 // then strip whitespace.
804 while (start
> 0 && (expressionStart
- start
< 20) && (*data
)[start
- 1] != '\n')
806 while (start
< (expressionStart
- 1) && isStrWhiteSpace((*data
)[start
]))
808 while (stop
< dataLength
&& (stop
- expressionStart
< 20) && (*data
)[stop
] != '\n')
810 while (stop
> expressionStart
&& isStrWhiteSpace((*data
)[stop
- 1]))
812 message
= makeUString(message
, " (near '...", codeBlock
->source()->getRange(start
, stop
), "...')");
815 exception
->putDirect(*globalData
, globalData
->propertyNames
->message
, jsString(globalData
, message
));
818 static int getLineNumberForCallFrame(JSGlobalData
* globalData
, CallFrame
* callFrame
)
820 UNUSED_PARAM(globalData
);
821 callFrame
= callFrame
->removeHostCallFrameFlag();
822 CodeBlock
* codeBlock
= callFrame
->codeBlock();
825 #if ENABLE(CLASSIC_INTERPRETER)
826 if (!globalData
->canUseJIT())
827 return codeBlock
->lineNumberForBytecodeOffset(callFrame
->bytecodeOffsetForNonDFGCode() - 1);
831 if (codeBlock
->getJITType() == JITCode::DFGJIT
)
832 return codeBlock
->lineNumberForBytecodeOffset(codeBlock
->codeOrigin(callFrame
->codeOriginIndexForDFG()).bytecodeIndex
);
834 return codeBlock
->lineNumberForBytecodeOffset(callFrame
->bytecodeOffsetForNonDFGCode());
840 static CallFrame
* getCallerInfo(JSGlobalData
* globalData
, CallFrame
* callFrame
, int& lineNumber
)
842 UNUSED_PARAM(globalData
);
843 unsigned bytecodeOffset
= 0;
845 ASSERT(!callFrame
->hasHostCallFrameFlag());
846 CallFrame
* callerFrame
= callFrame
->codeBlock() ? callFrame
->trueCallerFrame() : callFrame
->callerFrame()->removeHostCallFrameFlag();
847 bool callframeIsHost
= callerFrame
->addHostCallFrameFlag() == callFrame
->callerFrame();
848 ASSERT(!callerFrame
->hasHostCallFrameFlag());
850 if (callerFrame
== CallFrame::noCaller() || !callerFrame
|| !callerFrame
->codeBlock())
853 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
856 if (!callFrame
->hasReturnPC())
857 callframeIsHost
= true;
860 if (callFrame
->isInlineCallFrame())
861 callframeIsHost
= false;
864 if (callframeIsHost
) {
865 // Don't need to deal with inline callframes here as by definition we haven't
866 // inlined a call with an intervening native call frame.
867 #if ENABLE(CLASSIC_INTERPRETER)
868 if (!globalData
->canUseJIT()) {
869 bytecodeOffset
= callerFrame
->bytecodeOffsetForNonDFGCode();
870 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
- 1);
876 if (callerCodeBlock
&& callerCodeBlock
->getJITType() == JITCode::DFGJIT
) {
877 unsigned codeOriginIndex
= callerFrame
->codeOriginIndexForDFG();
878 bytecodeOffset
= callerCodeBlock
->codeOrigin(codeOriginIndex
).bytecodeIndex
;
881 bytecodeOffset
= callerFrame
->bytecodeOffsetForNonDFGCode();
884 #if ENABLE(CLASSIC_INTERPRETER)
885 if (!globalData
->canUseJIT()) {
886 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callFrame
->returnVPC());
887 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
- 1);
893 if (callFrame
->isInlineCallFrame()) {
894 InlineCallFrame
* icf
= callFrame
->inlineCallFrame();
895 bytecodeOffset
= icf
->caller
.bytecodeIndex
;
896 if (InlineCallFrame
* parentCallFrame
= icf
->caller
.inlineCallFrame
) {
897 FunctionExecutable
* executable
= static_cast<FunctionExecutable
*>(parentCallFrame
->executable
.get());
898 CodeBlock
* newCodeBlock
= executable
->baselineCodeBlockFor(parentCallFrame
->isCall
? CodeForCall
: CodeForConstruct
);
899 ASSERT(newCodeBlock
);
900 ASSERT(newCodeBlock
->instructionCount() > bytecodeOffset
);
901 callerCodeBlock
= newCodeBlock
;
903 } else if (callerCodeBlock
&& callerCodeBlock
->getJITType() == JITCode::DFGJIT
) {
905 if (!callerCodeBlock
->codeOriginForReturn(callFrame
->returnPC(), origin
))
906 ASSERT_NOT_REACHED();
907 bytecodeOffset
= origin
.bytecodeIndex
;
908 if (InlineCallFrame
* icf
= origin
.inlineCallFrame
) {
909 FunctionExecutable
* executable
= static_cast<FunctionExecutable
*>(icf
->executable
.get());
910 CodeBlock
* newCodeBlock
= executable
->baselineCodeBlockFor(icf
->isCall
? CodeForCall
: CodeForConstruct
);
911 ASSERT(newCodeBlock
);
912 ASSERT(newCodeBlock
->instructionCount() > bytecodeOffset
);
913 callerCodeBlock
= newCodeBlock
;
917 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callerFrame
, callFrame
->returnPC());
921 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
);
925 static ALWAYS_INLINE
const UString
getSourceURLFromCallFrame(CallFrame
* callFrame
)
927 ASSERT(!callFrame
->hasHostCallFrameFlag());
928 #if ENABLE(CLASSIC_INTERPRETER)
930 if (callFrame
->globalData().canUseJIT())
931 return callFrame
->codeBlock()->ownerExecutable()->sourceURL();
933 return callFrame
->codeBlock()->source()->url();
936 return callFrame
->codeBlock()->ownerExecutable()->sourceURL();
940 static StackFrameCodeType
getStackFrameCodeType(CallFrame
* callFrame
)
942 ASSERT(!callFrame
->hasHostCallFrameFlag());
944 switch (callFrame
->codeBlock()->codeType()) {
946 return StackFrameEvalCode
;
948 return StackFrameFunctionCode
;
950 return StackFrameGlobalCode
;
952 ASSERT_NOT_REACHED();
953 return StackFrameGlobalCode
;
956 void Interpreter::getStackTrace(JSGlobalData
* globalData
, Vector
<StackFrame
>& results
)
958 CallFrame
* callFrame
= globalData
->topCallFrame
->removeHostCallFrameFlag();
959 if (!callFrame
|| callFrame
== CallFrame::noCaller())
961 int line
= getLineNumberForCallFrame(globalData
, callFrame
);
963 callFrame
= callFrame
->trueCallFrameFromVMCode();
965 while (callFrame
&& callFrame
!= CallFrame::noCaller()) {
967 if (callFrame
->codeBlock()) {
968 sourceURL
= getSourceURLFromCallFrame(callFrame
);
969 StackFrame s
= { Strong
<JSObject
>(*globalData
, callFrame
->callee()), getStackFrameCodeType(callFrame
), Strong
<ExecutableBase
>(*globalData
, callFrame
->codeBlock()->ownerExecutable()), line
, sourceURL
};
972 StackFrame s
= { Strong
<JSObject
>(*globalData
, callFrame
->callee()), StackFrameNativeCode
, Strong
<ExecutableBase
>(), -1, UString()};
975 callFrame
= getCallerInfo(globalData
, callFrame
, line
);
979 void Interpreter::addStackTraceIfNecessary(CallFrame
* callFrame
, JSObject
* error
)
981 JSGlobalData
* globalData
= &callFrame
->globalData();
982 ASSERT(callFrame
== globalData
->topCallFrame
|| callFrame
== callFrame
->lexicalGlobalObject()->globalExec() || callFrame
== callFrame
->dynamicGlobalObject()->globalExec());
983 if (error
->hasProperty(callFrame
, globalData
->propertyNames
->stack
))
986 Vector
<StackFrame
> stackTrace
;
987 getStackTrace(&callFrame
->globalData(), stackTrace
);
989 if (stackTrace
.isEmpty())
992 JSGlobalObject
* globalObject
= 0;
993 if (isTerminatedExecutionException(error
) || isInterruptedExecutionException(error
))
994 globalObject
= globalData
->dynamicGlobalObject
;
996 globalObject
= error
->globalObject();
997 StringBuilder builder
;
998 for (unsigned i
= 0; i
< stackTrace
.size(); i
++) {
999 builder
.append(String(stackTrace
[i
].toString(globalObject
->globalExec()).impl()));
1000 if (i
!= stackTrace
.size() - 1)
1001 builder
.append('\n');
1004 error
->putDirect(*globalData
, globalData
->propertyNames
->stack
, jsString(globalData
, UString(builder
.toString().impl())), ReadOnly
| DontDelete
);
1007 NEVER_INLINE HandlerInfo
* Interpreter::throwException(CallFrame
*& callFrame
, JSValue
& exceptionValue
, unsigned bytecodeOffset
)
1009 CodeBlock
* codeBlock
= callFrame
->codeBlock();
1010 bool isInterrupt
= false;
1012 ASSERT(!exceptionValue
.isEmpty());
1013 ASSERT(!exceptionValue
.isCell() || exceptionValue
.asCell());
1014 // This shouldn't be possible (hence the assertions), but we're already in the slowest of
1015 // slow cases, so let's harden against it anyway to be safe.
1016 if (exceptionValue
.isEmpty() || (exceptionValue
.isCell() && !exceptionValue
.asCell()))
1017 exceptionValue
= jsNull();
1019 // Set up the exception object
1020 if (exceptionValue
.isObject()) {
1021 JSObject
* exception
= asObject(exceptionValue
);
1023 if (exception
->isErrorInstance() && static_cast<ErrorInstance
*>(exception
)->appendSourceToMessage())
1024 appendSourceToError(callFrame
, static_cast<ErrorInstance
*>(exception
), bytecodeOffset
);
1026 if (!hasErrorInfo(callFrame
, exception
)) {
1027 // FIXME: should only really be adding these properties to VM generated exceptions,
1028 // but the inspector currently requires these for all thrown objects.
1029 addErrorInfo(callFrame
, exception
, codeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
), codeBlock
->ownerExecutable()->source());
1032 isInterrupt
= isInterruptedExecutionException(exception
) || isTerminatedExecutionException(exception
);
1035 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
1036 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
1037 bool hasHandler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
);
1038 debugger
->exception(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
), hasHandler
);
1041 // Calculate an exception handler vPC, unwinding call frames as necessary.
1042 HandlerInfo
* handler
= 0;
1043 while (isInterrupt
|| !(handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
))) {
1044 if (!unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
)) {
1045 if (Profiler
* profiler
= *Profiler::enabledProfilerReference())
1046 profiler
->exceptionUnwind(callFrame
);
1047 callFrame
->globalData().topCallFrame
= callFrame
;
1051 callFrame
->globalData().topCallFrame
= callFrame
;
1053 if (Profiler
* profiler
= *Profiler::enabledProfilerReference())
1054 profiler
->exceptionUnwind(callFrame
);
1056 // Shrink the JS stack, in case stack overflow made it huge.
1057 Register
* highWaterMark
= 0;
1058 for (CallFrame
* callerFrame
= callFrame
; callerFrame
; callerFrame
= callerFrame
->callerFrame()->removeHostCallFrameFlag()) {
1059 CodeBlock
* codeBlock
= callerFrame
->codeBlock();
1062 Register
* callerHighWaterMark
= callerFrame
->registers() + codeBlock
->m_numCalleeRegisters
;
1063 highWaterMark
= max(highWaterMark
, callerHighWaterMark
);
1065 m_registerFile
.shrink(highWaterMark
);
1067 // Unwind the scope chain within the exception handler's call frame.
1068 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
1070 if (!codeBlock
->needsFullScopeChain() || codeBlock
->codeType() != FunctionCode
1071 || callFrame
->uncheckedR(codeBlock
->activationRegister()).jsValue())
1072 scopeDelta
= depth(codeBlock
, scopeChain
) - handler
->scopeDepth
;
1073 ASSERT(scopeDelta
>= 0);
1074 while (scopeDelta
--)
1075 scopeChain
= scopeChain
->pop();
1076 callFrame
->setScopeChain(scopeChain
);
1081 static inline JSValue
checkedReturn(JSValue returnValue
)
1083 ASSERT(returnValue
);
1087 static inline JSObject
* checkedReturn(JSObject
* returnValue
)
1089 ASSERT(returnValue
);
1093 JSValue
Interpreter::execute(ProgramExecutable
* program
, CallFrame
* callFrame
, ScopeChainNode
* scopeChain
, JSObject
* thisObj
)
1095 ASSERT(isValidThisObject(thisObj
, callFrame
));
1096 ASSERT(!scopeChain
->globalData
->exception
);
1097 ASSERT(!callFrame
->globalData().isCollectorBusy());
1098 if (callFrame
->globalData().isCollectorBusy())
1101 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
&& m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
)
1102 return checkedReturn(throwStackOverflowError(callFrame
));
1104 DynamicGlobalObjectScope
globalObjectScope(*scopeChain
->globalData
, scopeChain
->globalObject
.get());
1105 Vector
<JSONPData
> JSONPData
;
1107 const UString programSource
= program
->source().toString();
1108 if (programSource
.isNull())
1109 return jsUndefined();
1110 if (programSource
.is8Bit()) {
1111 LiteralParser
<LChar
> literalParser(callFrame
, programSource
.characters8(), programSource
.length(), JSONP
);
1112 parseResult
= literalParser
.tryJSONPParse(JSONPData
, scopeChain
->globalObject
->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain
->globalObject
.get()));
1114 LiteralParser
<UChar
> literalParser(callFrame
, programSource
.characters16(), programSource
.length(), JSONP
);
1115 parseResult
= literalParser
.tryJSONPParse(JSONPData
, scopeChain
->globalObject
->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain
->globalObject
.get()));
1119 JSGlobalObject
* globalObject
= scopeChain
->globalObject
.get();
1121 for (unsigned entry
= 0; entry
< JSONPData
.size(); entry
++) {
1122 Vector
<JSONPPathEntry
> JSONPPath
;
1123 JSONPPath
.swap(JSONPData
[entry
].m_path
);
1124 JSValue JSONPValue
= JSONPData
[entry
].m_value
.get();
1125 if (JSONPPath
.size() == 1 && JSONPPath
[0].m_type
== JSONPPathEntryTypeDeclare
) {
1126 if (globalObject
->hasProperty(callFrame
, JSONPPath
[0].m_pathEntryName
)) {
1127 PutPropertySlot slot
;
1128 globalObject
->methodTable()->put(globalObject
, callFrame
, JSONPPath
[0].m_pathEntryName
, JSONPValue
, slot
);
1130 globalObject
->methodTable()->putDirectVirtual(globalObject
, callFrame
, JSONPPath
[0].m_pathEntryName
, JSONPValue
, DontEnum
| DontDelete
);
1131 // var declarations return undefined
1132 result
= jsUndefined();
1135 JSValue
baseObject(globalObject
);
1136 for (unsigned i
= 0; i
< JSONPPath
.size() - 1; i
++) {
1137 ASSERT(JSONPPath
[i
].m_type
!= JSONPPathEntryTypeDeclare
);
1138 switch (JSONPPath
[i
].m_type
) {
1139 case JSONPPathEntryTypeDot
: {
1141 PropertySlot
slot(globalObject
);
1142 if (!globalObject
->getPropertySlot(callFrame
, JSONPPath
[i
].m_pathEntryName
, slot
)) {
1144 return throwError(callFrame
, createUndefinedVariableError(globalObject
->globalExec(), JSONPPath
[i
].m_pathEntryName
));
1147 baseObject
= slot
.getValue(callFrame
, JSONPPath
[i
].m_pathEntryName
);
1149 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathEntryName
);
1150 if (callFrame
->hadException())
1151 return jsUndefined();
1154 case JSONPPathEntryTypeLookup
: {
1155 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathIndex
);
1156 if (callFrame
->hadException())
1157 return jsUndefined();
1161 ASSERT_NOT_REACHED();
1162 return jsUndefined();
1165 PutPropertySlot slot
;
1166 switch (JSONPPath
.last().m_type
) {
1167 case JSONPPathEntryTypeCall
: {
1168 JSValue function
= baseObject
.get(callFrame
, JSONPPath
.last().m_pathEntryName
);
1169 if (callFrame
->hadException())
1170 return jsUndefined();
1172 CallType callType
= getCallData(function
, callData
);
1173 if (callType
== CallTypeNone
)
1174 return throwError(callFrame
, createNotAFunctionError(callFrame
, function
));
1175 MarkedArgumentBuffer jsonArg
;
1176 jsonArg
.append(JSONPValue
);
1177 JSValue thisValue
= JSONPPath
.size() == 1 ? jsUndefined(): baseObject
;
1178 JSONPValue
= JSC::call(callFrame
, function
, callType
, callData
, thisValue
, jsonArg
);
1179 if (callFrame
->hadException())
1180 return jsUndefined();
1183 case JSONPPathEntryTypeDot
: {
1184 baseObject
.put(callFrame
, JSONPPath
.last().m_pathEntryName
, JSONPValue
, slot
);
1185 if (callFrame
->hadException())
1186 return jsUndefined();
1189 case JSONPPathEntryTypeLookup
: {
1190 baseObject
.putByIndex(callFrame
, JSONPPath
.last().m_pathIndex
, JSONPValue
, slot
.isStrictMode());
1191 if (callFrame
->hadException())
1192 return jsUndefined();
1196 ASSERT_NOT_REACHED();
1197 return jsUndefined();
1199 result
= JSONPValue
;
1204 JSObject
* error
= program
->compile(callFrame
, scopeChain
);
1206 return checkedReturn(throwError(callFrame
, error
));
1207 CodeBlock
* codeBlock
= &program
->generatedBytecode();
1209 Register
* oldEnd
= m_registerFile
.end();
1210 Register
* newEnd
= oldEnd
+ codeBlock
->numParameters() + RegisterFile::CallFrameHeaderSize
+ codeBlock
->m_numCalleeRegisters
;
1211 if (!m_registerFile
.grow(newEnd
))
1212 return checkedReturn(throwStackOverflowError(callFrame
));
1214 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
+ codeBlock
->numParameters() + RegisterFile::CallFrameHeaderSize
);
1215 ASSERT(codeBlock
->numParameters() == 1); // 1 parameter for 'this'.
1216 newCallFrame
->init(codeBlock
, 0, scopeChain
, CallFrame::noCaller(), codeBlock
->numParameters(), 0);
1217 newCallFrame
->setThisValue(thisObj
);
1218 TopCallFrameSetter
topCallFrame(callFrame
->globalData(), newCallFrame
);
1220 Profiler
** profiler
= Profiler::enabledProfilerReference();
1222 (*profiler
)->willExecute(callFrame
, program
->sourceURL(), program
->lineNo());
1226 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1230 if (!classicEnabled())
1231 result
= program
->generatedJITCode().execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
);
1234 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
);
1240 (*profiler
)->didExecute(callFrame
, program
->sourceURL(), program
->lineNo());
1242 m_registerFile
.shrink(oldEnd
);
1244 return checkedReturn(result
);
1247 JSValue
Interpreter::executeCall(CallFrame
* callFrame
, JSObject
* function
, CallType callType
, const CallData
& callData
, JSValue thisValue
, const ArgList
& args
)
1249 ASSERT(isValidThisObject(thisValue
, callFrame
));
1250 ASSERT(!callFrame
->hadException());
1251 ASSERT(!callFrame
->globalData().isCollectorBusy());
1252 if (callFrame
->globalData().isCollectorBusy())
1255 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
&& m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
)
1256 return checkedReturn(throwStackOverflowError(callFrame
));
1258 Register
* oldEnd
= m_registerFile
.end();
1259 ASSERT(callFrame
->frameExtent() <= oldEnd
|| callFrame
== callFrame
->scopeChain()->globalObject
->globalExec());
1260 int argCount
= 1 + args
.size(); // implicit "this" parameter
1261 size_t registerOffset
= argCount
+ RegisterFile::CallFrameHeaderSize
;
1263 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
+ registerOffset
);
1264 if (!m_registerFile
.grow(newCallFrame
->registers()))
1265 return checkedReturn(throwStackOverflowError(callFrame
));
1267 newCallFrame
->setThisValue(thisValue
);
1268 for (size_t i
= 0; i
< args
.size(); ++i
)
1269 newCallFrame
->setArgument(i
, args
.at(i
));
1271 if (callType
== CallTypeJS
) {
1272 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
1274 DynamicGlobalObjectScope
globalObjectScope(*callDataScopeChain
->globalData
, callDataScopeChain
->globalObject
.get());
1276 JSObject
* compileError
= callData
.js
.functionExecutable
->compileForCall(callFrame
, callDataScopeChain
);
1277 if (UNLIKELY(!!compileError
)) {
1278 m_registerFile
.shrink(oldEnd
);
1279 return checkedReturn(throwError(callFrame
, compileError
));
1282 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->generatedBytecodeForCall();
1283 newCallFrame
= slideRegisterWindowForCall(newCodeBlock
, &m_registerFile
, newCallFrame
, 0, argCount
);
1284 if (UNLIKELY(!newCallFrame
)) {
1285 m_registerFile
.shrink(oldEnd
);
1286 return checkedReturn(throwStackOverflowError(callFrame
));
1289 newCallFrame
->init(newCodeBlock
, 0, callDataScopeChain
, callFrame
->addHostCallFrameFlag(), argCount
, function
);
1291 TopCallFrameSetter
topCallFrame(callFrame
->globalData(), newCallFrame
);
1293 Profiler
** profiler
= Profiler::enabledProfilerReference();
1295 (*profiler
)->willExecute(callFrame
, function
);
1299 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1303 if (!classicEnabled())
1304 result
= callData
.js
.functionExecutable
->generatedJITCodeForCall().execute(&m_registerFile
, newCallFrame
, callDataScopeChain
->globalData
);
1307 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
);
1312 (*profiler
)->didExecute(callFrame
, function
);
1314 m_registerFile
.shrink(oldEnd
);
1315 return checkedReturn(result
);
1318 ASSERT(callType
== CallTypeHost
);
1319 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
1320 newCallFrame
->init(0, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), argCount
, function
);
1322 TopCallFrameSetter
topCallFrame(callFrame
->globalData(), newCallFrame
);
1324 DynamicGlobalObjectScope
globalObjectScope(*scopeChain
->globalData
, scopeChain
->globalObject
.get());
1326 Profiler
** profiler
= Profiler::enabledProfilerReference();
1328 (*profiler
)->willExecute(callFrame
, function
);
1332 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
1333 result
= JSValue::decode(callData
.native
.function(newCallFrame
));
1337 (*profiler
)->didExecute(callFrame
, function
);
1339 m_registerFile
.shrink(oldEnd
);
1340 return checkedReturn(result
);
1343 JSObject
* Interpreter::executeConstruct(CallFrame
* callFrame
, JSObject
* constructor
, ConstructType constructType
, const ConstructData
& constructData
, const ArgList
& args
)
1345 ASSERT(!callFrame
->hadException());
1346 ASSERT(!callFrame
->globalData().isCollectorBusy());
1347 // We throw in this case because we have to return something "valid" but we're
1348 // already in an invalid state.
1349 if (callFrame
->globalData().isCollectorBusy())
1350 return checkedReturn(throwStackOverflowError(callFrame
));
1352 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
&& m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
)
1353 return checkedReturn(throwStackOverflowError(callFrame
));
1355 Register
* oldEnd
= m_registerFile
.end();
1356 int argCount
= 1 + args
.size(); // implicit "this" parameter
1357 size_t registerOffset
= argCount
+ RegisterFile::CallFrameHeaderSize
;
1359 if (!m_registerFile
.grow(oldEnd
+ registerOffset
))
1360 return checkedReturn(throwStackOverflowError(callFrame
));
1362 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
+ registerOffset
);
1363 newCallFrame
->setThisValue(jsUndefined());
1364 for (size_t i
= 0; i
< args
.size(); ++i
)
1365 newCallFrame
->setArgument(i
, args
.at(i
));
1367 if (constructType
== ConstructTypeJS
) {
1368 ScopeChainNode
* constructDataScopeChain
= constructData
.js
.scopeChain
;
1370 DynamicGlobalObjectScope
globalObjectScope(*constructDataScopeChain
->globalData
, constructDataScopeChain
->globalObject
.get());
1372 JSObject
* compileError
= constructData
.js
.functionExecutable
->compileForConstruct(callFrame
, constructDataScopeChain
);
1373 if (UNLIKELY(!!compileError
)) {
1374 m_registerFile
.shrink(oldEnd
);
1375 return checkedReturn(throwError(callFrame
, compileError
));
1378 CodeBlock
* newCodeBlock
= &constructData
.js
.functionExecutable
->generatedBytecodeForConstruct();
1379 newCallFrame
= slideRegisterWindowForCall(newCodeBlock
, &m_registerFile
, newCallFrame
, 0, argCount
);
1380 if (UNLIKELY(!newCallFrame
)) {
1381 m_registerFile
.shrink(oldEnd
);
1382 return checkedReturn(throwStackOverflowError(callFrame
));
1385 newCallFrame
->init(newCodeBlock
, 0, constructDataScopeChain
, callFrame
->addHostCallFrameFlag(), argCount
, constructor
);
1387 TopCallFrameSetter
topCallFrame(callFrame
->globalData(), newCallFrame
);
1389 Profiler
** profiler
= Profiler::enabledProfilerReference();
1391 (*profiler
)->willExecute(callFrame
, constructor
);
1395 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1399 if (!classicEnabled())
1400 result
= constructData
.js
.functionExecutable
->generatedJITCodeForConstruct().execute(&m_registerFile
, newCallFrame
, constructDataScopeChain
->globalData
);
1403 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
);
1408 (*profiler
)->didExecute(callFrame
, constructor
);
1410 m_registerFile
.shrink(oldEnd
);
1411 if (callFrame
->hadException())
1413 ASSERT(result
.isObject());
1414 return checkedReturn(asObject(result
));
1417 ASSERT(constructType
== ConstructTypeHost
);
1418 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
1419 newCallFrame
->init(0, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), argCount
, constructor
);
1421 TopCallFrameSetter
topCallFrame(callFrame
->globalData(), newCallFrame
);
1423 DynamicGlobalObjectScope
globalObjectScope(*scopeChain
->globalData
, scopeChain
->globalObject
.get());
1425 Profiler
** profiler
= Profiler::enabledProfilerReference();
1427 (*profiler
)->willExecute(callFrame
, constructor
);
1431 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
1432 result
= JSValue::decode(constructData
.native
.function(newCallFrame
));
1436 (*profiler
)->didExecute(callFrame
, constructor
);
1438 m_registerFile
.shrink(oldEnd
);
1439 if (callFrame
->hadException())
1441 ASSERT(result
.isObject());
1442 return checkedReturn(asObject(result
));
1445 CallFrameClosure
Interpreter::prepareForRepeatCall(FunctionExecutable
* functionExecutable
, CallFrame
* callFrame
, JSFunction
* function
, int argumentCountIncludingThis
, ScopeChainNode
* scopeChain
)
1447 ASSERT(!scopeChain
->globalData
->exception
);
1449 if (callFrame
->globalData().isCollectorBusy())
1450 return CallFrameClosure();
1452 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
&& m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
) {
1453 throwStackOverflowError(callFrame
);
1454 return CallFrameClosure();
1457 Register
* oldEnd
= m_registerFile
.end();
1458 size_t registerOffset
= argumentCountIncludingThis
+ RegisterFile::CallFrameHeaderSize
;
1460 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
+ registerOffset
);
1461 if (!m_registerFile
.grow(newCallFrame
->registers())) {
1462 throwStackOverflowError(callFrame
);
1463 return CallFrameClosure();
1466 JSObject
* error
= functionExecutable
->compileForCall(callFrame
, scopeChain
);
1468 throwError(callFrame
, error
);
1469 m_registerFile
.shrink(oldEnd
);
1470 return CallFrameClosure();
1472 CodeBlock
* codeBlock
= &functionExecutable
->generatedBytecodeForCall();
1474 newCallFrame
= slideRegisterWindowForCall(codeBlock
, &m_registerFile
, newCallFrame
, 0, argumentCountIncludingThis
);
1475 if (UNLIKELY(!newCallFrame
)) {
1476 throwStackOverflowError(callFrame
);
1477 m_registerFile
.shrink(oldEnd
);
1478 return CallFrameClosure();
1480 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), argumentCountIncludingThis
, function
);
1481 scopeChain
->globalData
->topCallFrame
= newCallFrame
;
1482 CallFrameClosure result
= { callFrame
, newCallFrame
, function
, functionExecutable
, scopeChain
->globalData
, oldEnd
, scopeChain
, codeBlock
->numParameters(), argumentCountIncludingThis
};
1486 JSValue
Interpreter::execute(CallFrameClosure
& closure
)
1488 ASSERT(!closure
.oldCallFrame
->globalData().isCollectorBusy());
1489 if (closure
.oldCallFrame
->globalData().isCollectorBusy())
1491 closure
.resetCallFrame();
1492 Profiler
** profiler
= Profiler::enabledProfilerReference();
1494 (*profiler
)->willExecute(closure
.oldCallFrame
, closure
.function
);
1496 TopCallFrameSetter
topCallFrame(*closure
.globalData
, closure
.newCallFrame
);
1500 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1504 #if ENABLE(CLASSIC_INTERPRETER)
1505 if (closure
.newCallFrame
->globalData().canUseJIT())
1507 result
= closure
.functionExecutable
->generatedJITCodeForCall().execute(&m_registerFile
, closure
.newCallFrame
, closure
.globalData
);
1508 #if ENABLE(CLASSIC_INTERPRETER)
1512 #if ENABLE(CLASSIC_INTERPRETER)
1513 result
= privateExecute(Normal
, &m_registerFile
, closure
.newCallFrame
);
1519 (*profiler
)->didExecute(closure
.oldCallFrame
, closure
.function
);
1520 return checkedReturn(result
);
1523 void Interpreter::endRepeatCall(CallFrameClosure
& closure
)
1525 closure
.globalData
->topCallFrame
= closure
.oldCallFrame
;
1526 m_registerFile
.shrink(closure
.oldEnd
);
1529 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSValue thisValue
, ScopeChainNode
* scopeChain
, int globalRegisterOffset
)
1531 ASSERT(isValidThisObject(thisValue
, callFrame
));
1532 ASSERT(!scopeChain
->globalData
->exception
);
1533 ASSERT(!callFrame
->globalData().isCollectorBusy());
1534 if (callFrame
->globalData().isCollectorBusy())
1537 DynamicGlobalObjectScope
globalObjectScope(*scopeChain
->globalData
, scopeChain
->globalObject
.get());
1539 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
&& m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
)
1540 return checkedReturn(throwStackOverflowError(callFrame
));
1542 JSObject
* compileError
= eval
->compile(callFrame
, scopeChain
);
1543 if (UNLIKELY(!!compileError
))
1544 return checkedReturn(throwError(callFrame
, compileError
));
1545 EvalCodeBlock
* codeBlock
= &eval
->generatedBytecode();
1547 JSObject
* variableObject
;
1548 for (ScopeChainNode
* node
= scopeChain
; ; node
= node
->next
.get()) {
1550 if (node
->object
->isVariableObject() && !node
->object
->isStaticScopeObject()) {
1551 variableObject
= jsCast
<JSVariableObject
*>(node
->object
.get());
1556 unsigned numVariables
= codeBlock
->numVariables();
1557 int numFunctions
= codeBlock
->numberOfFunctionDecls();
1558 bool pushedScope
= false;
1559 if (numVariables
|| numFunctions
) {
1560 if (codeBlock
->isStrictMode()) {
1561 variableObject
= StrictEvalActivation::create(callFrame
);
1562 scopeChain
= scopeChain
->push(variableObject
);
1565 // Scope for BatchedTransitionOptimizer
1566 BatchedTransitionOptimizer
optimizer(callFrame
->globalData(), variableObject
);
1568 for (unsigned i
= 0; i
< numVariables
; ++i
) {
1569 const Identifier
& ident
= codeBlock
->variable(i
);
1570 if (!variableObject
->hasProperty(callFrame
, ident
)) {
1571 PutPropertySlot slot
;
1572 variableObject
->methodTable()->put(variableObject
, callFrame
, ident
, jsUndefined(), slot
);
1576 for (int i
= 0; i
< numFunctions
; ++i
) {
1577 FunctionExecutable
* function
= codeBlock
->functionDecl(i
);
1578 PutPropertySlot slot
;
1579 variableObject
->methodTable()->put(variableObject
, callFrame
, function
->name(), function
->make(callFrame
, scopeChain
), slot
);
1583 Register
* oldEnd
= m_registerFile
.end();
1584 Register
* newEnd
= m_registerFile
.begin() + globalRegisterOffset
+ codeBlock
->m_numCalleeRegisters
;
1585 if (!m_registerFile
.grow(newEnd
)) {
1588 return checkedReturn(throwStackOverflowError(callFrame
));
1591 CallFrame
* newCallFrame
= CallFrame::create(m_registerFile
.begin() + globalRegisterOffset
);
1593 ASSERT(codeBlock
->numParameters() == 1); // 1 parameter for 'this'.
1594 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), codeBlock
->numParameters(), 0);
1595 newCallFrame
->setThisValue(thisValue
);
1597 TopCallFrameSetter
topCallFrame(callFrame
->globalData(), newCallFrame
);
1599 Profiler
** profiler
= Profiler::enabledProfilerReference();
1601 (*profiler
)->willExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
1605 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1610 #if ENABLE(CLASSIC_INTERPRETER)
1611 if (callFrame
->globalData().canUseJIT())
1613 result
= eval
->generatedJITCode().execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
);
1614 #if ENABLE(CLASSIC_INTERPRETER)
1618 #if ENABLE(CLASSIC_INTERPRETER)
1619 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
);
1625 (*profiler
)->didExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
1627 m_registerFile
.shrink(oldEnd
);
1630 return checkedReturn(result
);
1633 NEVER_INLINE
void Interpreter::debug(CallFrame
* callFrame
, DebugHookID debugHookID
, int firstLine
, int lastLine
)
1635 Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger();
1639 switch (debugHookID
) {
1640 case DidEnterCallFrame
:
1641 debugger
->callEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
1643 case WillLeaveCallFrame
:
1644 debugger
->returnEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
1646 case WillExecuteStatement
:
1647 debugger
->atStatement(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
1649 case WillExecuteProgram
:
1650 debugger
->willExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
1652 case DidExecuteProgram
:
1653 debugger
->didExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
1655 case DidReachBreakpoint
:
1656 debugger
->didReachBreakpoint(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
1661 #if ENABLE(CLASSIC_INTERPRETER)
1662 NEVER_INLINE ScopeChainNode
* Interpreter::createExceptionScope(CallFrame
* callFrame
, const Instruction
* vPC
)
1664 int dst
= vPC
[1].u
.operand
;
1665 CodeBlock
* codeBlock
= callFrame
->codeBlock();
1666 Identifier
& property
= codeBlock
->identifier(vPC
[2].u
.operand
);
1667 JSValue value
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1668 JSObject
* scope
= JSStaticScopeObject::create(callFrame
, property
, value
, DontDelete
);
1669 callFrame
->uncheckedR(dst
) = JSValue(scope
);
1671 return callFrame
->scopeChain()->push(scope
);
1674 NEVER_INLINE
void Interpreter::tryCachePutByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const PutPropertySlot
& slot
)
1676 // Recursive invocation may already have specialized this instruction.
1677 if (vPC
[0].u
.opcode
!= getOpcode(op_put_by_id
))
1680 if (!baseValue
.isCell())
1683 // Uncacheable: give up.
1684 if (!slot
.isCacheable()) {
1685 vPC
[0] = getOpcode(op_put_by_id_generic
);
1689 JSCell
* baseCell
= baseValue
.asCell();
1690 Structure
* structure
= baseCell
->structure();
1692 if (structure
->isUncacheableDictionary() || structure
->typeInfo().prohibitsPropertyCaching()) {
1693 vPC
[0] = getOpcode(op_put_by_id_generic
);
1697 // Cache miss: record Structure to compare against next time.
1698 Structure
* lastStructure
= vPC
[4].u
.structure
.get();
1699 if (structure
!= lastStructure
) {
1700 // First miss: record Structure to compare against next time.
1701 if (!lastStructure
) {
1702 vPC
[4].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
);
1706 // Second miss: give up.
1707 vPC
[0] = getOpcode(op_put_by_id_generic
);
1711 // Cache hit: Specialize instruction and ref Structures.
1713 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1714 if (baseCell
!= slot
.base()) {
1715 vPC
[0] = getOpcode(op_put_by_id_generic
);
1719 // Structure transition, cache transition info
1720 if (slot
.type() == PutPropertySlot::NewProperty
) {
1721 if (structure
->isDictionary()) {
1722 vPC
[0] = getOpcode(op_put_by_id_generic
);
1726 // put_by_id_transition checks the prototype chain for setters.
1727 normalizePrototypeChain(callFrame
, baseCell
);
1728 JSCell
* owner
= codeBlock
->ownerExecutable();
1729 JSGlobalData
& globalData
= callFrame
->globalData();
1730 // Get the prototype here because the call to prototypeChain could cause a
1731 // GC allocation, which we don't want to happen while we're in the middle of
1732 // initializing the union.
1733 StructureChain
* prototypeChain
= structure
->prototypeChain(callFrame
);
1734 vPC
[0] = getOpcode(op_put_by_id_transition
);
1735 vPC
[4].u
.structure
.set(globalData
, owner
, structure
->previousID());
1736 vPC
[5].u
.structure
.set(globalData
, owner
, structure
);
1737 vPC
[6].u
.structureChain
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), prototypeChain
);
1738 ASSERT(vPC
[6].u
.structureChain
);
1739 vPC
[7] = slot
.cachedOffset();
1743 vPC
[0] = getOpcode(op_put_by_id_replace
);
1744 vPC
[5] = slot
.cachedOffset();
1747 NEVER_INLINE
void Interpreter::uncachePutByID(CodeBlock
*, Instruction
* vPC
)
1749 vPC
[0] = getOpcode(op_put_by_id
);
1753 NEVER_INLINE
void Interpreter::tryCacheGetByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const Identifier
& propertyName
, const PropertySlot
& slot
)
1755 // Recursive invocation may already have specialized this instruction.
1756 if (vPC
[0].u
.opcode
!= getOpcode(op_get_by_id
))
1759 // FIXME: Cache property access for immediates.
1760 if (!baseValue
.isCell()) {
1761 vPC
[0] = getOpcode(op_get_by_id_generic
);
1765 if (isJSArray(baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
1766 vPC
[0] = getOpcode(op_get_array_length
);
1770 if (isJSString(baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
1771 vPC
[0] = getOpcode(op_get_string_length
);
1775 // Uncacheable: give up.
1776 if (!slot
.isCacheable()) {
1777 vPC
[0] = getOpcode(op_get_by_id_generic
);
1781 Structure
* structure
= baseValue
.asCell()->structure();
1783 if (structure
->isUncacheableDictionary() || structure
->typeInfo().prohibitsPropertyCaching()) {
1784 vPC
[0] = getOpcode(op_get_by_id_generic
);
1789 Structure
* lastStructure
= vPC
[4].u
.structure
.get();
1790 if (structure
!= lastStructure
) {
1791 // First miss: record Structure to compare against next time.
1792 if (!lastStructure
) {
1793 vPC
[4].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
);
1797 // Second miss: give up.
1798 vPC
[0] = getOpcode(op_get_by_id_generic
);
1802 // Cache hit: Specialize instruction and ref Structures.
1804 if (slot
.slotBase() == baseValue
) {
1805 switch (slot
.cachedPropertyType()) {
1806 case PropertySlot::Getter
:
1807 vPC
[0] = getOpcode(op_get_by_id_getter_self
);
1808 vPC
[5] = slot
.cachedOffset();
1810 case PropertySlot::Custom
:
1811 vPC
[0] = getOpcode(op_get_by_id_custom_self
);
1812 vPC
[5] = slot
.customGetter();
1815 vPC
[0] = getOpcode(op_get_by_id_self
);
1816 vPC
[5] = slot
.cachedOffset();
1822 if (structure
->isDictionary()) {
1823 vPC
[0] = getOpcode(op_get_by_id_generic
);
1827 if (slot
.slotBase() == structure
->prototypeForLookup(callFrame
)) {
1828 ASSERT(slot
.slotBase().isObject());
1830 JSObject
* baseObject
= asObject(slot
.slotBase());
1831 size_t offset
= slot
.cachedOffset();
1833 // Since we're accessing a prototype in a loop, it's a good bet that it
1834 // should not be treated as a dictionary.
1835 if (baseObject
->structure()->isDictionary()) {
1836 baseObject
->flattenDictionaryObject(callFrame
->globalData());
1837 offset
= baseObject
->structure()->get(callFrame
->globalData(), propertyName
);
1840 ASSERT(!baseObject
->structure()->isUncacheableDictionary());
1842 switch (slot
.cachedPropertyType()) {
1843 case PropertySlot::Getter
:
1844 vPC
[0] = getOpcode(op_get_by_id_getter_proto
);
1847 case PropertySlot::Custom
:
1848 vPC
[0] = getOpcode(op_get_by_id_custom_proto
);
1849 vPC
[6] = slot
.customGetter();
1852 vPC
[0] = getOpcode(op_get_by_id_proto
);
1856 vPC
[5].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), baseObject
->structure());
1860 size_t offset
= slot
.cachedOffset();
1861 size_t count
= normalizePrototypeChain(callFrame
, baseValue
, slot
.slotBase(), propertyName
, offset
);
1863 vPC
[0] = getOpcode(op_get_by_id_generic
);
1868 StructureChain
* prototypeChain
= structure
->prototypeChain(callFrame
);
1869 switch (slot
.cachedPropertyType()) {
1870 case PropertySlot::Getter
:
1871 vPC
[0] = getOpcode(op_get_by_id_getter_chain
);
1874 case PropertySlot::Custom
:
1875 vPC
[0] = getOpcode(op_get_by_id_custom_chain
);
1876 vPC
[7] = slot
.customGetter();
1879 vPC
[0] = getOpcode(op_get_by_id_chain
);
1883 vPC
[4].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
);
1884 vPC
[5].u
.structureChain
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), prototypeChain
);
1888 NEVER_INLINE
void Interpreter::uncacheGetByID(CodeBlock
*, Instruction
* vPC
)
1890 vPC
[0] = getOpcode(op_get_by_id
);
1894 #endif // ENABLE(CLASSIC_INTERPRETER)
1896 JSValue
Interpreter::privateExecute(ExecutionFlag flag
, RegisterFile
* registerFile
, CallFrame
* callFrame
)
1898 // One-time initialization of our address tables. We have to put this code
1899 // here because our labels are only in scope inside this function.
1900 if (UNLIKELY(flag
== InitializeAndReturn
)) {
1901 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
1902 #define LIST_OPCODE_LABEL(id, length) &&id,
1903 static Opcode labels
[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL
) };
1904 for (size_t i
= 0; i
< WTF_ARRAY_LENGTH(labels
); ++i
)
1905 m_opcodeTable
[i
] = labels
[i
];
1906 #undef LIST_OPCODE_LABEL
1907 #endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
1911 ASSERT(m_initialized
);
1912 ASSERT(m_classicEnabled
);
1915 #if ENABLE(CLASSIC_INTERPRETER)
1916 // Mixing Interpreter + JIT is not supported.
1917 if (callFrame
->globalData().canUseJIT())
1919 ASSERT_NOT_REACHED();
1922 #if !ENABLE(CLASSIC_INTERPRETER)
1923 UNUSED_PARAM(registerFile
);
1924 UNUSED_PARAM(callFrame
);
1928 ASSERT(callFrame
->globalData().topCallFrame
== callFrame
);
1930 JSGlobalData
* globalData
= &callFrame
->globalData();
1931 JSValue exceptionValue
;
1932 HandlerInfo
* handler
= 0;
1933 CallFrame
** topCallFrameSlot
= &globalData
->topCallFrame
;
1935 CodeBlock
* codeBlock
= callFrame
->codeBlock();
1936 Instruction
* vPC
= codeBlock
->instructions().begin();
1937 Profiler
** enabledProfilerReference
= Profiler::enabledProfilerReference();
1938 unsigned tickCount
= globalData
->timeoutChecker
.ticksUntilNextCheck();
1939 JSValue functionReturnValue
;
1941 #define CHECK_FOR_EXCEPTION() \
1943 if (UNLIKELY(globalData->exception != JSValue())) { \
1944 exceptionValue = globalData->exception; \
1949 #if ENABLE(OPCODE_STATS)
1950 OpcodeStats::resetLastInstruction();
1953 #define CHECK_FOR_TIMEOUT() \
1954 if (!--tickCount) { \
1955 if (globalData->terminator.shouldTerminate() || globalData->timeoutChecker.didTimeOut(callFrame)) { \
1956 exceptionValue = jsNull(); \
1959 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1962 #if ENABLE(OPCODE_SAMPLING)
1963 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1965 #define SAMPLE(codeBlock, vPC)
1968 #define UPDATE_BYTECODE_OFFSET() \
1970 callFrame->setBytecodeOffsetForNonDFGCode(vPC - codeBlock->instructions().data() + 1);\
1973 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
1974 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode
1975 #if ENABLE(OPCODE_STATS)
1976 #define DEFINE_OPCODE(opcode) \
1978 OpcodeStats::recordInstruction(opcode);\
1979 UPDATE_BYTECODE_OFFSET();
1981 #define DEFINE_OPCODE(opcode) opcode: UPDATE_BYTECODE_OFFSET();
1985 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart
1986 #if ENABLE(OPCODE_STATS)
1987 #define DEFINE_OPCODE(opcode) \
1989 OpcodeStats::recordInstruction(opcode);\
1990 UPDATE_BYTECODE_OFFSET();
1992 #define DEFINE_OPCODE(opcode) case opcode: UPDATE_BYTECODE_OFFSET();
1994 while (1) { // iterator loop begins
1995 interpreterLoopStart
:;
1996 switch (vPC
->u
.opcode
)
1999 DEFINE_OPCODE(op_new_object
) {
2000 /* new_object dst(r)
2002 Constructs a new empty Object instance using the original
2003 constructor, and puts the result in register dst.
2005 int dst
= vPC
[1].u
.operand
;
2006 callFrame
->uncheckedR(dst
) = JSValue(constructEmptyObject(callFrame
));
2008 vPC
+= OPCODE_LENGTH(op_new_object
);
2011 DEFINE_OPCODE(op_new_array
) {
2012 /* new_array dst(r) firstArg(r) argCount(n)
2014 Constructs a new Array instance using the original
2015 constructor, and puts the result in register dst.
2016 The array will contain argCount elements with values
2017 taken from registers starting at register firstArg.
2019 int dst
= vPC
[1].u
.operand
;
2020 int firstArg
= vPC
[2].u
.operand
;
2021 int argCount
= vPC
[3].u
.operand
;
2022 callFrame
->uncheckedR(dst
) = JSValue(constructArray(callFrame
, reinterpret_cast<JSValue
*>(&callFrame
->registers()[firstArg
]), argCount
));
2024 vPC
+= OPCODE_LENGTH(op_new_array
);
2027 DEFINE_OPCODE(op_new_array_buffer
) {
2028 /* new_array_buffer dst(r) index(n) argCount(n)
2030 Constructs a new Array instance using the original
2031 constructor, and puts the result in register dst.
2032 The array be initialized with the values from constantBuffer[index]
2034 int dst
= vPC
[1].u
.operand
;
2035 int firstArg
= vPC
[2].u
.operand
;
2036 int argCount
= vPC
[3].u
.operand
;
2037 callFrame
->uncheckedR(dst
) = JSValue(constructArray(callFrame
, codeBlock
->constantBuffer(firstArg
), argCount
));
2039 vPC
+= OPCODE_LENGTH(op_new_array
);
2042 DEFINE_OPCODE(op_new_regexp
) {
2043 /* new_regexp dst(r) regExp(re)
2045 Constructs a new RegExp instance using the original
2046 constructor from regexp regExp, and puts the result in
2049 int dst
= vPC
[1].u
.operand
;
2050 RegExp
* regExp
= codeBlock
->regexp(vPC
[2].u
.operand
);
2051 if (!regExp
->isValid()) {
2052 exceptionValue
= createSyntaxError(callFrame
, "Invalid flags supplied to RegExp constructor.");
2055 callFrame
->uncheckedR(dst
) = JSValue(RegExpObject::create(*globalData
, callFrame
->lexicalGlobalObject(), callFrame
->scopeChain()->globalObject
->regExpStructure(), regExp
));
2057 vPC
+= OPCODE_LENGTH(op_new_regexp
);
2060 DEFINE_OPCODE(op_mov
) {
2061 /* mov dst(r) src(r)
2063 Copies register src to register dst.
2065 int dst
= vPC
[1].u
.operand
;
2066 int src
= vPC
[2].u
.operand
;
2068 callFrame
->uncheckedR(dst
) = callFrame
->r(src
);
2070 vPC
+= OPCODE_LENGTH(op_mov
);
2073 DEFINE_OPCODE(op_eq
) {
2074 /* eq dst(r) src1(r) src2(r)
2076 Checks whether register src1 and register src2 are equal,
2077 as with the ECMAScript '==' operator, and puts the result
2078 as a boolean in register dst.
2080 int dst
= vPC
[1].u
.operand
;
2081 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2082 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2083 if (src1
.isInt32() && src2
.isInt32())
2084 callFrame
->uncheckedR(dst
) = jsBoolean(src1
.asInt32() == src2
.asInt32());
2086 JSValue result
= jsBoolean(JSValue::equalSlowCase(callFrame
, src1
, src2
));
2087 CHECK_FOR_EXCEPTION();
2088 callFrame
->uncheckedR(dst
) = result
;
2091 vPC
+= OPCODE_LENGTH(op_eq
);
2094 DEFINE_OPCODE(op_eq_null
) {
2095 /* eq_null dst(r) src(r)
2097 Checks whether register src is null, as with the ECMAScript '!='
2098 operator, and puts the result as a boolean in register dst.
2100 int dst
= vPC
[1].u
.operand
;
2101 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2103 if (src
.isUndefinedOrNull()) {
2104 callFrame
->uncheckedR(dst
) = jsBoolean(true);
2105 vPC
+= OPCODE_LENGTH(op_eq_null
);
2109 callFrame
->uncheckedR(dst
) = jsBoolean(src
.isCell() && src
.asCell()->structure()->typeInfo().masqueradesAsUndefined());
2110 vPC
+= OPCODE_LENGTH(op_eq_null
);
2113 DEFINE_OPCODE(op_neq
) {
2114 /* neq dst(r) src1(r) src2(r)
2116 Checks whether register src1 and register src2 are not
2117 equal, as with the ECMAScript '!=' operator, and puts the
2118 result as a boolean in register dst.
2120 int dst
= vPC
[1].u
.operand
;
2121 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2122 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2123 if (src1
.isInt32() && src2
.isInt32())
2124 callFrame
->uncheckedR(dst
) = jsBoolean(src1
.asInt32() != src2
.asInt32());
2126 JSValue result
= jsBoolean(!JSValue::equalSlowCase(callFrame
, src1
, src2
));
2127 CHECK_FOR_EXCEPTION();
2128 callFrame
->uncheckedR(dst
) = result
;
2131 vPC
+= OPCODE_LENGTH(op_neq
);
2134 DEFINE_OPCODE(op_neq_null
) {
2135 /* neq_null dst(r) src(r)
2137 Checks whether register src is not null, as with the ECMAScript '!='
2138 operator, and puts the result as a boolean in register dst.
2140 int dst
= vPC
[1].u
.operand
;
2141 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2143 if (src
.isUndefinedOrNull()) {
2144 callFrame
->uncheckedR(dst
) = jsBoolean(false);
2145 vPC
+= OPCODE_LENGTH(op_neq_null
);
2149 callFrame
->uncheckedR(dst
) = jsBoolean(!src
.isCell() || !src
.asCell()->structure()->typeInfo().masqueradesAsUndefined());
2150 vPC
+= OPCODE_LENGTH(op_neq_null
);
2153 DEFINE_OPCODE(op_stricteq
) {
2154 /* stricteq dst(r) src1(r) src2(r)
2156 Checks whether register src1 and register src2 are strictly
2157 equal, as with the ECMAScript '===' operator, and puts the
2158 result as a boolean in register dst.
2160 int dst
= vPC
[1].u
.operand
;
2161 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2162 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2163 bool result
= JSValue::strictEqual(callFrame
, src1
, src2
);
2164 CHECK_FOR_EXCEPTION();
2165 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
2167 vPC
+= OPCODE_LENGTH(op_stricteq
);
2170 DEFINE_OPCODE(op_nstricteq
) {
2171 /* nstricteq dst(r) src1(r) src2(r)
2173 Checks whether register src1 and register src2 are not
2174 strictly equal, as with the ECMAScript '!==' operator, and
2175 puts the result as a boolean in register dst.
2177 int dst
= vPC
[1].u
.operand
;
2178 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2179 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2180 bool result
= !JSValue::strictEqual(callFrame
, src1
, src2
);
2181 CHECK_FOR_EXCEPTION();
2182 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
2184 vPC
+= OPCODE_LENGTH(op_nstricteq
);
2187 DEFINE_OPCODE(op_less
) {
2188 /* less dst(r) src1(r) src2(r)
2190 Checks whether register src1 is less than register src2, as
2191 with the ECMAScript '<' operator, and puts the result as
2192 a boolean in register dst.
2194 int dst
= vPC
[1].u
.operand
;
2195 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2196 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2197 JSValue result
= jsBoolean(jsLess
<true>(callFrame
, src1
, src2
));
2198 CHECK_FOR_EXCEPTION();
2199 callFrame
->uncheckedR(dst
) = result
;
2201 vPC
+= OPCODE_LENGTH(op_less
);
2204 DEFINE_OPCODE(op_lesseq
) {
2205 /* lesseq dst(r) src1(r) src2(r)
2207 Checks whether register src1 is less than or equal to
2208 register src2, as with the ECMAScript '<=' operator, and
2209 puts the result as a boolean in register dst.
2211 int dst
= vPC
[1].u
.operand
;
2212 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2213 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2214 JSValue result
= jsBoolean(jsLessEq
<true>(callFrame
, src1
, src2
));
2215 CHECK_FOR_EXCEPTION();
2216 callFrame
->uncheckedR(dst
) = result
;
2218 vPC
+= OPCODE_LENGTH(op_lesseq
);
2221 DEFINE_OPCODE(op_greater
) {
2222 /* greater dst(r) src1(r) src2(r)
2224 Checks whether register src1 is greater than register src2, as
2225 with the ECMAScript '>' operator, and puts the result as
2226 a boolean in register dst.
2228 int dst
= vPC
[1].u
.operand
;
2229 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2230 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2231 JSValue result
= jsBoolean(jsLess
<false>(callFrame
, src2
, src1
));
2232 CHECK_FOR_EXCEPTION();
2233 callFrame
->uncheckedR(dst
) = result
;
2235 vPC
+= OPCODE_LENGTH(op_greater
);
2238 DEFINE_OPCODE(op_greatereq
) {
2239 /* greatereq dst(r) src1(r) src2(r)
2241 Checks whether register src1 is greater than or equal to
2242 register src2, as with the ECMAScript '>=' operator, and
2243 puts the result as a boolean in register dst.
2245 int dst
= vPC
[1].u
.operand
;
2246 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2247 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2248 JSValue result
= jsBoolean(jsLessEq
<false>(callFrame
, src2
, src1
));
2249 CHECK_FOR_EXCEPTION();
2250 callFrame
->uncheckedR(dst
) = result
;
2252 vPC
+= OPCODE_LENGTH(op_greatereq
);
2255 DEFINE_OPCODE(op_pre_inc
) {
2256 /* pre_inc srcDst(r)
2258 Converts register srcDst to number, adds one, and puts the result
2259 back in register srcDst.
2261 int srcDst
= vPC
[1].u
.operand
;
2262 JSValue v
= callFrame
->r(srcDst
).jsValue();
2263 if (v
.isInt32() && v
.asInt32() < INT_MAX
)
2264 callFrame
->uncheckedR(srcDst
) = jsNumber(v
.asInt32() + 1);
2266 JSValue result
= jsNumber(v
.toNumber(callFrame
) + 1);
2267 CHECK_FOR_EXCEPTION();
2268 callFrame
->uncheckedR(srcDst
) = result
;
2271 vPC
+= OPCODE_LENGTH(op_pre_inc
);
2274 DEFINE_OPCODE(op_pre_dec
) {
2275 /* pre_dec srcDst(r)
2277 Converts register srcDst to number, subtracts one, and puts the result
2278 back in register srcDst.
2280 int srcDst
= vPC
[1].u
.operand
;
2281 JSValue v
= callFrame
->r(srcDst
).jsValue();
2282 if (v
.isInt32() && v
.asInt32() > INT_MIN
)
2283 callFrame
->uncheckedR(srcDst
) = jsNumber(v
.asInt32() - 1);
2285 JSValue result
= jsNumber(v
.toNumber(callFrame
) - 1);
2286 CHECK_FOR_EXCEPTION();
2287 callFrame
->uncheckedR(srcDst
) = result
;
2290 vPC
+= OPCODE_LENGTH(op_pre_dec
);
2293 DEFINE_OPCODE(op_post_inc
) {
2294 /* post_inc dst(r) srcDst(r)
2296 Converts register srcDst to number. The number itself is
2297 written to register dst, and the number plus one is written
2298 back to register srcDst.
2300 int dst
= vPC
[1].u
.operand
;
2301 int srcDst
= vPC
[2].u
.operand
;
2302 JSValue v
= callFrame
->r(srcDst
).jsValue();
2303 if (v
.isInt32() && v
.asInt32() < INT_MAX
) {
2304 callFrame
->uncheckedR(srcDst
) = jsNumber(v
.asInt32() + 1);
2305 callFrame
->uncheckedR(dst
) = v
;
2307 double number
= callFrame
->r(srcDst
).jsValue().toNumber(callFrame
);
2308 CHECK_FOR_EXCEPTION();
2309 callFrame
->uncheckedR(srcDst
) = jsNumber(number
+ 1);
2310 callFrame
->uncheckedR(dst
) = jsNumber(number
);
2313 vPC
+= OPCODE_LENGTH(op_post_inc
);
2316 DEFINE_OPCODE(op_post_dec
) {
2317 /* post_dec dst(r) srcDst(r)
2319 Converts register srcDst to number. The number itself is
2320 written to register dst, and the number minus one is written
2321 back to register srcDst.
2323 int dst
= vPC
[1].u
.operand
;
2324 int srcDst
= vPC
[2].u
.operand
;
2325 JSValue v
= callFrame
->r(srcDst
).jsValue();
2326 if (v
.isInt32() && v
.asInt32() > INT_MIN
) {
2327 callFrame
->uncheckedR(srcDst
) = jsNumber(v
.asInt32() - 1);
2328 callFrame
->uncheckedR(dst
) = v
;
2330 double number
= callFrame
->r(srcDst
).jsValue().toNumber(callFrame
);
2331 CHECK_FOR_EXCEPTION();
2332 callFrame
->uncheckedR(srcDst
) = jsNumber(number
- 1);
2333 callFrame
->uncheckedR(dst
) = jsNumber(number
);
2336 vPC
+= OPCODE_LENGTH(op_post_dec
);
2339 DEFINE_OPCODE(op_to_jsnumber
) {
2340 /* to_jsnumber dst(r) src(r)
2342 Converts register src to number, and puts the result
2345 int dst
= vPC
[1].u
.operand
;
2346 int src
= vPC
[2].u
.operand
;
2348 JSValue srcVal
= callFrame
->r(src
).jsValue();
2350 if (LIKELY(srcVal
.isNumber()))
2351 callFrame
->uncheckedR(dst
) = callFrame
->r(src
);
2353 double number
= srcVal
.toNumber(callFrame
);
2354 CHECK_FOR_EXCEPTION();
2355 callFrame
->uncheckedR(dst
) = jsNumber(number
);
2358 vPC
+= OPCODE_LENGTH(op_to_jsnumber
);
2361 DEFINE_OPCODE(op_negate
) {
2362 /* negate dst(r) src(r)
2364 Converts register src to number, negates it, and puts the
2365 result in register dst.
2367 int dst
= vPC
[1].u
.operand
;
2368 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2369 if (src
.isInt32() && (src
.asInt32() & 0x7fffffff)) // non-zero and no overflow
2370 callFrame
->uncheckedR(dst
) = jsNumber(-src
.asInt32());
2372 JSValue result
= jsNumber(-src
.toNumber(callFrame
));
2373 CHECK_FOR_EXCEPTION();
2374 callFrame
->uncheckedR(dst
) = result
;
2377 vPC
+= OPCODE_LENGTH(op_negate
);
2380 DEFINE_OPCODE(op_add
) {
2381 /* add dst(r) src1(r) src2(r)
2383 Adds register src1 and register src2, and puts the result
2384 in register dst. (JS add may be string concatenation or
2385 numeric add, depending on the types of the operands.)
2387 int dst
= vPC
[1].u
.operand
;
2388 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2389 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2390 if (src1
.isInt32() && src2
.isInt32() && !((src1
.asInt32() | src2
.asInt32()) & 0xc0000000)) // no overflow
2391 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() + src2
.asInt32());
2393 JSValue result
= jsAdd(callFrame
, src1
, src2
);
2394 CHECK_FOR_EXCEPTION();
2395 callFrame
->uncheckedR(dst
) = result
;
2397 vPC
+= OPCODE_LENGTH(op_add
);
2400 DEFINE_OPCODE(op_mul
) {
2401 /* mul dst(r) src1(r) src2(r)
2403 Multiplies register src1 and register src2 (converted to
2404 numbers), and puts the product in register dst.
2406 int dst
= vPC
[1].u
.operand
;
2407 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2408 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2409 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | src2
.asInt32()) >> 15) // no overflow
2410 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() * src2
.asInt32());
2412 JSValue result
= jsNumber(src1
.toNumber(callFrame
) * src2
.toNumber(callFrame
));
2413 CHECK_FOR_EXCEPTION();
2414 callFrame
->uncheckedR(dst
) = result
;
2417 vPC
+= OPCODE_LENGTH(op_mul
);
2420 DEFINE_OPCODE(op_div
) {
2421 /* div dst(r) dividend(r) divisor(r)
2423 Divides register dividend (converted to number) by the
2424 register divisor (converted to number), and puts the
2425 quotient in register dst.
2427 int dst
= vPC
[1].u
.operand
;
2428 JSValue dividend
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2429 JSValue divisor
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2431 JSValue result
= jsNumber(dividend
.toNumber(callFrame
) / divisor
.toNumber(callFrame
));
2432 CHECK_FOR_EXCEPTION();
2433 callFrame
->uncheckedR(dst
) = result
;
2435 vPC
+= OPCODE_LENGTH(op_div
);
2438 DEFINE_OPCODE(op_mod
) {
2439 /* mod dst(r) dividend(r) divisor(r)
2441 Divides register dividend (converted to number) by
2442 register divisor (converted to number), and puts the
2443 remainder in register dst.
2445 int dst
= vPC
[1].u
.operand
;
2446 JSValue dividend
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2447 JSValue divisor
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2449 if (dividend
.isInt32() && divisor
.isInt32() && divisor
.asInt32() != 0) {
2450 JSValue result
= jsNumber(dividend
.asInt32() % divisor
.asInt32());
2452 callFrame
->uncheckedR(dst
) = result
;
2453 vPC
+= OPCODE_LENGTH(op_mod
);
2457 // Conversion to double must happen outside the call to fmod since the
2458 // order of argument evaluation is not guaranteed.
2459 double d1
= dividend
.toNumber(callFrame
);
2460 double d2
= divisor
.toNumber(callFrame
);
2461 JSValue result
= jsNumber(fmod(d1
, d2
));
2462 CHECK_FOR_EXCEPTION();
2463 callFrame
->uncheckedR(dst
) = result
;
2464 vPC
+= OPCODE_LENGTH(op_mod
);
2467 DEFINE_OPCODE(op_sub
) {
2468 /* sub dst(r) src1(r) src2(r)
2470 Subtracts register src2 (converted to number) from register
2471 src1 (converted to number), and puts the difference in
2474 int dst
= vPC
[1].u
.operand
;
2475 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2476 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2477 if (src1
.isInt32() && src2
.isInt32() && !((src1
.asInt32() | src2
.asInt32()) & 0xc0000000)) // no overflow
2478 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() - src2
.asInt32());
2480 JSValue result
= jsNumber(src1
.toNumber(callFrame
) - src2
.toNumber(callFrame
));
2481 CHECK_FOR_EXCEPTION();
2482 callFrame
->uncheckedR(dst
) = result
;
2484 vPC
+= OPCODE_LENGTH(op_sub
);
2487 DEFINE_OPCODE(op_lshift
) {
2488 /* lshift dst(r) val(r) shift(r)
2490 Performs left shift of register val (converted to int32) by
2491 register shift (converted to uint32), and puts the result
2494 int dst
= vPC
[1].u
.operand
;
2495 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2496 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2498 if (val
.isInt32() && shift
.isInt32())
2499 callFrame
->uncheckedR(dst
) = jsNumber(val
.asInt32() << (shift
.asInt32() & 0x1f));
2501 JSValue result
= jsNumber((val
.toInt32(callFrame
)) << (shift
.toUInt32(callFrame
) & 0x1f));
2502 CHECK_FOR_EXCEPTION();
2503 callFrame
->uncheckedR(dst
) = result
;
2506 vPC
+= OPCODE_LENGTH(op_lshift
);
2509 DEFINE_OPCODE(op_rshift
) {
2510 /* rshift dst(r) val(r) shift(r)
2512 Performs arithmetic right shift of register val (converted
2513 to int32) by register shift (converted to
2514 uint32), and puts the result in register dst.
2516 int dst
= vPC
[1].u
.operand
;
2517 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2518 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2520 if (val
.isInt32() && shift
.isInt32())
2521 callFrame
->uncheckedR(dst
) = jsNumber(val
.asInt32() >> (shift
.asInt32() & 0x1f));
2523 JSValue result
= jsNumber((val
.toInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
2524 CHECK_FOR_EXCEPTION();
2525 callFrame
->uncheckedR(dst
) = result
;
2528 vPC
+= OPCODE_LENGTH(op_rshift
);
2531 DEFINE_OPCODE(op_urshift
) {
2532 /* rshift dst(r) val(r) shift(r)
2534 Performs logical right shift of register val (converted
2535 to uint32) by register shift (converted to
2536 uint32), and puts the result in register dst.
2538 int dst
= vPC
[1].u
.operand
;
2539 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2540 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2541 if (val
.isUInt32() && shift
.isInt32())
2542 callFrame
->uncheckedR(dst
) = jsNumber(val
.asInt32() >> (shift
.asInt32() & 0x1f));
2544 JSValue result
= jsNumber((val
.toUInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
2545 CHECK_FOR_EXCEPTION();
2546 callFrame
->uncheckedR(dst
) = result
;
2549 vPC
+= OPCODE_LENGTH(op_urshift
);
2552 DEFINE_OPCODE(op_bitand
) {
2553 /* bitand dst(r) src1(r) src2(r)
2555 Computes bitwise AND of register src1 (converted to int32)
2556 and register src2 (converted to int32), and puts the result
2559 int dst
= vPC
[1].u
.operand
;
2560 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2561 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2562 if (src1
.isInt32() && src2
.isInt32())
2563 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() & src2
.asInt32());
2565 JSValue result
= jsNumber(src1
.toInt32(callFrame
) & src2
.toInt32(callFrame
));
2566 CHECK_FOR_EXCEPTION();
2567 callFrame
->uncheckedR(dst
) = result
;
2570 vPC
+= OPCODE_LENGTH(op_bitand
);
2573 DEFINE_OPCODE(op_bitxor
) {
2574 /* bitxor dst(r) src1(r) src2(r)
2576 Computes bitwise XOR of register src1 (converted to int32)
2577 and register src2 (converted to int32), and puts the result
2580 int dst
= vPC
[1].u
.operand
;
2581 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2582 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2583 if (src1
.isInt32() && src2
.isInt32())
2584 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() ^ src2
.asInt32());
2586 JSValue result
= jsNumber(src1
.toInt32(callFrame
) ^ src2
.toInt32(callFrame
));
2587 CHECK_FOR_EXCEPTION();
2588 callFrame
->uncheckedR(dst
) = result
;
2591 vPC
+= OPCODE_LENGTH(op_bitxor
);
2594 DEFINE_OPCODE(op_bitor
) {
2595 /* bitor dst(r) src1(r) src2(r)
2597 Computes bitwise OR of register src1 (converted to int32)
2598 and register src2 (converted to int32), and puts the
2599 result in register dst.
2601 int dst
= vPC
[1].u
.operand
;
2602 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2603 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2604 if (src1
.isInt32() && src2
.isInt32())
2605 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() | src2
.asInt32());
2607 JSValue result
= jsNumber(src1
.toInt32(callFrame
) | src2
.toInt32(callFrame
));
2608 CHECK_FOR_EXCEPTION();
2609 callFrame
->uncheckedR(dst
) = result
;
2612 vPC
+= OPCODE_LENGTH(op_bitor
);
2615 DEFINE_OPCODE(op_not
) {
2616 /* not dst(r) src(r)
2618 Computes logical NOT of register src (converted to
2619 boolean), and puts the result in register dst.
2621 int dst
= vPC
[1].u
.operand
;
2622 int src
= vPC
[2].u
.operand
;
2623 JSValue result
= jsBoolean(!callFrame
->r(src
).jsValue().toBoolean(callFrame
));
2624 CHECK_FOR_EXCEPTION();
2625 callFrame
->uncheckedR(dst
) = result
;
2627 vPC
+= OPCODE_LENGTH(op_not
);
2630 DEFINE_OPCODE(op_check_has_instance
) {
2631 /* check_has_instance constructor(r)
2633 Check 'constructor' is an object with the internal property
2634 [HasInstance] (i.e. is a function ... *shakes head sadly at
2635 JSC API*). Raises an exception if register constructor is not
2636 an valid parameter for instanceof.
2638 int base
= vPC
[1].u
.operand
;
2639 JSValue baseVal
= callFrame
->r(base
).jsValue();
2641 if (isInvalidParamForInstanceOf(callFrame
, baseVal
, exceptionValue
))
2644 vPC
+= OPCODE_LENGTH(op_check_has_instance
);
2647 DEFINE_OPCODE(op_instanceof
) {
2648 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2650 Tests whether register value is an instance of register
2651 constructor, and puts the boolean result in register
2652 dst. Register constructorProto must contain the "prototype"
2653 property (not the actual prototype) of the object in
2654 register constructor. This lookup is separated so that
2655 polymorphic inline caching can apply.
2657 Raises an exception if register constructor is not an
2660 int dst
= vPC
[1].u
.operand
;
2661 int value
= vPC
[2].u
.operand
;
2662 int base
= vPC
[3].u
.operand
;
2663 int baseProto
= vPC
[4].u
.operand
;
2665 JSValue baseVal
= callFrame
->r(base
).jsValue();
2667 ASSERT(!isInvalidParamForInstanceOf(callFrame
, baseVal
, exceptionValue
));
2669 bool result
= asObject(baseVal
)->methodTable()->hasInstance(asObject(baseVal
), callFrame
, callFrame
->r(value
).jsValue(), callFrame
->r(baseProto
).jsValue());
2670 CHECK_FOR_EXCEPTION();
2671 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
2673 vPC
+= OPCODE_LENGTH(op_instanceof
);
2676 DEFINE_OPCODE(op_typeof
) {
2677 /* typeof dst(r) src(r)
2679 Determines the type string for src according to ECMAScript
2680 rules, and puts the result in register dst.
2682 int dst
= vPC
[1].u
.operand
;
2683 int src
= vPC
[2].u
.operand
;
2684 callFrame
->uncheckedR(dst
) = JSValue(jsTypeStringForValue(callFrame
, callFrame
->r(src
).jsValue()));
2686 vPC
+= OPCODE_LENGTH(op_typeof
);
2689 DEFINE_OPCODE(op_is_undefined
) {
2690 /* is_undefined dst(r) src(r)
2692 Determines whether the type string for src according to
2693 the ECMAScript rules is "undefined", and puts the result
2696 int dst
= vPC
[1].u
.operand
;
2697 int src
= vPC
[2].u
.operand
;
2698 JSValue v
= callFrame
->r(src
).jsValue();
2699 callFrame
->uncheckedR(dst
) = jsBoolean(v
.isCell() ? v
.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v
.isUndefined());
2701 vPC
+= OPCODE_LENGTH(op_is_undefined
);
2704 DEFINE_OPCODE(op_is_boolean
) {
2705 /* is_boolean dst(r) src(r)
2707 Determines whether the type string for src according to
2708 the ECMAScript rules is "boolean", and puts the result
2711 int dst
= vPC
[1].u
.operand
;
2712 int src
= vPC
[2].u
.operand
;
2713 callFrame
->uncheckedR(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isBoolean());
2715 vPC
+= OPCODE_LENGTH(op_is_boolean
);
2718 DEFINE_OPCODE(op_is_number
) {
2719 /* is_number dst(r) src(r)
2721 Determines whether the type string for src according to
2722 the ECMAScript rules is "number", and puts the result
2725 int dst
= vPC
[1].u
.operand
;
2726 int src
= vPC
[2].u
.operand
;
2727 callFrame
->uncheckedR(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isNumber());
2729 vPC
+= OPCODE_LENGTH(op_is_number
);
2732 DEFINE_OPCODE(op_is_string
) {
2733 /* is_string dst(r) src(r)
2735 Determines whether the type string for src according to
2736 the ECMAScript rules is "string", and puts the result
2739 int dst
= vPC
[1].u
.operand
;
2740 int src
= vPC
[2].u
.operand
;
2741 callFrame
->uncheckedR(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isString());
2743 vPC
+= OPCODE_LENGTH(op_is_string
);
2746 DEFINE_OPCODE(op_is_object
) {
2747 /* is_object dst(r) src(r)
2749 Determines whether the type string for src according to
2750 the ECMAScript rules is "object", and puts the result
2753 int dst
= vPC
[1].u
.operand
;
2754 int src
= vPC
[2].u
.operand
;
2755 callFrame
->uncheckedR(dst
) = jsBoolean(jsIsObjectType(callFrame
->r(src
).jsValue()));
2757 vPC
+= OPCODE_LENGTH(op_is_object
);
2760 DEFINE_OPCODE(op_is_function
) {
2761 /* is_function dst(r) src(r)
2763 Determines whether the type string for src according to
2764 the ECMAScript rules is "function", and puts the result
2767 int dst
= vPC
[1].u
.operand
;
2768 int src
= vPC
[2].u
.operand
;
2769 callFrame
->uncheckedR(dst
) = jsBoolean(jsIsFunctionType(callFrame
->r(src
).jsValue()));
2771 vPC
+= OPCODE_LENGTH(op_is_function
);
2774 DEFINE_OPCODE(op_in
) {
2775 /* in dst(r) property(r) base(r)
2777 Tests whether register base has a property named register
2778 property, and puts the boolean result in register dst.
2780 Raises an exception if register constructor is not an
2783 int dst
= vPC
[1].u
.operand
;
2784 int property
= vPC
[2].u
.operand
;
2785 int base
= vPC
[3].u
.operand
;
2787 JSValue baseVal
= callFrame
->r(base
).jsValue();
2788 if (isInvalidParamForIn(callFrame
, baseVal
, exceptionValue
))
2791 JSObject
* baseObj
= asObject(baseVal
);
2793 JSValue propName
= callFrame
->r(property
).jsValue();
2796 if (propName
.getUInt32(i
))
2797 callFrame
->uncheckedR(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, i
));
2799 Identifier
property(callFrame
, propName
.toString(callFrame
)->value(callFrame
));
2800 CHECK_FOR_EXCEPTION();
2801 callFrame
->uncheckedR(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, property
));
2804 vPC
+= OPCODE_LENGTH(op_in
);
2807 DEFINE_OPCODE(op_resolve
) {
2808 /* resolve dst(r) property(id)
2810 Looks up the property named by identifier property in the
2811 scope chain, and writes the resulting value to register
2812 dst. If the property is not found, raises an exception.
2814 if (UNLIKELY(!resolve(callFrame
, vPC
, exceptionValue
)))
2817 vPC
+= OPCODE_LENGTH(op_resolve
);
2820 DEFINE_OPCODE(op_resolve_skip
) {
2821 /* resolve_skip dst(r) property(id) skip(n)
2823 Looks up the property named by identifier property in the
2824 scope chain skipping the top 'skip' levels, and writes the resulting
2825 value to register dst. If the property is not found, raises an exception.
2827 if (UNLIKELY(!resolveSkip(callFrame
, vPC
, exceptionValue
)))
2830 vPC
+= OPCODE_LENGTH(op_resolve_skip
);
2834 DEFINE_OPCODE(op_resolve_global
) {
2835 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
2837 Performs a dynamic property lookup for the given property, on the provided
2838 global object. If structure matches the Structure of the global then perform
2839 a fast lookup using the case offset, otherwise fall back to a full resolve and
2840 cache the new structure and offset
2842 if (UNLIKELY(!resolveGlobal(callFrame
, vPC
, exceptionValue
)))
2845 vPC
+= OPCODE_LENGTH(op_resolve_global
);
2849 DEFINE_OPCODE(op_resolve_global_dynamic
) {
2850 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n), depth(n)
2852 Performs a dynamic property lookup for the given property, on the provided
2853 global object. If structure matches the Structure of the global then perform
2854 a fast lookup using the case offset, otherwise fall back to a full resolve and
2855 cache the new structure and offset.
2857 This walks through n levels of the scope chain to verify that none of those levels
2858 in the scope chain include dynamically added properties.
2860 if (UNLIKELY(!resolveGlobalDynamic(callFrame
, vPC
, exceptionValue
)))
2863 vPC
+= OPCODE_LENGTH(op_resolve_global_dynamic
);
2867 DEFINE_OPCODE(op_get_global_var
) {
2868 /* get_global_var dst(r) globalObject(c) index(n)
2870 Gets the global var at global slot index and places it in register dst.
2872 int dst
= vPC
[1].u
.operand
;
2873 JSGlobalObject
* scope
= codeBlock
->globalObject();
2874 ASSERT(scope
->isGlobalObject());
2875 int index
= vPC
[2].u
.operand
;
2877 callFrame
->uncheckedR(dst
) = scope
->registerAt(index
).get();
2878 vPC
+= OPCODE_LENGTH(op_get_global_var
);
2881 DEFINE_OPCODE(op_put_global_var
) {
2882 /* put_global_var globalObject(c) index(n) value(r)
2884 Puts value into global slot index.
2886 JSGlobalObject
* scope
= codeBlock
->globalObject();
2887 ASSERT(scope
->isGlobalObject());
2888 int index
= vPC
[1].u
.operand
;
2889 int value
= vPC
[2].u
.operand
;
2891 scope
->registerAt(index
).set(*globalData
, scope
, callFrame
->r(value
).jsValue());
2892 vPC
+= OPCODE_LENGTH(op_put_global_var
);
2895 DEFINE_OPCODE(op_get_scoped_var
) {
2896 /* get_scoped_var dst(r) index(n) skip(n)
2898 Loads the contents of the index-th local from the scope skip nodes from
2899 the top of the scope chain, and places it in register dst.
2901 int dst
= vPC
[1].u
.operand
;
2902 int index
= vPC
[2].u
.operand
;
2903 int skip
= vPC
[3].u
.operand
;
2905 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2906 ScopeChainIterator iter
= scopeChain
->begin();
2907 ScopeChainIterator end
= scopeChain
->end();
2908 ASSERT_UNUSED(end
, iter
!= end
);
2909 ASSERT(codeBlock
== callFrame
->codeBlock());
2910 bool checkTopLevel
= codeBlock
->codeType() == FunctionCode
&& codeBlock
->needsFullScopeChain();
2911 ASSERT(skip
|| !checkTopLevel
);
2912 if (checkTopLevel
&& skip
--) {
2913 if (callFrame
->r(codeBlock
->activationRegister()).jsValue())
2918 ASSERT_UNUSED(end
, iter
!= end
);
2920 ASSERT((*iter
)->isVariableObject());
2921 JSVariableObject
* scope
= jsCast
<JSVariableObject
*>(iter
->get());
2922 callFrame
->uncheckedR(dst
) = scope
->registerAt(index
).get();
2923 ASSERT(callFrame
->r(dst
).jsValue());
2924 vPC
+= OPCODE_LENGTH(op_get_scoped_var
);
2927 DEFINE_OPCODE(op_put_scoped_var
) {
2928 /* put_scoped_var index(n) skip(n) value(r)
2931 int index
= vPC
[1].u
.operand
;
2932 int skip
= vPC
[2].u
.operand
;
2933 int value
= vPC
[3].u
.operand
;
2935 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2936 ScopeChainIterator iter
= scopeChain
->begin();
2937 ScopeChainIterator end
= scopeChain
->end();
2938 ASSERT(codeBlock
== callFrame
->codeBlock());
2939 ASSERT_UNUSED(end
, iter
!= end
);
2940 bool checkTopLevel
= codeBlock
->codeType() == FunctionCode
&& codeBlock
->needsFullScopeChain();
2941 ASSERT(skip
|| !checkTopLevel
);
2942 if (checkTopLevel
&& skip
--) {
2943 if (callFrame
->r(codeBlock
->activationRegister()).jsValue())
2948 ASSERT_UNUSED(end
, iter
!= end
);
2951 ASSERT((*iter
)->isVariableObject());
2952 JSVariableObject
* scope
= jsCast
<JSVariableObject
*>(iter
->get());
2953 ASSERT(callFrame
->r(value
).jsValue());
2954 scope
->registerAt(index
).set(*globalData
, scope
, callFrame
->r(value
).jsValue());
2955 vPC
+= OPCODE_LENGTH(op_put_scoped_var
);
2958 DEFINE_OPCODE(op_resolve_base
) {
2959 /* resolve_base dst(r) property(id) isStrict(bool)
2961 Searches the scope chain for an object containing
2962 identifier property, and if one is found, writes it to
2963 register dst. If none is found and isStrict is false, the
2964 outermost scope (which will be the global object) is
2965 stored in register dst.
2967 resolveBase(callFrame
, vPC
);
2968 CHECK_FOR_EXCEPTION();
2970 vPC
+= OPCODE_LENGTH(op_resolve_base
);
2973 DEFINE_OPCODE(op_ensure_property_exists
) {
2974 /* ensure_property_exists base(r) property(id)
2976 Throws an exception if property does not exist on base
2978 int base
= vPC
[1].u
.operand
;
2979 int property
= vPC
[2].u
.operand
;
2980 Identifier
& ident
= codeBlock
->identifier(property
);
2982 JSValue baseVal
= callFrame
->r(base
).jsValue();
2983 JSObject
* baseObject
= asObject(baseVal
);
2984 PropertySlot
slot(baseVal
);
2985 if (!baseObject
->getPropertySlot(callFrame
, ident
, slot
)) {
2986 exceptionValue
= createErrorForInvalidGlobalAssignment(callFrame
, ident
.ustring());
2990 vPC
+= OPCODE_LENGTH(op_ensure_property_exists
);
2993 DEFINE_OPCODE(op_resolve_with_base
) {
2994 /* resolve_with_base baseDst(r) propDst(r) property(id)
2996 Searches the scope chain for an object containing
2997 identifier property, and if one is found, writes it to
2998 register srcDst, and the retrieved property value to register
2999 propDst. If the property is not found, raises an exception.
3001 This is more efficient than doing resolve_base followed by
3002 resolve, or resolve_base followed by get_by_id, as it
3003 avoids duplicate hash lookups.
3005 if (UNLIKELY(!resolveBaseAndProperty(callFrame
, vPC
, exceptionValue
)))
3008 vPC
+= OPCODE_LENGTH(op_resolve_with_base
);
3011 DEFINE_OPCODE(op_resolve_with_this
) {
3012 /* resolve_with_this thisDst(r) propDst(r) property(id)
3014 Searches the scope chain for an object containing
3015 identifier property, and if one is found, writes the
3016 retrieved property value to register propDst, and the
3017 this object to pass in a call to thisDst.
3019 If the property is not found, raises an exception.
3021 if (UNLIKELY(!resolveThisAndProperty(callFrame
, vPC
, exceptionValue
)))
3024 vPC
+= OPCODE_LENGTH(op_resolve_with_this
);
3027 DEFINE_OPCODE(op_get_by_id
) {
3028 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
3030 Generic property access: Gets the property named by identifier
3031 property from the value base, and puts the result in register dst.
3033 int dst
= vPC
[1].u
.operand
;
3034 int base
= vPC
[2].u
.operand
;
3035 int property
= vPC
[3].u
.operand
;
3037 Identifier
& ident
= codeBlock
->identifier(property
);
3038 JSValue baseValue
= callFrame
->r(base
).jsValue();
3039 PropertySlot
slot(baseValue
);
3040 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
3041 CHECK_FOR_EXCEPTION();
3043 tryCacheGetByID(callFrame
, codeBlock
, vPC
, baseValue
, ident
, slot
);
3045 callFrame
->uncheckedR(dst
) = result
;
3046 vPC
+= OPCODE_LENGTH(op_get_by_id
);
3049 DEFINE_OPCODE(op_get_by_id_self
) {
3050 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
3052 Cached property access: Attempts to get a cached property from the
3053 value base. If the cache misses, op_get_by_id_self reverts to
3056 int base
= vPC
[2].u
.operand
;
3057 JSValue baseValue
= callFrame
->r(base
).jsValue();
3059 if (LIKELY(baseValue
.isCell())) {
3060 JSCell
* baseCell
= baseValue
.asCell();
3061 Structure
* structure
= vPC
[4].u
.structure
.get();
3063 if (LIKELY(baseCell
->structure() == structure
)) {
3064 ASSERT(baseCell
->isObject());
3065 JSObject
* baseObject
= asObject(baseCell
);
3066 int dst
= vPC
[1].u
.operand
;
3067 int offset
= vPC
[5].u
.operand
;
3069 ASSERT(baseObject
->get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
3070 callFrame
->uncheckedR(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
3072 vPC
+= OPCODE_LENGTH(op_get_by_id_self
);
3077 uncacheGetByID(codeBlock
, vPC
);
3080 DEFINE_OPCODE(op_get_by_id_proto
) {
3081 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
3083 Cached property access: Attempts to get a cached property from the
3084 value base's prototype. If the cache misses, op_get_by_id_proto
3085 reverts to op_get_by_id.
3087 int base
= vPC
[2].u
.operand
;
3088 JSValue baseValue
= callFrame
->r(base
).jsValue();
3090 if (LIKELY(baseValue
.isCell())) {
3091 JSCell
* baseCell
= baseValue
.asCell();
3092 Structure
* structure
= vPC
[4].u
.structure
.get();
3094 if (LIKELY(baseCell
->structure() == structure
)) {
3095 ASSERT(structure
->prototypeForLookup(callFrame
).isObject());
3096 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
3097 Structure
* prototypeStructure
= vPC
[5].u
.structure
.get();
3099 if (LIKELY(protoObject
->structure() == prototypeStructure
)) {
3100 int dst
= vPC
[1].u
.operand
;
3101 int offset
= vPC
[6].u
.operand
;
3103 ASSERT(protoObject
->get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
3104 ASSERT(baseValue
.get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
3105 callFrame
->uncheckedR(dst
) = JSValue(protoObject
->getDirectOffset(offset
));
3107 vPC
+= OPCODE_LENGTH(op_get_by_id_proto
);
3113 uncacheGetByID(codeBlock
, vPC
);
3116 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3117 goto *(&&skip_id_getter_proto
);
3119 DEFINE_OPCODE(op_get_by_id_getter_proto
) {
3120 /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
3122 Cached property access: Attempts to get a cached getter property from the
3123 value base's prototype. If the cache misses, op_get_by_id_getter_proto
3124 reverts to op_get_by_id.
3126 int base
= vPC
[2].u
.operand
;
3127 JSValue baseValue
= callFrame
->r(base
).jsValue();
3129 if (LIKELY(baseValue
.isCell())) {
3130 JSCell
* baseCell
= baseValue
.asCell();
3131 Structure
* structure
= vPC
[4].u
.structure
.get();
3133 if (LIKELY(baseCell
->structure() == structure
)) {
3134 ASSERT(structure
->prototypeForLookup(callFrame
).isObject());
3135 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
3136 Structure
* prototypeStructure
= vPC
[5].u
.structure
.get();
3138 if (LIKELY(protoObject
->structure() == prototypeStructure
)) {
3139 int dst
= vPC
[1].u
.operand
;
3140 int offset
= vPC
[6].u
.operand
;
3141 if (GetterSetter
* getterSetter
= asGetterSetter(protoObject
->getDirectOffset(offset
).asCell())) {
3142 JSObject
* getter
= getterSetter
->getter();
3144 CallType callType
= getter
->methodTable()->getCallData(getter
, callData
);
3145 JSValue result
= call(callFrame
, getter
, callType
, callData
, asObject(baseCell
), ArgList());
3146 CHECK_FOR_EXCEPTION();
3147 callFrame
->uncheckedR(dst
) = result
;
3149 callFrame
->uncheckedR(dst
) = jsUndefined();
3150 vPC
+= OPCODE_LENGTH(op_get_by_id_getter_proto
);
3155 uncacheGetByID(codeBlock
, vPC
);
3158 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3159 skip_id_getter_proto
:
3161 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3162 goto *(&&skip_id_custom_proto
);
3164 DEFINE_OPCODE(op_get_by_id_custom_proto
) {
3165 /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
3167 Cached property access: Attempts to use a cached named property getter
3168 from the value base's prototype. If the cache misses, op_get_by_id_custom_proto
3169 reverts to op_get_by_id.
3171 int base
= vPC
[2].u
.operand
;
3172 JSValue baseValue
= callFrame
->r(base
).jsValue();
3174 if (LIKELY(baseValue
.isCell())) {
3175 JSCell
* baseCell
= baseValue
.asCell();
3176 Structure
* structure
= vPC
[4].u
.structure
.get();
3178 if (LIKELY(baseCell
->structure() == structure
)) {
3179 ASSERT(structure
->prototypeForLookup(callFrame
).isObject());
3180 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
3181 Structure
* prototypeStructure
= vPC
[5].u
.structure
.get();
3183 if (LIKELY(protoObject
->structure() == prototypeStructure
)) {
3184 int dst
= vPC
[1].u
.operand
;
3185 int property
= vPC
[3].u
.operand
;
3186 Identifier
& ident
= codeBlock
->identifier(property
);
3188 PropertySlot::GetValueFunc getter
= vPC
[6].u
.getterFunc
;
3189 JSValue result
= getter(callFrame
, protoObject
, ident
);
3190 CHECK_FOR_EXCEPTION();
3191 callFrame
->uncheckedR(dst
) = result
;
3192 vPC
+= OPCODE_LENGTH(op_get_by_id_custom_proto
);
3197 uncacheGetByID(codeBlock
, vPC
);
3200 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3201 skip_id_custom_proto
:
3203 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3204 goto *(&&skip_get_by_id_chain
);
3206 DEFINE_OPCODE(op_get_by_id_chain
) {
3207 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
3209 Cached property access: Attempts to get a cached property from the
3210 value base's prototype chain. If the cache misses, op_get_by_id_chain
3211 reverts to op_get_by_id.
3213 int base
= vPC
[2].u
.operand
;
3214 JSValue baseValue
= callFrame
->r(base
).jsValue();
3216 if (LIKELY(baseValue
.isCell())) {
3217 JSCell
* baseCell
= baseValue
.asCell();
3218 Structure
* structure
= vPC
[4].u
.structure
.get();
3220 if (LIKELY(baseCell
->structure() == structure
)) {
3221 WriteBarrier
<Structure
>* it
= vPC
[5].u
.structureChain
->head();
3222 size_t count
= vPC
[6].u
.operand
;
3223 WriteBarrier
<Structure
>* end
= it
+ count
;
3226 JSObject
* baseObject
= asObject(baseCell
->structure()->prototypeForLookup(callFrame
));
3228 if (UNLIKELY(baseObject
->structure() != (*it
).get()))
3232 int dst
= vPC
[1].u
.operand
;
3233 int offset
= vPC
[7].u
.operand
;
3235 ASSERT(baseObject
->get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
3236 ASSERT(baseValue
.get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
3237 callFrame
->uncheckedR(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
3239 vPC
+= OPCODE_LENGTH(op_get_by_id_chain
);
3243 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
3244 baseCell
= baseObject
;
3249 uncacheGetByID(codeBlock
, vPC
);
3252 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3253 skip_get_by_id_chain
:
3254 goto *(&&skip_id_getter_self
);
3256 DEFINE_OPCODE(op_get_by_id_getter_self
) {
3257 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
3259 Cached property access: Attempts to get a cached property from the
3260 value base. If the cache misses, op_get_by_id_getter_self reverts to
3263 int base
= vPC
[2].u
.operand
;
3264 JSValue baseValue
= callFrame
->r(base
).jsValue();
3266 if (LIKELY(baseValue
.isCell())) {
3267 JSCell
* baseCell
= baseValue
.asCell();
3268 Structure
* structure
= vPC
[4].u
.structure
.get();
3270 if (LIKELY(baseCell
->structure() == structure
)) {
3271 ASSERT(baseCell
->isObject());
3272 JSObject
* baseObject
= asObject(baseCell
);
3273 int dst
= vPC
[1].u
.operand
;
3274 int offset
= vPC
[5].u
.operand
;
3276 if (GetterSetter
* getterSetter
= asGetterSetter(baseObject
->getDirectOffset(offset
).asCell())) {
3277 JSObject
* getter
= getterSetter
->getter();
3279 CallType callType
= getter
->methodTable()->getCallData(getter
, callData
);
3280 JSValue result
= call(callFrame
, getter
, callType
, callData
, baseObject
, ArgList());
3281 CHECK_FOR_EXCEPTION();
3282 callFrame
->uncheckedR(dst
) = result
;
3284 callFrame
->uncheckedR(dst
) = jsUndefined();
3286 vPC
+= OPCODE_LENGTH(op_get_by_id_getter_self
);
3290 uncacheGetByID(codeBlock
, vPC
);
3293 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3294 skip_id_getter_self
:
3296 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3297 goto *(&&skip_id_custom_self
);
3299 DEFINE_OPCODE(op_get_by_id_custom_self
) {
3300 /* op_get_by_id_custom_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
3302 Cached property access: Attempts to use a cached named property getter
3303 from the value base. If the cache misses, op_get_by_id_custom_self reverts to
3306 int base
= vPC
[2].u
.operand
;
3307 JSValue baseValue
= callFrame
->r(base
).jsValue();
3309 if (LIKELY(baseValue
.isCell())) {
3310 JSCell
* baseCell
= baseValue
.asCell();
3311 Structure
* structure
= vPC
[4].u
.structure
.get();
3313 if (LIKELY(baseCell
->structure() == structure
)) {
3314 ASSERT(baseCell
->isObject());
3315 int dst
= vPC
[1].u
.operand
;
3316 int property
= vPC
[3].u
.operand
;
3317 Identifier
& ident
= codeBlock
->identifier(property
);
3319 PropertySlot::GetValueFunc getter
= vPC
[5].u
.getterFunc
;
3320 JSValue result
= getter(callFrame
, baseValue
, ident
);
3321 CHECK_FOR_EXCEPTION();
3322 callFrame
->uncheckedR(dst
) = result
;
3323 vPC
+= OPCODE_LENGTH(op_get_by_id_custom_self
);
3327 uncacheGetByID(codeBlock
, vPC
);
3330 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3331 skip_id_custom_self
:
3333 DEFINE_OPCODE(op_get_by_id_generic
) {
3334 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3336 Generic property access: Gets the property named by identifier
3337 property from the value base, and puts the result in register dst.
3339 int dst
= vPC
[1].u
.operand
;
3340 int base
= vPC
[2].u
.operand
;
3341 int property
= vPC
[3].u
.operand
;
3343 Identifier
& ident
= codeBlock
->identifier(property
);
3344 JSValue baseValue
= callFrame
->r(base
).jsValue();
3345 PropertySlot
slot(baseValue
);
3346 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
3347 CHECK_FOR_EXCEPTION();
3349 callFrame
->uncheckedR(dst
) = result
;
3350 vPC
+= OPCODE_LENGTH(op_get_by_id_generic
);
3353 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3354 goto *(&&skip_id_getter_chain
);
3356 DEFINE_OPCODE(op_get_by_id_getter_chain
) {
3357 /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
3359 Cached property access: Attempts to get a cached property from the
3360 value base's prototype chain. If the cache misses, op_get_by_id_getter_chain
3361 reverts to op_get_by_id.
3363 int base
= vPC
[2].u
.operand
;
3364 JSValue baseValue
= callFrame
->r(base
).jsValue();
3366 if (LIKELY(baseValue
.isCell())) {
3367 JSCell
* baseCell
= baseValue
.asCell();
3368 Structure
* structure
= vPC
[4].u
.structure
.get();
3370 if (LIKELY(baseCell
->structure() == structure
)) {
3371 WriteBarrier
<Structure
>* it
= vPC
[5].u
.structureChain
->head();
3372 size_t count
= vPC
[6].u
.operand
;
3373 WriteBarrier
<Structure
>* end
= it
+ count
;
3376 JSObject
* baseObject
= asObject(baseCell
->structure()->prototypeForLookup(callFrame
));
3378 if (UNLIKELY(baseObject
->structure() != (*it
).get()))
3382 int dst
= vPC
[1].u
.operand
;
3383 int offset
= vPC
[7].u
.operand
;
3384 if (GetterSetter
* getterSetter
= asGetterSetter(baseObject
->getDirectOffset(offset
).asCell())) {
3385 JSObject
* getter
= getterSetter
->getter();
3387 CallType callType
= getter
->methodTable()->getCallData(getter
, callData
);
3388 JSValue result
= call(callFrame
, getter
, callType
, callData
, baseValue
, ArgList());
3389 CHECK_FOR_EXCEPTION();
3390 callFrame
->uncheckedR(dst
) = result
;
3392 callFrame
->uncheckedR(dst
) = jsUndefined();
3393 vPC
+= OPCODE_LENGTH(op_get_by_id_getter_chain
);
3397 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
3398 baseCell
= baseObject
;
3402 uncacheGetByID(codeBlock
, vPC
);
3405 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3406 skip_id_getter_chain
:
3408 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3409 goto *(&&skip_id_custom_chain
);
3411 DEFINE_OPCODE(op_get_by_id_custom_chain
) {
3412 /* op_get_by_id_custom_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
3414 Cached property access: Attempts to use a cached named property getter on the
3415 value base's prototype chain. If the cache misses, op_get_by_id_custom_chain
3416 reverts to op_get_by_id.
3418 int base
= vPC
[2].u
.operand
;
3419 JSValue baseValue
= callFrame
->r(base
).jsValue();
3421 if (LIKELY(baseValue
.isCell())) {
3422 JSCell
* baseCell
= baseValue
.asCell();
3423 Structure
* structure
= vPC
[4].u
.structure
.get();
3425 if (LIKELY(baseCell
->structure() == structure
)) {
3426 WriteBarrier
<Structure
>* it
= vPC
[5].u
.structureChain
->head();
3427 size_t count
= vPC
[6].u
.operand
;
3428 WriteBarrier
<Structure
>* end
= it
+ count
;
3431 JSObject
* baseObject
= asObject(baseCell
->structure()->prototypeForLookup(callFrame
));
3433 if (UNLIKELY(baseObject
->structure() != (*it
).get()))
3437 int dst
= vPC
[1].u
.operand
;
3438 int property
= vPC
[3].u
.operand
;
3439 Identifier
& ident
= codeBlock
->identifier(property
);
3441 PropertySlot::GetValueFunc getter
= vPC
[7].u
.getterFunc
;
3442 JSValue result
= getter(callFrame
, baseObject
, ident
);
3443 CHECK_FOR_EXCEPTION();
3444 callFrame
->uncheckedR(dst
) = result
;
3445 vPC
+= OPCODE_LENGTH(op_get_by_id_custom_chain
);
3449 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
3450 baseCell
= baseObject
;
3454 uncacheGetByID(codeBlock
, vPC
);
3457 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3458 skip_id_custom_chain
:
3459 goto *(&&skip_get_array_length
);
3461 DEFINE_OPCODE(op_get_array_length
) {
3462 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3464 Cached property access: Gets the length of the array in register base,
3465 and puts the result in register dst. If register base does not hold
3466 an array, op_get_array_length reverts to op_get_by_id.
3469 int base
= vPC
[2].u
.operand
;
3470 JSValue baseValue
= callFrame
->r(base
).jsValue();
3471 if (LIKELY(isJSArray(baseValue
))) {
3472 int dst
= vPC
[1].u
.operand
;
3473 callFrame
->uncheckedR(dst
) = jsNumber(asArray(baseValue
)->length());
3474 vPC
+= OPCODE_LENGTH(op_get_array_length
);
3478 uncacheGetByID(codeBlock
, vPC
);
3481 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3482 skip_get_array_length
:
3483 goto *(&&skip_get_string_length
);
3485 DEFINE_OPCODE(op_get_string_length
) {
3486 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3488 Cached property access: Gets the length of the string in register base,
3489 and puts the result in register dst. If register base does not hold
3490 a string, op_get_string_length reverts to op_get_by_id.
3493 int base
= vPC
[2].u
.operand
;
3494 JSValue baseValue
= callFrame
->r(base
).jsValue();
3495 if (LIKELY(isJSString(baseValue
))) {
3496 int dst
= vPC
[1].u
.operand
;
3497 callFrame
->uncheckedR(dst
) = jsNumber(asString(baseValue
)->length());
3498 vPC
+= OPCODE_LENGTH(op_get_string_length
);
3502 uncacheGetByID(codeBlock
, vPC
);
3505 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3506 skip_get_string_length
:
3507 goto *(&&skip_put_by_id
);
3509 DEFINE_OPCODE(op_put_by_id
) {
3510 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
3512 Generic property access: Sets the property named by identifier
3513 property, belonging to register base, to register value.
3515 Unlike many opcodes, this one does not write any output to
3518 The "direct" flag should only be set this put_by_id is to initialize
3522 int base
= vPC
[1].u
.operand
;
3523 int property
= vPC
[2].u
.operand
;
3524 int value
= vPC
[3].u
.operand
;
3525 int direct
= vPC
[8].u
.operand
;
3527 JSValue baseValue
= callFrame
->r(base
).jsValue();
3528 Identifier
& ident
= codeBlock
->identifier(property
);
3529 PutPropertySlot
slot(codeBlock
->isStrictMode());
3531 ASSERT(baseValue
.isObject());
3532 asObject(baseValue
)->putDirect(*globalData
, ident
, callFrame
->r(value
).jsValue(), slot
);
3534 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
3535 CHECK_FOR_EXCEPTION();
3537 tryCachePutByID(callFrame
, codeBlock
, vPC
, baseValue
, slot
);
3539 vPC
+= OPCODE_LENGTH(op_put_by_id
);
3542 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3545 DEFINE_OPCODE(op_put_by_id_transition_direct
)
3546 DEFINE_OPCODE(op_put_by_id_transition_normal
)
3547 DEFINE_OPCODE(op_put_by_id_transition
) {
3548 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b)
3550 Cached property access: Attempts to set a new property with a cached transition
3551 property named by identifier property, belonging to register base,
3552 to register value. If the cache misses, op_put_by_id_transition
3553 reverts to op_put_by_id_generic.
3555 Unlike many opcodes, this one does not write any output to
3558 int base
= vPC
[1].u
.operand
;
3559 JSValue baseValue
= callFrame
->r(base
).jsValue();
3561 if (LIKELY(baseValue
.isCell())) {
3562 JSCell
* baseCell
= baseValue
.asCell();
3563 Structure
* oldStructure
= vPC
[4].u
.structure
.get();
3564 Structure
* newStructure
= vPC
[5].u
.structure
.get();
3566 if (LIKELY(baseCell
->structure() == oldStructure
)) {
3567 ASSERT(baseCell
->isObject());
3568 JSObject
* baseObject
= asObject(baseCell
);
3569 int direct
= vPC
[8].u
.operand
;
3572 WriteBarrier
<Structure
>* it
= vPC
[6].u
.structureChain
->head();
3574 JSValue proto
= baseObject
->structure()->prototypeForLookup(callFrame
);
3575 while (!proto
.isNull()) {
3576 if (UNLIKELY(asObject(proto
)->structure() != (*it
).get())) {
3577 uncachePutByID(codeBlock
, vPC
);
3581 proto
= asObject(proto
)->structure()->prototypeForLookup(callFrame
);
3584 baseObject
->transitionTo(*globalData
, newStructure
);
3586 int value
= vPC
[3].u
.operand
;
3587 unsigned offset
= vPC
[7].u
.operand
;
3588 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(*globalData
, codeBlock
->identifier(vPC
[2].u
.operand
))) == offset
);
3589 baseObject
->putDirectOffset(callFrame
->globalData(), offset
, callFrame
->r(value
).jsValue());
3591 vPC
+= OPCODE_LENGTH(op_put_by_id_transition
);
3596 uncachePutByID(codeBlock
, vPC
);
3599 DEFINE_OPCODE(op_put_by_id_replace
) {
3600 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n) direct(b)
3602 Cached property access: Attempts to set a pre-existing, cached
3603 property named by identifier property, belonging to register base,
3604 to register value. If the cache misses, op_put_by_id_replace
3605 reverts to op_put_by_id.
3607 Unlike many opcodes, this one does not write any output to
3610 int base
= vPC
[1].u
.operand
;
3611 JSValue baseValue
= callFrame
->r(base
).jsValue();
3613 if (LIKELY(baseValue
.isCell())) {
3614 JSCell
* baseCell
= baseValue
.asCell();
3615 Structure
* structure
= vPC
[4].u
.structure
.get();
3617 if (LIKELY(baseCell
->structure() == structure
)) {
3618 ASSERT(baseCell
->isObject());
3619 JSObject
* baseObject
= asObject(baseCell
);
3620 int value
= vPC
[3].u
.operand
;
3621 unsigned offset
= vPC
[5].u
.operand
;
3623 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(*globalData
, codeBlock
->identifier(vPC
[2].u
.operand
))) == offset
);
3624 baseObject
->putDirectOffset(callFrame
->globalData(), offset
, callFrame
->r(value
).jsValue());
3626 vPC
+= OPCODE_LENGTH(op_put_by_id_replace
);
3631 uncachePutByID(codeBlock
, vPC
);
3634 DEFINE_OPCODE(op_put_by_id_generic
) {
3635 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
3637 Generic property access: Sets the property named by identifier
3638 property, belonging to register base, to register value.
3640 Unlike many opcodes, this one does not write any output to
3643 int base
= vPC
[1].u
.operand
;
3644 int property
= vPC
[2].u
.operand
;
3645 int value
= vPC
[3].u
.operand
;
3646 int direct
= vPC
[8].u
.operand
;
3648 JSValue baseValue
= callFrame
->r(base
).jsValue();
3649 Identifier
& ident
= codeBlock
->identifier(property
);
3650 PutPropertySlot
slot(codeBlock
->isStrictMode());
3652 ASSERT(baseValue
.isObject());
3653 asObject(baseValue
)->putDirect(*globalData
, ident
, callFrame
->r(value
).jsValue(), slot
);
3655 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
3656 CHECK_FOR_EXCEPTION();
3658 vPC
+= OPCODE_LENGTH(op_put_by_id_generic
);
3661 DEFINE_OPCODE(op_del_by_id
) {
3662 /* del_by_id dst(r) base(r) property(id)
3664 Converts register base to Object, deletes the property
3665 named by identifier property from the object, and writes a
3666 boolean indicating success (if true) or failure (if false)
3669 int dst
= vPC
[1].u
.operand
;
3670 int base
= vPC
[2].u
.operand
;
3671 int property
= vPC
[3].u
.operand
;
3673 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
);
3674 Identifier
& ident
= codeBlock
->identifier(property
);
3675 bool result
= baseObj
->methodTable()->deleteProperty(baseObj
, callFrame
, ident
);
3676 if (!result
&& codeBlock
->isStrictMode()) {
3677 exceptionValue
= createTypeError(callFrame
, "Unable to delete property.");
3680 CHECK_FOR_EXCEPTION();
3681 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
3682 vPC
+= OPCODE_LENGTH(op_del_by_id
);
3685 DEFINE_OPCODE(op_get_by_pname
) {
3686 int dst
= vPC
[1].u
.operand
;
3687 int base
= vPC
[2].u
.operand
;
3688 int property
= vPC
[3].u
.operand
;
3689 int expected
= vPC
[4].u
.operand
;
3690 int iter
= vPC
[5].u
.operand
;
3691 int i
= vPC
[6].u
.operand
;
3693 JSValue baseValue
= callFrame
->r(base
).jsValue();
3694 JSPropertyNameIterator
* it
= callFrame
->r(iter
).propertyNameIterator();
3695 JSValue subscript
= callFrame
->r(property
).jsValue();
3696 JSValue expectedSubscript
= callFrame
->r(expected
).jsValue();
3697 int index
= callFrame
->r(i
).i() - 1;
3700 if (subscript
== expectedSubscript
&& baseValue
.isCell() && (baseValue
.asCell()->structure() == it
->cachedStructure()) && it
->getOffset(index
, offset
)) {
3701 callFrame
->uncheckedR(dst
) = JSValue(asObject(baseValue
)->getDirectOffset(offset
));
3702 vPC
+= OPCODE_LENGTH(op_get_by_pname
);
3706 Identifier
propertyName(callFrame
, subscript
.toString(callFrame
)->value(callFrame
));
3707 result
= baseValue
.get(callFrame
, propertyName
);
3709 CHECK_FOR_EXCEPTION();
3710 callFrame
->uncheckedR(dst
) = result
;
3711 vPC
+= OPCODE_LENGTH(op_get_by_pname
);
3714 DEFINE_OPCODE(op_get_arguments_length
) {
3715 int dst
= vPC
[1].u
.operand
;
3716 int argumentsRegister
= vPC
[2].u
.operand
;
3717 int property
= vPC
[3].u
.operand
;
3718 JSValue arguments
= callFrame
->r(argumentsRegister
).jsValue();
3720 Identifier
& ident
= codeBlock
->identifier(property
);
3721 PropertySlot
slot(arguments
);
3722 JSValue result
= arguments
.get(callFrame
, ident
, slot
);
3723 CHECK_FOR_EXCEPTION();
3724 callFrame
->uncheckedR(dst
) = result
;
3726 callFrame
->uncheckedR(dst
) = jsNumber(callFrame
->argumentCount());
3728 vPC
+= OPCODE_LENGTH(op_get_arguments_length
);
3731 DEFINE_OPCODE(op_get_argument_by_val
) {
3732 int dst
= vPC
[1].u
.operand
;
3733 int argumentsRegister
= vPC
[2].u
.operand
;
3734 int property
= vPC
[3].u
.operand
;
3735 JSValue arguments
= callFrame
->r(argumentsRegister
).jsValue();
3736 JSValue subscript
= callFrame
->r(property
).jsValue();
3737 if (!arguments
&& subscript
.isUInt32() && subscript
.asUInt32() < callFrame
->argumentCount()) {
3738 callFrame
->uncheckedR(dst
) = callFrame
->argument(subscript
.asUInt32());
3739 vPC
+= OPCODE_LENGTH(op_get_argument_by_val
);
3743 Arguments
* arguments
= Arguments::create(*globalData
, callFrame
);
3744 callFrame
->uncheckedR(argumentsRegister
) = JSValue(arguments
);
3745 callFrame
->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister
)) = JSValue(arguments
);
3749 DEFINE_OPCODE(op_get_by_val
) {
3750 /* get_by_val dst(r) base(r) property(r)
3752 Converts register base to Object, gets the property named
3753 by register property from the object, and puts the result
3754 in register dst. property is nominally converted to string
3755 but numbers are treated more efficiently.
3757 int dst
= vPC
[1].u
.operand
;
3758 int base
= vPC
[2].u
.operand
;
3759 int property
= vPC
[3].u
.operand
;
3761 JSValue baseValue
= callFrame
->r(base
).jsValue();
3762 JSValue subscript
= callFrame
->r(property
).jsValue();
3766 if (LIKELY(subscript
.isUInt32())) {
3767 uint32_t i
= subscript
.asUInt32();
3768 if (isJSArray(baseValue
)) {
3769 JSArray
* jsArray
= asArray(baseValue
);
3770 if (jsArray
->canGetIndex(i
))
3771 result
= jsArray
->getIndex(i
);
3773 result
= jsArray
->JSArray::get(callFrame
, i
);
3774 } else if (isJSString(baseValue
) && asString(baseValue
)->canGetIndex(i
))
3775 result
= asString(baseValue
)->getIndex(callFrame
, i
);
3777 result
= baseValue
.get(callFrame
, i
);
3779 Identifier
property(callFrame
, subscript
.toString(callFrame
)->value(callFrame
));
3780 result
= baseValue
.get(callFrame
, property
);
3783 CHECK_FOR_EXCEPTION();
3784 callFrame
->uncheckedR(dst
) = result
;
3785 vPC
+= OPCODE_LENGTH(op_get_by_val
);
3788 DEFINE_OPCODE(op_put_by_val
) {
3789 /* put_by_val base(r) property(r) value(r)
3791 Sets register value on register base as the property named
3792 by register property. Base is converted to object
3793 first. register property is nominally converted to string
3794 but numbers are treated more efficiently.
3796 Unlike many opcodes, this one does not write any output to
3799 int base
= vPC
[1].u
.operand
;
3800 int property
= vPC
[2].u
.operand
;
3801 int value
= vPC
[3].u
.operand
;
3803 JSValue baseValue
= callFrame
->r(base
).jsValue();
3804 JSValue subscript
= callFrame
->r(property
).jsValue();
3806 if (LIKELY(subscript
.isUInt32())) {
3807 uint32_t i
= subscript
.asUInt32();
3808 if (isJSArray(baseValue
)) {
3809 JSArray
* jsArray
= asArray(baseValue
);
3810 if (jsArray
->canSetIndex(i
))
3811 jsArray
->setIndex(*globalData
, i
, callFrame
->r(value
).jsValue());
3813 jsArray
->JSArray::putByIndex(jsArray
, callFrame
, i
, callFrame
->r(value
).jsValue(), codeBlock
->isStrictMode());
3815 baseValue
.putByIndex(callFrame
, i
, callFrame
->r(value
).jsValue(), codeBlock
->isStrictMode());
3817 Identifier
property(callFrame
, subscript
.toString(callFrame
)->value(callFrame
));
3818 if (!globalData
->exception
) { // Don't put to an object if toString threw an exception.
3819 PutPropertySlot
slot(codeBlock
->isStrictMode());
3820 baseValue
.put(callFrame
, property
, callFrame
->r(value
).jsValue(), slot
);
3824 CHECK_FOR_EXCEPTION();
3825 vPC
+= OPCODE_LENGTH(op_put_by_val
);
3828 DEFINE_OPCODE(op_del_by_val
) {
3829 /* del_by_val dst(r) base(r) property(r)
3831 Converts register base to Object, deletes the property
3832 named by register property from the object, and writes a
3833 boolean indicating success (if true) or failure (if false)
3836 int dst
= vPC
[1].u
.operand
;
3837 int base
= vPC
[2].u
.operand
;
3838 int property
= vPC
[3].u
.operand
;
3840 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
); // may throw
3842 JSValue subscript
= callFrame
->r(property
).jsValue();
3845 if (subscript
.getUInt32(i
))
3846 result
= baseObj
->methodTable()->deletePropertyByIndex(baseObj
, callFrame
, i
);
3848 CHECK_FOR_EXCEPTION();
3849 Identifier
property(callFrame
, subscript
.toString(callFrame
)->value(callFrame
));
3850 CHECK_FOR_EXCEPTION();
3851 result
= baseObj
->methodTable()->deleteProperty(baseObj
, callFrame
, property
);
3853 if (!result
&& codeBlock
->isStrictMode()) {
3854 exceptionValue
= createTypeError(callFrame
, "Unable to delete property.");
3857 CHECK_FOR_EXCEPTION();
3858 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
3859 vPC
+= OPCODE_LENGTH(op_del_by_val
);
3862 DEFINE_OPCODE(op_put_by_index
) {
3863 /* put_by_index base(r) property(n) value(r)
3865 Sets register value on register base as the property named
3866 by the immediate number property. Base is converted to
3869 Unlike many opcodes, this one does not write any output to
3872 This opcode is mainly used to initialize array literals.
3874 int base
= vPC
[1].u
.operand
;
3875 unsigned property
= vPC
[2].u
.operand
;
3876 int value
= vPC
[3].u
.operand
;
3878 JSValue arrayValue
= callFrame
->r(base
).jsValue();
3879 ASSERT(isJSArray(arrayValue
));
3880 asArray(arrayValue
)->putDirectIndex(callFrame
, property
, callFrame
->r(value
).jsValue(), false);
3882 vPC
+= OPCODE_LENGTH(op_put_by_index
);
3885 DEFINE_OPCODE(op_loop
) {
3886 /* loop target(offset)
3888 Jumps unconditionally to offset target from the current
3891 Additionally this loop instruction may terminate JS execution is
3892 the JS timeout is reached.
3894 #if ENABLE(OPCODE_STATS)
3895 OpcodeStats::resetLastInstruction();
3897 int target
= vPC
[1].u
.operand
;
3898 CHECK_FOR_TIMEOUT();
3902 DEFINE_OPCODE(op_jmp
) {
3903 /* jmp target(offset)
3905 Jumps unconditionally to offset target from the current
3908 #if ENABLE(OPCODE_STATS)
3909 OpcodeStats::resetLastInstruction();
3911 int target
= vPC
[1].u
.operand
;
3916 DEFINE_OPCODE(op_loop_hint
) {
3917 // This is a no-op unless we intend on doing OSR from the interpreter.
3918 vPC
+= OPCODE_LENGTH(op_loop_hint
);
3921 DEFINE_OPCODE(op_loop_if_true
) {
3922 /* loop_if_true cond(r) target(offset)
3924 Jumps to offset target from the current instruction, if and
3925 only if register cond converts to boolean as true.
3927 Additionally this loop instruction may terminate JS execution is
3928 the JS timeout is reached.
3930 int cond
= vPC
[1].u
.operand
;
3931 int target
= vPC
[2].u
.operand
;
3932 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
3934 CHECK_FOR_TIMEOUT();
3938 vPC
+= OPCODE_LENGTH(op_loop_if_true
);
3941 DEFINE_OPCODE(op_loop_if_false
) {
3942 /* loop_if_true cond(r) target(offset)
3944 Jumps to offset target from the current instruction, if and
3945 only if register cond converts to boolean as false.
3947 Additionally this loop instruction may terminate JS execution is
3948 the JS timeout is reached.
3950 int cond
= vPC
[1].u
.operand
;
3951 int target
= vPC
[2].u
.operand
;
3952 if (!callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
3954 CHECK_FOR_TIMEOUT();
3958 vPC
+= OPCODE_LENGTH(op_loop_if_true
);
3961 DEFINE_OPCODE(op_jtrue
) {
3962 /* jtrue cond(r) target(offset)
3964 Jumps to offset target from the current instruction, if and
3965 only if register cond converts to boolean as true.
3967 int cond
= vPC
[1].u
.operand
;
3968 int target
= vPC
[2].u
.operand
;
3969 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
3974 vPC
+= OPCODE_LENGTH(op_jtrue
);
3977 DEFINE_OPCODE(op_jfalse
) {
3978 /* jfalse cond(r) target(offset)
3980 Jumps to offset target from the current instruction, if and
3981 only if register cond converts to boolean as false.
3983 int cond
= vPC
[1].u
.operand
;
3984 int target
= vPC
[2].u
.operand
;
3985 if (!callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
3990 vPC
+= OPCODE_LENGTH(op_jfalse
);
3993 DEFINE_OPCODE(op_jeq_null
) {
3994 /* jeq_null src(r) target(offset)
3996 Jumps to offset target from the current instruction, if and
3997 only if register src is null.
3999 int src
= vPC
[1].u
.operand
;
4000 int target
= vPC
[2].u
.operand
;
4001 JSValue srcValue
= callFrame
->r(src
).jsValue();
4003 if (srcValue
.isUndefinedOrNull() || (srcValue
.isCell() && srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
4008 vPC
+= OPCODE_LENGTH(op_jeq_null
);
4011 DEFINE_OPCODE(op_jneq_null
) {
4012 /* jneq_null src(r) target(offset)
4014 Jumps to offset target from the current instruction, if and
4015 only if register src is not null.
4017 int src
= vPC
[1].u
.operand
;
4018 int target
= vPC
[2].u
.operand
;
4019 JSValue srcValue
= callFrame
->r(src
).jsValue();
4021 if (!srcValue
.isUndefinedOrNull() && (!srcValue
.isCell() || !srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
4026 vPC
+= OPCODE_LENGTH(op_jneq_null
);
4029 DEFINE_OPCODE(op_jneq_ptr
) {
4030 /* jneq_ptr src(r) ptr(jsCell) target(offset)
4032 Jumps to offset target from the current instruction, if the value r is equal
4033 to ptr, using pointer equality.
4035 int src
= vPC
[1].u
.operand
;
4036 int target
= vPC
[3].u
.operand
;
4037 JSValue srcValue
= callFrame
->r(src
).jsValue();
4038 if (srcValue
!= vPC
[2].u
.jsCell
.get()) {
4043 vPC
+= OPCODE_LENGTH(op_jneq_ptr
);
4046 DEFINE_OPCODE(op_loop_if_less
) {
4047 /* loop_if_less src1(r) src2(r) target(offset)
4049 Checks whether register src1 is less than register src2, as
4050 with the ECMAScript '<' operator, and then jumps to offset
4051 target from the current instruction, if and only if the
4052 result of the comparison is true.
4054 Additionally this loop instruction may terminate JS execution is
4055 the JS timeout is reached.
4057 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4058 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4059 int target
= vPC
[3].u
.operand
;
4061 bool result
= jsLess
<true>(callFrame
, src1
, src2
);
4062 CHECK_FOR_EXCEPTION();
4066 CHECK_FOR_TIMEOUT();
4070 vPC
+= OPCODE_LENGTH(op_loop_if_less
);
4073 DEFINE_OPCODE(op_loop_if_lesseq
) {
4074 /* loop_if_lesseq src1(r) src2(r) target(offset)
4076 Checks whether register src1 is less than or equal to register
4077 src2, as with the ECMAScript '<=' operator, and then jumps to
4078 offset target from the current instruction, if and only if the
4079 result of the comparison is true.
4081 Additionally this loop instruction may terminate JS execution is
4082 the JS timeout is reached.
4084 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4085 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4086 int target
= vPC
[3].u
.operand
;
4088 bool result
= jsLessEq
<true>(callFrame
, src1
, src2
);
4089 CHECK_FOR_EXCEPTION();
4093 CHECK_FOR_TIMEOUT();
4097 vPC
+= OPCODE_LENGTH(op_loop_if_lesseq
);
4100 DEFINE_OPCODE(op_loop_if_greater
) {
4101 /* loop_if_greater src1(r) src2(r) target(offset)
4103 Checks whether register src1 is greater than register src2, as
4104 with the ECMAScript '>' operator, and then jumps to offset
4105 target from the current instruction, if and only if the
4106 result of the comparison is true.
4108 Additionally this loop instruction may terminate JS execution is
4109 the JS timeout is reached.
4111 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4112 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4113 int target
= vPC
[3].u
.operand
;
4115 bool result
= jsLess
<false>(callFrame
, src2
, src1
);
4116 CHECK_FOR_EXCEPTION();
4120 CHECK_FOR_TIMEOUT();
4124 vPC
+= OPCODE_LENGTH(op_loop_if_greater
);
4127 DEFINE_OPCODE(op_loop_if_greatereq
) {
4128 /* loop_if_greatereq src1(r) src2(r) target(offset)
4130 Checks whether register src1 is greater than or equal to register
4131 src2, as with the ECMAScript '>=' operator, and then jumps to
4132 offset target from the current instruction, if and only if the
4133 result of the comparison is true.
4135 Additionally this loop instruction may terminate JS execution is
4136 the JS timeout is reached.
4138 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4139 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4140 int target
= vPC
[3].u
.operand
;
4142 bool result
= jsLessEq
<false>(callFrame
, src2
, src1
);
4143 CHECK_FOR_EXCEPTION();
4147 CHECK_FOR_TIMEOUT();
4151 vPC
+= OPCODE_LENGTH(op_loop_if_greatereq
);
4154 DEFINE_OPCODE(op_jless
) {
4155 /* jless src1(r) src2(r) target(offset)
4157 Checks whether register src1 is less than register src2, as
4158 with the ECMAScript '<' operator, and then jumps to offset
4159 target from the current instruction, if and only if the
4160 result of the comparison is true.
4162 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4163 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4164 int target
= vPC
[3].u
.operand
;
4166 bool result
= jsLess
<true>(callFrame
, src1
, src2
);
4167 CHECK_FOR_EXCEPTION();
4174 vPC
+= OPCODE_LENGTH(op_jless
);
4177 DEFINE_OPCODE(op_jlesseq
) {
4178 /* jlesseq src1(r) src2(r) target(offset)
4180 Checks whether register src1 is less than or equal to
4181 register src2, as with the ECMAScript '<=' operator,
4182 and then jumps to offset target from the current instruction,
4183 if and only if the result of the comparison is true.
4185 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4186 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4187 int target
= vPC
[3].u
.operand
;
4189 bool result
= jsLessEq
<true>(callFrame
, src1
, src2
);
4190 CHECK_FOR_EXCEPTION();
4197 vPC
+= OPCODE_LENGTH(op_jlesseq
);
4200 DEFINE_OPCODE(op_jgreater
) {
4201 /* jgreater src1(r) src2(r) target(offset)
4203 Checks whether register src1 is greater than register src2, as
4204 with the ECMAScript '>' operator, and then jumps to offset
4205 target from the current instruction, if and only if the
4206 result of the comparison is true.
4208 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4209 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4210 int target
= vPC
[3].u
.operand
;
4212 bool result
= jsLess
<false>(callFrame
, src2
, src1
);
4213 CHECK_FOR_EXCEPTION();
4220 vPC
+= OPCODE_LENGTH(op_jgreater
);
4223 DEFINE_OPCODE(op_jgreatereq
) {
4224 /* jgreatereq src1(r) src2(r) target(offset)
4226 Checks whether register src1 is greater than or equal to
4227 register src2, as with the ECMAScript '>=' operator,
4228 and then jumps to offset target from the current instruction,
4229 if and only if the result of the comparison is true.
4231 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4232 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4233 int target
= vPC
[3].u
.operand
;
4235 bool result
= jsLessEq
<false>(callFrame
, src2
, src1
);
4236 CHECK_FOR_EXCEPTION();
4243 vPC
+= OPCODE_LENGTH(op_jgreatereq
);
4246 DEFINE_OPCODE(op_jnless
) {
4247 /* jnless src1(r) src2(r) target(offset)
4249 Checks whether register src1 is less than register src2, as
4250 with the ECMAScript '<' operator, and then jumps to offset
4251 target from the current instruction, if and only if the
4252 result of the comparison is false.
4254 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4255 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4256 int target
= vPC
[3].u
.operand
;
4258 bool result
= jsLess
<true>(callFrame
, src1
, src2
);
4259 CHECK_FOR_EXCEPTION();
4266 vPC
+= OPCODE_LENGTH(op_jnless
);
4269 DEFINE_OPCODE(op_jnlesseq
) {
4270 /* jnlesseq src1(r) src2(r) target(offset)
4272 Checks whether register src1 is less than or equal to
4273 register src2, as with the ECMAScript '<=' operator,
4274 and then jumps to offset target from the current instruction,
4275 if and only if theresult of the comparison is false.
4277 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4278 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4279 int target
= vPC
[3].u
.operand
;
4281 bool result
= jsLessEq
<true>(callFrame
, src1
, src2
);
4282 CHECK_FOR_EXCEPTION();
4289 vPC
+= OPCODE_LENGTH(op_jnlesseq
);
4292 DEFINE_OPCODE(op_jngreater
) {
4293 /* jngreater src1(r) src2(r) target(offset)
4295 Checks whether register src1 is greater than register src2, as
4296 with the ECMAScript '>' operator, and then jumps to offset
4297 target from the current instruction, if and only if the
4298 result of the comparison is false.
4300 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4301 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4302 int target
= vPC
[3].u
.operand
;
4304 bool result
= jsLess
<false>(callFrame
, src2
, src1
);
4305 CHECK_FOR_EXCEPTION();
4312 vPC
+= OPCODE_LENGTH(op_jngreater
);
4315 DEFINE_OPCODE(op_jngreatereq
) {
4316 /* jngreatereq src1(r) src2(r) target(offset)
4318 Checks whether register src1 is greater than or equal to
4319 register src2, as with the ECMAScript '>=' operator,
4320 and then jumps to offset target from the current instruction,
4321 if and only if theresult of the comparison is false.
4323 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4324 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4325 int target
= vPC
[3].u
.operand
;
4327 bool result
= jsLessEq
<false>(callFrame
, src2
, src1
);
4328 CHECK_FOR_EXCEPTION();
4335 vPC
+= OPCODE_LENGTH(op_jngreatereq
);
4338 DEFINE_OPCODE(op_switch_imm
) {
4339 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
4341 Performs a range checked switch on the scrutinee value, using
4342 the tableIndex-th immediate switch jump table. If the scrutinee value
4343 is an immediate number in the range covered by the referenced jump
4344 table, and the value at jumpTable[scrutinee value] is non-zero, then
4345 that value is used as the jump offset, otherwise defaultOffset is used.
4347 int tableIndex
= vPC
[1].u
.operand
;
4348 int defaultOffset
= vPC
[2].u
.operand
;
4349 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
4350 if (scrutinee
.isInt32())
4351 vPC
+= codeBlock
->immediateSwitchJumpTable(tableIndex
).offsetForValue(scrutinee
.asInt32(), defaultOffset
);
4352 else if (scrutinee
.isDouble() && scrutinee
.asDouble() == static_cast<int32_t>(scrutinee
.asDouble()))
4353 vPC
+= codeBlock
->immediateSwitchJumpTable(tableIndex
).offsetForValue(static_cast<int32_t>(scrutinee
.asDouble()), defaultOffset
);
4355 vPC
+= defaultOffset
;
4358 DEFINE_OPCODE(op_switch_char
) {
4359 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
4361 Performs a range checked switch on the scrutinee value, using
4362 the tableIndex-th character switch jump table. If the scrutinee value
4363 is a single character string in the range covered by the referenced jump
4364 table, and the value at jumpTable[scrutinee value] is non-zero, then
4365 that value is used as the jump offset, otherwise defaultOffset is used.
4367 int tableIndex
= vPC
[1].u
.operand
;
4368 int defaultOffset
= vPC
[2].u
.operand
;
4369 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
4370 if (!scrutinee
.isString())
4371 vPC
+= defaultOffset
;
4373 StringImpl
* value
= asString(scrutinee
)->value(callFrame
).impl();
4374 if (value
->length() != 1)
4375 vPC
+= defaultOffset
;
4377 vPC
+= codeBlock
->characterSwitchJumpTable(tableIndex
).offsetForValue((*value
)[0], defaultOffset
);
4381 DEFINE_OPCODE(op_switch_string
) {
4382 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
4384 Performs a sparse hashmap based switch on the value in the scrutinee
4385 register, using the tableIndex-th string switch jump table. If the
4386 scrutinee value is a string that exists as a key in the referenced
4387 jump table, then the value associated with the string is used as the
4388 jump offset, otherwise defaultOffset is used.
4390 int tableIndex
= vPC
[1].u
.operand
;
4391 int defaultOffset
= vPC
[2].u
.operand
;
4392 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
4393 if (!scrutinee
.isString())
4394 vPC
+= defaultOffset
;
4396 vPC
+= codeBlock
->stringSwitchJumpTable(tableIndex
).offsetForValue(asString(scrutinee
)->value(callFrame
).impl(), defaultOffset
);
4399 DEFINE_OPCODE(op_new_func
) {
4400 /* new_func dst(r) func(f)
4402 Constructs a new Function instance from function func and
4403 the current scope chain using the original Function
4404 constructor, using the rules for function declarations, and
4405 puts the result in register dst.
4407 int dst
= vPC
[1].u
.operand
;
4408 int func
= vPC
[2].u
.operand
;
4409 int shouldCheck
= vPC
[3].u
.operand
;
4410 ASSERT(codeBlock
->codeType() != FunctionCode
|| !codeBlock
->needsFullScopeChain() || callFrame
->r(codeBlock
->activationRegister()).jsValue());
4411 if (!shouldCheck
|| !callFrame
->r(dst
).jsValue())
4412 callFrame
->uncheckedR(dst
) = JSValue(codeBlock
->functionDecl(func
)->make(callFrame
, callFrame
->scopeChain()));
4414 vPC
+= OPCODE_LENGTH(op_new_func
);
4417 DEFINE_OPCODE(op_new_func_exp
) {
4418 /* new_func_exp dst(r) func(f)
4420 Constructs a new Function instance from function func and
4421 the current scope chain using the original Function
4422 constructor, using the rules for function expressions, and
4423 puts the result in register dst.
4425 int dst
= vPC
[1].u
.operand
;
4426 int funcIndex
= vPC
[2].u
.operand
;
4428 ASSERT(codeBlock
->codeType() != FunctionCode
|| !codeBlock
->needsFullScopeChain() || callFrame
->r(codeBlock
->activationRegister()).jsValue());
4429 FunctionExecutable
* function
= codeBlock
->functionExpr(funcIndex
);
4430 JSFunction
* func
= function
->make(callFrame
, callFrame
->scopeChain());
4433 The Identifier in a FunctionExpression can be referenced from inside
4434 the FunctionExpression's FunctionBody to allow the function to call
4435 itself recursively. However, unlike in a FunctionDeclaration, the
4436 Identifier in a FunctionExpression cannot be referenced from and
4437 does not affect the scope enclosing the FunctionExpression.
4439 if (!function
->name().isNull()) {
4440 JSStaticScopeObject
* functionScopeObject
= JSStaticScopeObject::create(callFrame
, function
->name(), func
, ReadOnly
| DontDelete
);
4441 func
->setScope(*globalData
, func
->scope()->push(functionScopeObject
));
4444 callFrame
->uncheckedR(dst
) = JSValue(func
);
4446 vPC
+= OPCODE_LENGTH(op_new_func_exp
);
4449 DEFINE_OPCODE(op_call_eval
) {
4450 /* call_eval func(r) argCount(n) registerOffset(n)
4452 Call a function named "eval" with no explicit "this" value
4453 (which may therefore be the eval operator). If register
4454 thisVal is the global object, and register func contains
4455 that global object's original global eval function, then
4456 perform the eval operator in local scope (interpreting
4457 the argument registers as for the "call"
4458 opcode). Otherwise, act exactly as the "call" opcode would.
4461 int func
= vPC
[1].u
.operand
;
4462 int argCount
= vPC
[2].u
.operand
;
4463 int registerOffset
= vPC
[3].u
.operand
;
4465 ASSERT(codeBlock
->codeType() != FunctionCode
|| !codeBlock
->needsFullScopeChain() || callFrame
->r(codeBlock
->activationRegister()).jsValue());
4466 JSValue funcVal
= callFrame
->r(func
).jsValue();
4468 if (isHostFunction(funcVal
, globalFuncEval
)) {
4469 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
4470 newCallFrame
->init(0, vPC
+ OPCODE_LENGTH(op_call_eval
), callFrame
->scopeChain(), callFrame
, argCount
, jsCast
<JSFunction
*>(funcVal
));
4472 JSValue result
= eval(newCallFrame
);
4473 if ((exceptionValue
= globalData
->exception
))
4475 functionReturnValue
= result
;
4477 vPC
+= OPCODE_LENGTH(op_call_eval
);
4481 // We didn't find the blessed version of eval, so process this
4482 // instruction as a normal function call.
4483 // fall through to op_call
4485 DEFINE_OPCODE(op_call
) {
4486 /* call func(r) argCount(n) registerOffset(n)
4488 Perform a function call.
4490 registerOffset is the distance the callFrame pointer should move
4491 before the VM initializes the new call frame's header.
4493 dst is where op_ret should store its result.
4496 int func
= vPC
[1].u
.operand
;
4497 int argCount
= vPC
[2].u
.operand
;
4498 int registerOffset
= vPC
[3].u
.operand
;
4500 JSValue v
= callFrame
->r(func
).jsValue();
4503 CallType callType
= getCallData(v
, callData
);
4505 if (callType
== CallTypeJS
) {
4506 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
4508 JSObject
* error
= callData
.js
.functionExecutable
->compileForCall(callFrame
, callDataScopeChain
);
4509 if (UNLIKELY(!!error
)) {
4510 exceptionValue
= error
;
4514 CallFrame
* previousCallFrame
= callFrame
;
4515 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->generatedBytecodeForCall();
4516 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
4517 if (UNLIKELY(!callFrame
)) {
4518 callFrame
= previousCallFrame
;
4519 exceptionValue
= createStackOverflowError(callFrame
);
4523 callFrame
->init(newCodeBlock
, vPC
+ OPCODE_LENGTH(op_call
), callDataScopeChain
, previousCallFrame
, argCount
, jsCast
<JSFunction
*>(v
));
4524 codeBlock
= newCodeBlock
;
4525 ASSERT(codeBlock
== callFrame
->codeBlock());
4526 *topCallFrameSlot
= callFrame
;
4527 vPC
= newCodeBlock
->instructions().begin();
4529 #if ENABLE(OPCODE_STATS)
4530 OpcodeStats::resetLastInstruction();
4536 if (callType
== CallTypeHost
) {
4537 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
4538 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
4539 newCallFrame
->init(0, vPC
+ OPCODE_LENGTH(op_call
), scopeChain
, callFrame
, argCount
, asObject(v
));
4540 JSValue returnValue
;
4542 *topCallFrameSlot
= newCallFrame
;
4543 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
4544 returnValue
= JSValue::decode(callData
.native
.function(newCallFrame
));
4545 *topCallFrameSlot
= callFrame
;
4547 CHECK_FOR_EXCEPTION();
4549 functionReturnValue
= returnValue
;
4551 vPC
+= OPCODE_LENGTH(op_call
);
4555 ASSERT(callType
== CallTypeNone
);
4557 exceptionValue
= createNotAFunctionError(callFrame
, v
);
4560 DEFINE_OPCODE(op_call_varargs
) {
4561 /* call_varargs callee(r) thisValue(r) arguments(r) firstFreeRegister(n)
4563 Perform a function call with a dynamic set of arguments.
4565 registerOffset is the distance the callFrame pointer should move
4566 before the VM initializes the new call frame's header, excluding
4567 space for arguments.
4569 dst is where op_ret should store its result.
4572 JSValue v
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
4573 JSValue thisValue
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4574 JSValue arguments
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
4575 int firstFreeRegister
= vPC
[4].u
.operand
;
4577 CallFrame
* newCallFrame
= loadVarargs(callFrame
, registerFile
, thisValue
, arguments
, firstFreeRegister
);
4578 if ((exceptionValue
= globalData
->exception
))
4580 int argCount
= newCallFrame
->argumentCountIncludingThis();
4583 CallType callType
= getCallData(v
, callData
);
4585 if (callType
== CallTypeJS
) {
4586 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
4588 JSObject
* error
= callData
.js
.functionExecutable
->compileForCall(callFrame
, callDataScopeChain
);
4589 if (UNLIKELY(!!error
)) {
4590 exceptionValue
= error
;
4594 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->generatedBytecodeForCall();
4595 newCallFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, newCallFrame
, 0, argCount
);
4596 if (UNLIKELY(!newCallFrame
)) {
4597 exceptionValue
= createStackOverflowError(callFrame
);
4601 newCallFrame
->init(newCodeBlock
, vPC
+ OPCODE_LENGTH(op_call_varargs
), callDataScopeChain
, callFrame
, argCount
, jsCast
<JSFunction
*>(v
));
4602 codeBlock
= newCodeBlock
;
4603 callFrame
= newCallFrame
;
4604 ASSERT(codeBlock
== callFrame
->codeBlock());
4605 *topCallFrameSlot
= callFrame
;
4606 vPC
= newCodeBlock
->instructions().begin();
4608 #if ENABLE(OPCODE_STATS)
4609 OpcodeStats::resetLastInstruction();
4615 if (callType
== CallTypeHost
) {
4616 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
4617 newCallFrame
->init(0, vPC
+ OPCODE_LENGTH(op_call_varargs
), scopeChain
, callFrame
, argCount
, asObject(v
));
4619 JSValue returnValue
;
4621 *topCallFrameSlot
= newCallFrame
;
4622 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
4623 returnValue
= JSValue::decode(callData
.native
.function(newCallFrame
));
4624 *topCallFrameSlot
= callFrame
;
4626 CHECK_FOR_EXCEPTION();
4628 functionReturnValue
= returnValue
;
4630 vPC
+= OPCODE_LENGTH(op_call_varargs
);
4634 ASSERT(callType
== CallTypeNone
);
4636 exceptionValue
= createNotAFunctionError(callFrame
, v
);
4639 DEFINE_OPCODE(op_tear_off_activation
) {
4640 /* tear_off_activation activation(r) arguments(r)
4642 Copy locals and named parameters from the register file to the heap.
4643 Point the bindings in 'activation' and 'arguments' to this new backing
4644 store. (Note that 'arguments' may not have been created. If created,
4645 'arguments' already holds a copy of any extra / unnamed parameters.)
4647 This opcode appears before op_ret in functions that require full scope chains.
4650 int activation
= vPC
[1].u
.operand
;
4651 int arguments
= vPC
[2].u
.operand
;
4652 ASSERT(codeBlock
->needsFullScopeChain());
4653 JSValue activationValue
= callFrame
->r(activation
).jsValue();
4654 if (activationValue
) {
4655 asActivation(activationValue
)->tearOff(*globalData
);
4657 if (JSValue argumentsValue
= callFrame
->r(unmodifiedArgumentsRegister(arguments
)).jsValue())
4658 asArguments(argumentsValue
)->didTearOffActivation(*globalData
, asActivation(activationValue
));
4659 } else if (JSValue argumentsValue
= callFrame
->r(unmodifiedArgumentsRegister(arguments
)).jsValue()) {
4660 if (!codeBlock
->isStrictMode())
4661 asArguments(argumentsValue
)->tearOff(callFrame
);
4664 vPC
+= OPCODE_LENGTH(op_tear_off_activation
);
4667 DEFINE_OPCODE(op_tear_off_arguments
) {
4668 /* tear_off_arguments arguments(r)
4670 Copy named parameters from the register file to the heap. Point the
4671 bindings in 'arguments' to this new backing store. (Note that
4672 'arguments' may not have been created. If created, 'arguments' already
4673 holds a copy of any extra / unnamed parameters.)
4675 This opcode appears before op_ret in functions that don't require full
4676 scope chains, but do use 'arguments'.
4679 int src1
= vPC
[1].u
.operand
;
4680 ASSERT(!codeBlock
->needsFullScopeChain() && codeBlock
->ownerExecutable()->usesArguments());
4682 if (JSValue arguments
= callFrame
->r(unmodifiedArgumentsRegister(src1
)).jsValue())
4683 asArguments(arguments
)->tearOff(callFrame
);
4685 vPC
+= OPCODE_LENGTH(op_tear_off_arguments
);
4688 DEFINE_OPCODE(op_ret
) {
4691 Return register result as the return value of the current
4692 function call, writing it into functionReturnValue.
4693 In addition, unwind one call frame and restore the scope
4694 chain, code block instruction pointer and register base
4695 to those of the calling function.
4698 int result
= vPC
[1].u
.operand
;
4700 JSValue returnValue
= callFrame
->r(result
).jsValue();
4702 vPC
= callFrame
->returnVPC();
4703 callFrame
= callFrame
->callerFrame();
4705 if (callFrame
->hasHostCallFrameFlag())
4708 *topCallFrameSlot
= callFrame
;
4709 functionReturnValue
= returnValue
;
4710 codeBlock
= callFrame
->codeBlock();
4711 ASSERT(codeBlock
== callFrame
->codeBlock());
4715 DEFINE_OPCODE(op_call_put_result
) {
4716 /* op_call_put_result result(r)
4718 Move call result from functionReturnValue to caller's
4719 expected return value register.
4722 callFrame
->uncheckedR(vPC
[1].u
.operand
) = functionReturnValue
;
4724 vPC
+= OPCODE_LENGTH(op_call_put_result
);
4727 DEFINE_OPCODE(op_ret_object_or_this
) {
4730 Return register result as the return value of the current
4731 function call, writing it into the caller's expected return
4732 value register. In addition, unwind one call frame and
4733 restore the scope chain, code block instruction pointer and
4734 register base to those of the calling function.
4737 int result
= vPC
[1].u
.operand
;
4739 JSValue returnValue
= callFrame
->r(result
).jsValue();
4741 if (UNLIKELY(!returnValue
.isObject()))
4742 returnValue
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4744 vPC
= callFrame
->returnVPC();
4745 callFrame
= callFrame
->callerFrame();
4747 if (callFrame
->hasHostCallFrameFlag())
4750 *topCallFrameSlot
= callFrame
;
4751 functionReturnValue
= returnValue
;
4752 codeBlock
= callFrame
->codeBlock();
4753 ASSERT(codeBlock
== callFrame
->codeBlock());
4757 DEFINE_OPCODE(op_enter
) {
4760 Initializes local variables to undefined. If the code block requires
4761 an activation, enter_with_activation is used instead.
4763 This opcode appears only at the beginning of a code block.
4767 for (size_t count
= codeBlock
->m_numVars
; i
< count
; ++i
)
4768 callFrame
->uncheckedR(i
) = jsUndefined();
4770 vPC
+= OPCODE_LENGTH(op_enter
);
4773 DEFINE_OPCODE(op_create_activation
) {
4774 /* create_activation dst(r)
4776 If the activation object for this callframe has not yet been created,
4777 this creates it and writes it back to dst.
4780 int activationReg
= vPC
[1].u
.operand
;
4781 if (!callFrame
->r(activationReg
).jsValue()) {
4782 JSActivation
* activation
= JSActivation::create(*globalData
, callFrame
, static_cast<FunctionExecutable
*>(codeBlock
->ownerExecutable()));
4783 callFrame
->r(activationReg
) = JSValue(activation
);
4784 callFrame
->setScopeChain(callFrame
->scopeChain()->push(activation
));
4786 vPC
+= OPCODE_LENGTH(op_create_activation
);
4789 DEFINE_OPCODE(op_get_callee
) {
4790 /* op_get_callee callee(r)
4792 Move callee into a register.
4795 callFrame
->uncheckedR(vPC
[1].u
.operand
) = JSValue(callFrame
->callee());
4797 vPC
+= OPCODE_LENGTH(op_get_callee
);
4800 DEFINE_OPCODE(op_create_this
) {
4801 /* op_create_this this(r) proto(r)
4803 Allocate an object as 'this', fr use in construction.
4805 This opcode should only be used at the beginning of a code
4809 int thisRegister
= vPC
[1].u
.operand
;
4810 int protoRegister
= vPC
[2].u
.operand
;
4812 JSFunction
* constructor
= jsCast
<JSFunction
*>(callFrame
->callee());
4813 #if !ASSERT_DISABLED
4814 ConstructData constructData
;
4815 ASSERT(constructor
->methodTable()->getConstructData(constructor
, constructData
) == ConstructTypeJS
);
4818 Structure
* structure
;
4819 JSValue proto
= callFrame
->r(protoRegister
).jsValue();
4820 if (proto
.isObject())
4821 structure
= asObject(proto
)->inheritorID(callFrame
->globalData());
4823 structure
= constructor
->scope()->globalObject
->emptyObjectStructure();
4824 callFrame
->uncheckedR(thisRegister
) = constructEmptyObject(callFrame
, structure
);
4826 vPC
+= OPCODE_LENGTH(op_create_this
);
4829 DEFINE_OPCODE(op_convert_this
) {
4830 /* convert_this this(r)
4832 Takes the value in the 'this' register, converts it to a
4833 value that is suitable for use as the 'this' value, and
4834 stores it in the 'this' register. This opcode is emitted
4835 to avoid doing the conversion in the caller unnecessarily.
4837 This opcode should only be used at the beginning of a code
4841 int thisRegister
= vPC
[1].u
.operand
;
4842 JSValue thisVal
= callFrame
->r(thisRegister
).jsValue();
4843 if (thisVal
.isPrimitive())
4844 callFrame
->uncheckedR(thisRegister
) = JSValue(thisVal
.toThisObject(callFrame
));
4846 vPC
+= OPCODE_LENGTH(op_convert_this
);
4849 DEFINE_OPCODE(op_init_lazy_reg
) {
4850 /* init_lazy_reg dst(r)
4852 Initialises dst(r) to JSValue().
4854 This opcode appears only at the beginning of a code block.
4856 int dst
= vPC
[1].u
.operand
;
4858 callFrame
->uncheckedR(dst
) = JSValue();
4859 vPC
+= OPCODE_LENGTH(op_init_lazy_reg
);
4862 DEFINE_OPCODE(op_create_arguments
) {
4863 /* create_arguments dst(r)
4865 Creates the 'arguments' object and places it in both the
4866 'arguments' call frame slot and the local 'arguments'
4867 register, if it has not already been initialised.
4870 int dst
= vPC
[1].u
.operand
;
4872 if (!callFrame
->r(dst
).jsValue()) {
4873 Arguments
* arguments
= Arguments::create(*globalData
, callFrame
);
4874 callFrame
->uncheckedR(dst
) = JSValue(arguments
);
4875 callFrame
->uncheckedR(unmodifiedArgumentsRegister(dst
)) = JSValue(arguments
);
4877 vPC
+= OPCODE_LENGTH(op_create_arguments
);
4880 DEFINE_OPCODE(op_construct
) {
4881 /* construct func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
4883 Invoke register "func" as a constructor. For JS
4884 functions, the calling convention is exactly as for the
4885 "call" opcode, except that the "this" value is a newly
4886 created Object. For native constructors, no "this"
4887 value is passed. In either case, the argCount and registerOffset
4888 registers are interpreted as for the "call" opcode.
4890 Register proto must contain the prototype property of
4891 register func. This is to enable polymorphic inline
4892 caching of this lookup.
4895 int func
= vPC
[1].u
.operand
;
4896 int argCount
= vPC
[2].u
.operand
;
4897 int registerOffset
= vPC
[3].u
.operand
;
4899 JSValue v
= callFrame
->r(func
).jsValue();
4901 ConstructData constructData
;
4902 ConstructType constructType
= getConstructData(v
, constructData
);
4904 if (constructType
== ConstructTypeJS
) {
4905 ScopeChainNode
* callDataScopeChain
= constructData
.js
.scopeChain
;
4907 JSObject
* error
= constructData
.js
.functionExecutable
->compileForConstruct(callFrame
, callDataScopeChain
);
4908 if (UNLIKELY(!!error
)) {
4909 exceptionValue
= error
;
4913 CallFrame
* previousCallFrame
= callFrame
;
4914 CodeBlock
* newCodeBlock
= &constructData
.js
.functionExecutable
->generatedBytecodeForConstruct();
4915 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
4916 if (UNLIKELY(!callFrame
)) {
4917 callFrame
= previousCallFrame
;
4918 exceptionValue
= createStackOverflowError(callFrame
);
4922 callFrame
->init(newCodeBlock
, vPC
+ OPCODE_LENGTH(op_construct
), callDataScopeChain
, previousCallFrame
, argCount
, jsCast
<JSFunction
*>(v
));
4923 codeBlock
= newCodeBlock
;
4924 *topCallFrameSlot
= callFrame
;
4925 vPC
= newCodeBlock
->instructions().begin();
4926 #if ENABLE(OPCODE_STATS)
4927 OpcodeStats::resetLastInstruction();
4933 if (constructType
== ConstructTypeHost
) {
4934 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
4935 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
4936 newCallFrame
->init(0, vPC
+ OPCODE_LENGTH(op_construct
), scopeChain
, callFrame
, argCount
, asObject(v
));
4938 JSValue returnValue
;
4940 *topCallFrameSlot
= newCallFrame
;
4941 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
4942 returnValue
= JSValue::decode(constructData
.native
.function(newCallFrame
));
4943 *topCallFrameSlot
= callFrame
;
4945 CHECK_FOR_EXCEPTION();
4946 functionReturnValue
= returnValue
;
4948 vPC
+= OPCODE_LENGTH(op_construct
);
4952 ASSERT(constructType
== ConstructTypeNone
);
4954 exceptionValue
= createNotAConstructorError(callFrame
, v
);
4957 DEFINE_OPCODE(op_strcat
) {
4958 /* strcat dst(r) src(r) count(n)
4960 Construct a new String instance using the original
4961 constructor, and puts the result in register dst.
4962 The string will be the result of concatenating count
4963 strings with values taken from registers starting at
4966 int dst
= vPC
[1].u
.operand
;
4967 int src
= vPC
[2].u
.operand
;
4968 int count
= vPC
[3].u
.operand
;
4970 callFrame
->uncheckedR(dst
) = concatenateStrings(callFrame
, &callFrame
->registers()[src
], count
);
4971 CHECK_FOR_EXCEPTION();
4972 vPC
+= OPCODE_LENGTH(op_strcat
);
4976 DEFINE_OPCODE(op_to_primitive
) {
4977 int dst
= vPC
[1].u
.operand
;
4978 int src
= vPC
[2].u
.operand
;
4980 callFrame
->uncheckedR(dst
) = callFrame
->r(src
).jsValue().toPrimitive(callFrame
);
4981 vPC
+= OPCODE_LENGTH(op_to_primitive
);
4985 DEFINE_OPCODE(op_push_scope
) {
4986 /* push_scope scope(r)
4988 Converts register scope to object, and pushes it onto the top
4989 of the current scope chain. The contents of the register scope
4990 are replaced by the result of toObject conversion of the scope.
4992 int scope
= vPC
[1].u
.operand
;
4993 JSValue v
= callFrame
->r(scope
).jsValue();
4994 JSObject
* o
= v
.toObject(callFrame
);
4995 CHECK_FOR_EXCEPTION();
4997 callFrame
->uncheckedR(scope
) = JSValue(o
);
4998 callFrame
->setScopeChain(callFrame
->scopeChain()->push(o
));
5000 vPC
+= OPCODE_LENGTH(op_push_scope
);
5003 DEFINE_OPCODE(op_pop_scope
) {
5006 Removes the top item from the current scope chain.
5008 callFrame
->setScopeChain(callFrame
->scopeChain()->pop());
5010 vPC
+= OPCODE_LENGTH(op_pop_scope
);
5013 DEFINE_OPCODE(op_get_pnames
) {
5014 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
5016 Creates a property name list for register base and puts it
5017 in register dst, initializing i and size for iteration. If
5018 base is undefined or null, jumps to breakTarget.
5020 int dst
= vPC
[1].u
.operand
;
5021 int base
= vPC
[2].u
.operand
;
5022 int i
= vPC
[3].u
.operand
;
5023 int size
= vPC
[4].u
.operand
;
5024 int breakTarget
= vPC
[5].u
.operand
;
5026 JSValue v
= callFrame
->r(base
).jsValue();
5027 if (v
.isUndefinedOrNull()) {
5032 JSObject
* o
= v
.toObject(callFrame
);
5033 Structure
* structure
= o
->structure();
5034 JSPropertyNameIterator
* jsPropertyNameIterator
= structure
->enumerationCache();
5035 if (!jsPropertyNameIterator
|| jsPropertyNameIterator
->cachedPrototypeChain() != structure
->prototypeChain(callFrame
))
5036 jsPropertyNameIterator
= JSPropertyNameIterator::create(callFrame
, o
);
5038 callFrame
->uncheckedR(dst
) = jsPropertyNameIterator
;
5039 callFrame
->uncheckedR(base
) = JSValue(o
);
5040 callFrame
->uncheckedR(i
) = Register::withInt(0);
5041 callFrame
->uncheckedR(size
) = Register::withInt(jsPropertyNameIterator
->size());
5042 vPC
+= OPCODE_LENGTH(op_get_pnames
);
5045 DEFINE_OPCODE(op_next_pname
) {
5046 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
5048 Copies the next name from the property name list in
5049 register iter to dst, then jumps to offset target. If there are no
5050 names left, invalidates the iterator and continues to the next
5053 int dst
= vPC
[1].u
.operand
;
5054 int base
= vPC
[2].u
.operand
;
5055 int i
= vPC
[3].u
.operand
;
5056 int size
= vPC
[4].u
.operand
;
5057 int iter
= vPC
[5].u
.operand
;
5058 int target
= vPC
[6].u
.operand
;
5060 JSPropertyNameIterator
* it
= callFrame
->r(iter
).propertyNameIterator();
5061 while (callFrame
->r(i
).i() != callFrame
->r(size
).i()) {
5062 JSValue key
= it
->get(callFrame
, asObject(callFrame
->r(base
).jsValue()), callFrame
->r(i
).i());
5063 CHECK_FOR_EXCEPTION();
5064 callFrame
->uncheckedR(i
) = Register::withInt(callFrame
->r(i
).i() + 1);
5066 CHECK_FOR_TIMEOUT();
5067 callFrame
->uncheckedR(dst
) = key
;
5073 vPC
+= OPCODE_LENGTH(op_next_pname
);
5076 DEFINE_OPCODE(op_jmp_scopes
) {
5077 /* jmp_scopes count(n) target(offset)
5079 Removes the a number of items from the current scope chain
5080 specified by immediate number count, then jumps to offset
5083 int count
= vPC
[1].u
.operand
;
5084 int target
= vPC
[2].u
.operand
;
5086 ScopeChainNode
* tmp
= callFrame
->scopeChain();
5089 callFrame
->setScopeChain(tmp
);
5094 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
5096 goto *(&&skip_new_scope
);
5098 DEFINE_OPCODE(op_push_new_scope
) {
5099 /* new_scope dst(r) property(id) value(r)
5101 Constructs a new StaticScopeObject with property set to value. That scope
5102 object is then pushed onto the ScopeChain. The scope object is then stored
5105 callFrame
->setScopeChain(createExceptionScope(callFrame
, vPC
));
5107 vPC
+= OPCODE_LENGTH(op_push_new_scope
);
5110 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
5113 DEFINE_OPCODE(op_catch
) {
5116 Retrieves the VM's current exception and puts it in register
5117 ex. This is only valid after an exception has been raised,
5118 and usually forms the beginning of an exception handler.
5120 ASSERT(exceptionValue
);
5121 ASSERT(!globalData
->exception
);
5122 int ex
= vPC
[1].u
.operand
;
5123 callFrame
->uncheckedR(ex
) = exceptionValue
;
5124 exceptionValue
= JSValue();
5126 vPC
+= OPCODE_LENGTH(op_catch
);
5129 DEFINE_OPCODE(op_throw
) {
5132 Throws register ex as an exception. This involves three
5133 steps: first, it is set as the current exception in the
5134 VM's internal state, then the stack is unwound until an
5135 exception handler or a native code boundary is found, and
5136 then control resumes at the exception handler if any or
5137 else the script returns control to the nearest native caller.
5140 int ex
= vPC
[1].u
.operand
;
5141 exceptionValue
= callFrame
->r(ex
).jsValue();
5143 handler
= throwException(callFrame
, exceptionValue
, vPC
- codeBlock
->instructions().begin());
5145 return throwError(callFrame
, exceptionValue
);
5147 codeBlock
= callFrame
->codeBlock();
5148 vPC
= codeBlock
->instructions().begin() + handler
->target
;
5151 DEFINE_OPCODE(op_throw_reference_error
) {
5152 /* op_throw_reference_error message(k)
5154 Constructs a new reference Error instance using the
5155 original constructor, using constant message as the
5156 message string. The result is thrown.
5158 UString message
= callFrame
->r(vPC
[1].u
.operand
).jsValue().toString(callFrame
)->value(callFrame
);
5159 exceptionValue
= JSValue(createReferenceError(callFrame
, message
));
5162 DEFINE_OPCODE(op_end
) {
5165 Return register result as the value of a global or eval
5166 program. Return control to the calling native code.
5169 int result
= vPC
[1].u
.operand
;
5170 return callFrame
->r(result
).jsValue();
5172 DEFINE_OPCODE(op_put_getter_setter
) {
5173 /* put_getter_setter base(r) property(id) getter(r) setter(r)
5175 Puts accessor descriptor to register base as the named
5176 identifier property. Base and function may be objects
5177 or undefined, this op should only be used for accessors
5178 defined in object literal form.
5180 Unlike many opcodes, this one does not write any output to
5183 int base
= vPC
[1].u
.operand
;
5184 int property
= vPC
[2].u
.operand
;
5185 int getterReg
= vPC
[3].u
.operand
;
5186 int setterReg
= vPC
[4].u
.operand
;
5188 ASSERT(callFrame
->r(base
).jsValue().isObject());
5189 JSObject
* baseObj
= asObject(callFrame
->r(base
).jsValue());
5190 Identifier
& ident
= codeBlock
->identifier(property
);
5192 GetterSetter
* accessor
= GetterSetter::create(callFrame
);
5194 JSValue getter
= callFrame
->r(getterReg
).jsValue();
5195 JSValue setter
= callFrame
->r(setterReg
).jsValue();
5196 ASSERT(getter
.isObject() || getter
.isUndefined());
5197 ASSERT(setter
.isObject() || setter
.isUndefined());
5198 ASSERT(getter
.isObject() || setter
.isObject());
5200 if (!getter
.isUndefined())
5201 accessor
->setGetter(callFrame
->globalData(), asObject(getter
));
5202 if (!setter
.isUndefined())
5203 accessor
->setSetter(callFrame
->globalData(), asObject(setter
));
5204 baseObj
->putDirectAccessor(callFrame
->globalData(), ident
, accessor
, Accessor
);
5206 vPC
+= OPCODE_LENGTH(op_put_getter_setter
);
5209 DEFINE_OPCODE(op_method_check
) {
5213 DEFINE_OPCODE(op_debug
) {
5214 /* debug debugHookID(n) firstLine(n) lastLine(n)
5216 Notifies the debugger of the current state of execution. This opcode
5217 is only generated while the debugger is attached.
5219 int debugHookID
= vPC
[1].u
.operand
;
5220 int firstLine
= vPC
[2].u
.operand
;
5221 int lastLine
= vPC
[3].u
.operand
;
5223 debug(callFrame
, static_cast<DebugHookID
>(debugHookID
), firstLine
, lastLine
);
5225 vPC
+= OPCODE_LENGTH(op_debug
);
5228 DEFINE_OPCODE(op_profile_will_call
) {
5229 /* op_profile_will_call function(r)
5231 Notifies the profiler of the beginning of a function call. This opcode
5232 is only generated if developer tools are enabled.
5234 int function
= vPC
[1].u
.operand
;
5236 if (*enabledProfilerReference
)
5237 (*enabledProfilerReference
)->willExecute(callFrame
, callFrame
->r(function
).jsValue());
5239 vPC
+= OPCODE_LENGTH(op_profile_will_call
);
5242 DEFINE_OPCODE(op_profile_did_call
) {
5243 /* op_profile_did_call function(r)
5245 Notifies the profiler of the end of a function call. This opcode
5246 is only generated if developer tools are enabled.
5248 int function
= vPC
[1].u
.operand
;
5250 if (*enabledProfilerReference
)
5251 (*enabledProfilerReference
)->didExecute(callFrame
, callFrame
->r(function
).jsValue());
5253 vPC
+= OPCODE_LENGTH(op_profile_did_call
);
5257 globalData
->exception
= JSValue();
5259 // The exceptionValue is a lie! (GCC produces bad code for reasons I
5260 // cannot fathom if we don't assign to the exceptionValue before branching)
5261 exceptionValue
= createInterruptedExecutionException(globalData
);
5263 JSGlobalObject
* globalObject
= callFrame
->lexicalGlobalObject();
5264 handler
= throwException(callFrame
, exceptionValue
, vPC
- codeBlock
->instructions().begin());
5266 // Can't use the callframe at this point as the scopechain, etc have
5268 return throwError(globalObject
->globalExec(), exceptionValue
);
5271 codeBlock
= callFrame
->codeBlock();
5272 vPC
= codeBlock
->instructions().begin() + handler
->target
;
5276 #if !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)
5277 } // iterator loop ends
5279 #undef NEXT_INSTRUCTION
5280 #undef DEFINE_OPCODE
5281 #undef CHECK_FOR_EXCEPTION
5282 #undef CHECK_FOR_TIMEOUT
5283 #endif // ENABLE(CLASSIC_INTERPRETER)
5286 JSValue
Interpreter::retrieveArgumentsFromVMCode(CallFrame
* callFrame
, JSFunction
* function
) const
5288 CallFrame
* functionCallFrame
= findFunctionCallFrameFromVMCode(callFrame
, function
);
5289 if (!functionCallFrame
)
5292 CodeBlock
* codeBlock
= functionCallFrame
->codeBlock();
5293 if (codeBlock
->usesArguments()) {
5294 ASSERT(codeBlock
->codeType() == FunctionCode
);
5295 int argumentsRegister
= codeBlock
->argumentsRegister();
5296 int realArgumentsRegister
= unmodifiedArgumentsRegister(argumentsRegister
);
5297 if (JSValue arguments
= functionCallFrame
->uncheckedR(argumentsRegister
).jsValue())
5299 JSValue arguments
= JSValue(Arguments::create(callFrame
->globalData(), functionCallFrame
));
5300 functionCallFrame
->r(argumentsRegister
) = arguments
;
5301 functionCallFrame
->r(realArgumentsRegister
) = arguments
;
5305 Arguments
* arguments
= Arguments::create(functionCallFrame
->globalData(), functionCallFrame
);
5306 arguments
->tearOff(functionCallFrame
);
5307 return JSValue(arguments
);
5310 JSValue
Interpreter::retrieveCallerFromVMCode(CallFrame
* callFrame
, JSFunction
* function
) const
5312 CallFrame
* functionCallFrame
= findFunctionCallFrameFromVMCode(callFrame
, function
);
5314 if (!functionCallFrame
)
5318 CallFrame
* callerFrame
= getCallerInfo(&callFrame
->globalData(), functionCallFrame
, lineNumber
);
5321 JSValue caller
= callerFrame
->callee();
5325 // Skip over function bindings.
5326 ASSERT(caller
.isObject());
5327 while (asObject(caller
)->inherits(&JSBoundFunction::s_info
)) {
5328 callerFrame
= getCallerInfo(&callFrame
->globalData(), callerFrame
, lineNumber
);
5331 caller
= callerFrame
->callee();
5339 void Interpreter::retrieveLastCaller(CallFrame
* callFrame
, int& lineNumber
, intptr_t& sourceID
, UString
& sourceURL
, JSValue
& function
) const
5341 function
= JSValue();
5343 sourceURL
= UString();
5345 CallFrame
* callerFrame
= callFrame
->callerFrame();
5346 if (callerFrame
->hasHostCallFrameFlag())
5349 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
5350 if (!callerCodeBlock
)
5352 unsigned bytecodeOffset
= 0;
5353 #if ENABLE(CLASSIC_INTERPRETER)
5354 if (!callerFrame
->globalData().canUseJIT())
5355 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callFrame
->returnVPC());
5358 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callerFrame
, callFrame
->returnPC());
5361 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callerFrame
, callFrame
->returnPC());
5363 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
- 1);
5364 sourceID
= callerCodeBlock
->ownerExecutable()->sourceID();
5365 sourceURL
= callerCodeBlock
->ownerExecutable()->sourceURL();
5366 function
= callerFrame
->callee();
5369 CallFrame
* Interpreter::findFunctionCallFrameFromVMCode(CallFrame
* callFrame
, JSFunction
* function
)
5371 for (CallFrame
* candidate
= callFrame
->trueCallFrameFromVMCode(); candidate
; candidate
= candidate
->trueCallerFrame()) {
5372 if (candidate
->callee() == function
)
5378 void Interpreter::enableSampler()
5380 #if ENABLE(OPCODE_SAMPLING)
5382 m_sampler
= adoptPtr(new SamplingTool(this));
5387 void Interpreter::dumpSampleData(ExecState
* exec
)
5389 #if ENABLE(OPCODE_SAMPLING)
5391 m_sampler
->dump(exec
);
5396 void Interpreter::startSampling()
5398 #if ENABLE(SAMPLING_THREAD)
5399 if (!m_sampleEntryDepth
)
5400 SamplingThread::start();
5402 m_sampleEntryDepth
++;
5405 void Interpreter::stopSampling()
5407 #if ENABLE(SAMPLING_THREAD)
5408 m_sampleEntryDepth
--;
5409 if (!m_sampleEntryDepth
)
5410 SamplingThread::stop();