2 * Copyright (C) 2008, 2009 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"
38 #include "Collector.h"
40 #include "DebuggerCallFrame.h"
41 #include "EvalCodeCache.h"
42 #include "ExceptionHelpers.h"
43 #include "GlobalEvalFunction.h"
44 #include "JSActivation.h"
46 #include "JSByteArray.h"
47 #include "JSFunction.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"
62 #include <wtf/Threading.h>
72 static ALWAYS_INLINE
unsigned bytecodeOffsetForPC(CallFrame
* callFrame
, CodeBlock
* codeBlock
, void* pc
)
75 return codeBlock
->getBytecodeIndex(callFrame
, ReturnAddressPtr(pc
));
77 UNUSED_PARAM(callFrame
);
78 return static_cast<Instruction
*>(pc
) - codeBlock
->instructions().begin();
82 // Returns the depth of the scope chain within a given call frame.
83 static int depth(CodeBlock
* codeBlock
, ScopeChain
& sc
)
85 if (!codeBlock
->needsFullScopeChain())
87 return sc
.localDepth();
91 NEVER_INLINE
bool Interpreter::resolve(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
93 int dst
= (vPC
+ 1)->u
.operand
;
94 int property
= (vPC
+ 2)->u
.operand
;
96 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
97 ScopeChainIterator iter
= scopeChain
->begin();
98 ScopeChainIterator end
= scopeChain
->end();
101 CodeBlock
* codeBlock
= callFrame
->codeBlock();
102 Identifier
& ident
= codeBlock
->identifier(property
);
105 PropertySlot
slot(o
);
106 if (o
->getPropertySlot(callFrame
, ident
, slot
)) {
107 JSValue result
= slot
.getValue(callFrame
, ident
);
108 exceptionValue
= callFrame
->globalData().exception
;
111 callFrame
->r(dst
) = JSValue(result
);
114 } while (++iter
!= end
);
115 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
119 NEVER_INLINE
bool Interpreter::resolveSkip(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
121 CodeBlock
* codeBlock
= callFrame
->codeBlock();
123 int dst
= (vPC
+ 1)->u
.operand
;
124 int property
= (vPC
+ 2)->u
.operand
;
125 int skip
= (vPC
+ 3)->u
.operand
+ codeBlock
->needsFullScopeChain();
127 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
128 ScopeChainIterator iter
= scopeChain
->begin();
129 ScopeChainIterator end
= scopeChain
->end();
135 Identifier
& ident
= codeBlock
->identifier(property
);
138 PropertySlot
slot(o
);
139 if (o
->getPropertySlot(callFrame
, ident
, slot
)) {
140 JSValue result
= slot
.getValue(callFrame
, ident
);
141 exceptionValue
= callFrame
->globalData().exception
;
144 callFrame
->r(dst
) = JSValue(result
);
147 } while (++iter
!= end
);
148 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
152 NEVER_INLINE
bool Interpreter::resolveGlobal(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
154 int dst
= (vPC
+ 1)->u
.operand
;
155 JSGlobalObject
* globalObject
= static_cast<JSGlobalObject
*>((vPC
+ 2)->u
.jsCell
);
156 ASSERT(globalObject
->isGlobalObject());
157 int property
= (vPC
+ 3)->u
.operand
;
158 Structure
* structure
= (vPC
+ 4)->u
.structure
;
159 int offset
= (vPC
+ 5)->u
.operand
;
161 if (structure
== globalObject
->structure()) {
162 callFrame
->r(dst
) = JSValue(globalObject
->getDirectOffset(offset
));
166 CodeBlock
* codeBlock
= callFrame
->codeBlock();
167 Identifier
& ident
= codeBlock
->identifier(property
);
168 PropertySlot
slot(globalObject
);
169 if (globalObject
->getPropertySlot(callFrame
, ident
, slot
)) {
170 JSValue result
= slot
.getValue(callFrame
, ident
);
171 if (slot
.isCacheable() && !globalObject
->structure()->isUncacheableDictionary() && slot
.slotBase() == globalObject
) {
172 if (vPC
[4].u
.structure
)
173 vPC
[4].u
.structure
->deref();
174 globalObject
->structure()->ref();
175 vPC
[4] = globalObject
->structure();
176 vPC
[5] = slot
.cachedOffset();
177 callFrame
->r(dst
) = JSValue(result
);
181 exceptionValue
= callFrame
->globalData().exception
;
184 callFrame
->r(dst
) = JSValue(result
);
188 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
192 NEVER_INLINE
void Interpreter::resolveBase(CallFrame
* callFrame
, Instruction
* vPC
)
194 int dst
= (vPC
+ 1)->u
.operand
;
195 int property
= (vPC
+ 2)->u
.operand
;
196 callFrame
->r(dst
) = JSValue(JSC::resolveBase(callFrame
, callFrame
->codeBlock()->identifier(property
), callFrame
->scopeChain()));
199 NEVER_INLINE
bool Interpreter::resolveBaseAndProperty(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
201 int baseDst
= (vPC
+ 1)->u
.operand
;
202 int propDst
= (vPC
+ 2)->u
.operand
;
203 int property
= (vPC
+ 3)->u
.operand
;
205 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
206 ScopeChainIterator iter
= scopeChain
->begin();
207 ScopeChainIterator end
= scopeChain
->end();
209 // FIXME: add scopeDepthIsZero optimization
213 CodeBlock
* codeBlock
= callFrame
->codeBlock();
214 Identifier
& ident
= codeBlock
->identifier(property
);
218 PropertySlot
slot(base
);
219 if (base
->getPropertySlot(callFrame
, ident
, slot
)) {
220 JSValue result
= slot
.getValue(callFrame
, ident
);
221 exceptionValue
= callFrame
->globalData().exception
;
224 callFrame
->r(propDst
) = JSValue(result
);
225 callFrame
->r(baseDst
) = JSValue(base
);
229 } while (iter
!= end
);
231 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
235 NEVER_INLINE
bool Interpreter::resolveBaseAndFunc(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
237 int baseDst
= (vPC
+ 1)->u
.operand
;
238 int funcDst
= (vPC
+ 2)->u
.operand
;
239 int property
= (vPC
+ 3)->u
.operand
;
241 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
242 ScopeChainIterator iter
= scopeChain
->begin();
243 ScopeChainIterator end
= scopeChain
->end();
245 // FIXME: add scopeDepthIsZero optimization
249 CodeBlock
* codeBlock
= callFrame
->codeBlock();
250 Identifier
& ident
= codeBlock
->identifier(property
);
254 PropertySlot
slot(base
);
255 if (base
->getPropertySlot(callFrame
, ident
, slot
)) {
256 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
257 // However, section 10.2.3 says that in the case where the value provided
258 // by the caller is null, the global object should be used. It also says
259 // that the section does not apply to internal functions, but for simplicity
260 // of implementation we use the global object anyway here. This guarantees
261 // that in host objects you always get a valid object for this.
262 // We also handle wrapper substitution for the global object at the same time.
263 JSObject
* thisObj
= base
->toThisObject(callFrame
);
264 JSValue result
= slot
.getValue(callFrame
, ident
);
265 exceptionValue
= callFrame
->globalData().exception
;
269 callFrame
->r(baseDst
) = JSValue(thisObj
);
270 callFrame
->r(funcDst
) = JSValue(result
);
274 } while (iter
!= end
);
276 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
280 #endif // USE(INTERPRETER)
282 ALWAYS_INLINE CallFrame
* Interpreter::slideRegisterWindowForCall(CodeBlock
* newCodeBlock
, RegisterFile
* registerFile
, CallFrame
* callFrame
, size_t registerOffset
, int argc
)
284 Register
* r
= callFrame
->registers();
285 Register
* newEnd
= r
+ registerOffset
+ newCodeBlock
->m_numCalleeRegisters
;
287 if (LIKELY(argc
== newCodeBlock
->m_numParameters
)) { // correct number of arguments
288 if (UNLIKELY(!registerFile
->grow(newEnd
)))
291 } else if (argc
< newCodeBlock
->m_numParameters
) { // too few arguments -- fill in the blanks
292 size_t omittedArgCount
= newCodeBlock
->m_numParameters
- argc
;
293 registerOffset
+= omittedArgCount
;
294 newEnd
+= omittedArgCount
;
295 if (!registerFile
->grow(newEnd
))
299 Register
* argv
= r
- RegisterFile::CallFrameHeaderSize
- omittedArgCount
;
300 for (size_t i
= 0; i
< omittedArgCount
; ++i
)
301 argv
[i
] = jsUndefined();
302 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
303 size_t numParameters
= newCodeBlock
->m_numParameters
;
304 registerOffset
+= numParameters
;
305 newEnd
+= numParameters
;
307 if (!registerFile
->grow(newEnd
))
311 Register
* argv
= r
- RegisterFile::CallFrameHeaderSize
- numParameters
- argc
;
312 for (size_t i
= 0; i
< numParameters
; ++i
)
313 argv
[i
+ argc
] = argv
[i
];
316 return CallFrame::create(r
);
320 static NEVER_INLINE
bool isInvalidParamForIn(CallFrame
* callFrame
, CodeBlock
* codeBlock
, const Instruction
* vPC
, JSValue value
, JSValue
& exceptionData
)
322 if (value
.isObject())
324 exceptionData
= createInvalidParamError(callFrame
, "in" , value
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
328 static NEVER_INLINE
bool isInvalidParamForInstanceOf(CallFrame
* callFrame
, CodeBlock
* codeBlock
, const Instruction
* vPC
, JSValue value
, JSValue
& exceptionData
)
330 if (value
.isObject() && asObject(value
)->structure()->typeInfo().implementsHasInstance())
332 exceptionData
= createInvalidParamError(callFrame
, "instanceof" , value
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
337 NEVER_INLINE JSValue
Interpreter::callEval(CallFrame
* callFrame
, RegisterFile
* registerFile
, Register
* argv
, int argc
, int registerOffset
, JSValue
& exceptionValue
)
340 return jsUndefined();
342 JSValue program
= argv
[1].jsValue();
344 if (!program
.isString())
347 UString programSource
= asString(program
)->value();
349 LiteralParser
preparser(callFrame
, programSource
, LiteralParser::NonStrictJSON
);
350 if (JSValue parsedObject
= preparser
.tryLiteralParse())
354 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
355 CodeBlock
* codeBlock
= callFrame
->codeBlock();
356 RefPtr
<EvalNode
> evalNode
= codeBlock
->evalCodeCache().get(callFrame
, programSource
, scopeChain
, exceptionValue
);
358 JSValue result
= jsUndefined();
360 result
= callFrame
->globalData().interpreter
->execute(evalNode
.get(), callFrame
, callFrame
->thisValue().toThisObject(callFrame
), callFrame
->registers() - registerFile
->start() + registerOffset
, scopeChain
, &exceptionValue
);
365 Interpreter::Interpreter()
369 #if HAVE(COMPUTED_GOTO)
370 privateExecute(InitializeAndReturn
, 0, 0, 0);
372 for (int i
= 0; i
< numOpcodeIDs
; ++i
)
373 m_opcodeIDTable
.add(m_opcodeTable
[i
], static_cast<OpcodeID
>(i
));
374 #endif // HAVE(COMPUTED_GOTO)
379 void Interpreter::dumpCallFrame(CallFrame
* callFrame
)
381 callFrame
->codeBlock()->dump(callFrame
);
382 dumpRegisters(callFrame
);
385 void Interpreter::dumpRegisters(CallFrame
* callFrame
)
387 printf("Register frame: \n\n");
388 printf("-----------------------------------------------------------------------------\n");
389 printf(" use | address | value \n");
390 printf("-----------------------------------------------------------------------------\n");
392 CodeBlock
* codeBlock
= callFrame
->codeBlock();
393 RegisterFile
* registerFile
= &callFrame
->scopeChain()->globalObject()->globalData()->interpreter
->registerFile();
398 if (codeBlock
->codeType() == GlobalCode
) {
399 it
= registerFile
->lastGlobal();
400 end
= it
+ registerFile
->numGlobals();
403 #if USE(JSVALUE32_64)
404 printf("[global var] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
));
406 printf("[global var] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
));
410 printf("-----------------------------------------------------------------------------\n");
413 it
= callFrame
->registers() - RegisterFile::CallFrameHeaderSize
- codeBlock
->m_numParameters
;
415 #if USE(JSVALUE32_64)
416 printf("[this] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
)); ++it
;
418 printf("[this] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
)); ++it
;
420 end
= it
+ max(codeBlock
->m_numParameters
- 1, 0); // - 1 to skip "this"
424 #if USE(JSVALUE32_64)
425 printf("[param] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
));
427 printf("[param] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
));
432 printf("-----------------------------------------------------------------------------\n");
433 printf("[CodeBlock] | %10p | %p \n", it
, (*it
).codeBlock()); ++it
;
434 printf("[ScopeChain] | %10p | %p \n", it
, (*it
).scopeChain()); ++it
;
435 printf("[CallerRegisters] | %10p | %d \n", it
, (*it
).i()); ++it
;
436 printf("[ReturnPC] | %10p | %p \n", it
, (*it
).vPC()); ++it
;
437 printf("[ReturnValueRegister] | %10p | %d \n", it
, (*it
).i()); ++it
;
438 printf("[ArgumentCount] | %10p | %d \n", it
, (*it
).i()); ++it
;
439 printf("[Callee] | %10p | %p \n", it
, (*it
).function()); ++it
;
440 printf("[OptionalCalleeArguments] | %10p | %p \n", it
, (*it
).arguments()); ++it
;
441 printf("-----------------------------------------------------------------------------\n");
443 int registerCount
= 0;
445 end
= it
+ codeBlock
->m_numVars
;
449 #if USE(JSVALUE32_64)
450 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
452 printf("[r%2d] | %10p | %-16s %p \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
458 printf("-----------------------------------------------------------------------------\n");
460 end
= it
+ codeBlock
->m_numCalleeRegisters
- codeBlock
->m_numVars
;
464 #if USE(JSVALUE32_64)
465 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
467 printf("[r%2d] | %10p | %-16s %p \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
473 printf("-----------------------------------------------------------------------------\n");
478 bool Interpreter::isOpcode(Opcode opcode
)
480 #if HAVE(COMPUTED_GOTO)
481 return opcode
!= HashTraits
<Opcode
>::emptyValue()
482 && !HashTraits
<Opcode
>::isDeletedValue(opcode
)
483 && m_opcodeIDTable
.contains(opcode
);
485 return opcode
>= 0 && opcode
<= op_end
;
489 NEVER_INLINE
bool Interpreter::unwindCallFrame(CallFrame
*& callFrame
, JSValue exceptionValue
, unsigned& bytecodeOffset
, CodeBlock
*& codeBlock
)
491 CodeBlock
* oldCodeBlock
= codeBlock
;
492 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
494 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
495 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
496 if (callFrame
->callee())
497 debugger
->returnEvent(debuggerCallFrame
, codeBlock
->ownerNode()->sourceID(), codeBlock
->ownerNode()->lastLine());
499 debugger
->didExecuteProgram(debuggerCallFrame
, codeBlock
->ownerNode()->sourceID(), codeBlock
->ownerNode()->lastLine());
502 if (Profiler
* profiler
= *Profiler::enabledProfilerReference()) {
503 if (callFrame
->callee())
504 profiler
->didExecute(callFrame
, callFrame
->callee());
506 profiler
->didExecute(callFrame
, codeBlock
->ownerNode()->sourceURL(), codeBlock
->ownerNode()->lineNo());
509 // If this call frame created an activation or an 'arguments' object, tear it off.
510 if (oldCodeBlock
->codeType() == FunctionCode
&& oldCodeBlock
->needsFullScopeChain()) {
511 while (!scopeChain
->object
->isObject(&JSActivation::info
))
512 scopeChain
= scopeChain
->pop();
513 static_cast<JSActivation
*>(scopeChain
->object
)->copyRegisters(callFrame
->optionalCalleeArguments());
514 } else if (Arguments
* arguments
= callFrame
->optionalCalleeArguments()) {
515 if (!arguments
->isTornOff())
516 arguments
->copyRegisters();
519 if (oldCodeBlock
->needsFullScopeChain())
522 void* returnPC
= callFrame
->returnPC();
523 callFrame
= callFrame
->callerFrame();
524 if (callFrame
->hasHostCallFrameFlag())
527 codeBlock
= callFrame
->codeBlock();
528 bytecodeOffset
= bytecodeOffsetForPC(callFrame
, codeBlock
, returnPC
);
532 NEVER_INLINE HandlerInfo
* Interpreter::throwException(CallFrame
*& callFrame
, JSValue
& exceptionValue
, unsigned bytecodeOffset
, bool explicitThrow
)
534 // Set up the exception object
536 CodeBlock
* codeBlock
= callFrame
->codeBlock();
537 if (exceptionValue
.isObject()) {
538 JSObject
* exception
= asObject(exceptionValue
);
539 if (exception
->isNotAnObjectErrorStub()) {
540 exception
= createNotAnObjectError(callFrame
, static_cast<JSNotAnObjectErrorStub
*>(exception
), bytecodeOffset
, codeBlock
);
541 exceptionValue
= exception
;
543 if (!exception
->hasProperty(callFrame
, Identifier(callFrame
, "line")) &&
544 !exception
->hasProperty(callFrame
, Identifier(callFrame
, "sourceId")) &&
545 !exception
->hasProperty(callFrame
, Identifier(callFrame
, "sourceURL")) &&
546 !exception
->hasProperty(callFrame
, Identifier(callFrame
, expressionBeginOffsetPropertyName
)) &&
547 !exception
->hasProperty(callFrame
, Identifier(callFrame
, expressionCaretOffsetPropertyName
)) &&
548 !exception
->hasProperty(callFrame
, Identifier(callFrame
, expressionEndOffsetPropertyName
))) {
553 int line
= codeBlock
->expressionRangeForBytecodeOffset(callFrame
, bytecodeOffset
, divotPoint
, startOffset
, endOffset
);
554 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "line"), jsNumber(callFrame
, line
), ReadOnly
| DontDelete
);
556 // We only hit this path for error messages and throw statements, which don't have a specific failure position
557 // So we just give the full range of the error/throw statement.
558 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, expressionBeginOffsetPropertyName
), jsNumber(callFrame
, divotPoint
- startOffset
), ReadOnly
| DontDelete
);
559 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, expressionEndOffsetPropertyName
), jsNumber(callFrame
, divotPoint
+ endOffset
), ReadOnly
| DontDelete
);
561 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "line"), jsNumber(callFrame
, codeBlock
->lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
)), ReadOnly
| DontDelete
);
562 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "sourceId"), jsNumber(callFrame
, codeBlock
->ownerNode()->sourceID()), ReadOnly
| DontDelete
);
563 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "sourceURL"), jsOwnedString(callFrame
, codeBlock
->ownerNode()->sourceURL()), ReadOnly
| DontDelete
);
566 if (exception
->isWatchdogException()) {
567 while (unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
)) {
568 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
575 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
576 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
577 debugger
->exception(debuggerCallFrame
, codeBlock
->ownerNode()->sourceID(), codeBlock
->lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
));
580 // If we throw in the middle of a call instruction, we need to notify
581 // the profiler manually that the call instruction has returned, since
582 // we'll never reach the relevant op_profile_did_call.
583 if (Profiler
* profiler
= *Profiler::enabledProfilerReference()) {
585 if (isCallBytecode(codeBlock
->instructions()[bytecodeOffset
].u
.opcode
))
586 profiler
->didExecute(callFrame
, callFrame
->r(codeBlock
->instructions()[bytecodeOffset
+ 2].u
.operand
).jsValue());
587 else if (codeBlock
->instructions()[bytecodeOffset
+ 8].u
.opcode
== getOpcode(op_construct
))
588 profiler
->didExecute(callFrame
, callFrame
->r(codeBlock
->instructions()[bytecodeOffset
+ 10].u
.operand
).jsValue());
590 int functionRegisterIndex
;
591 if (codeBlock
->functionRegisterForBytecodeOffset(bytecodeOffset
, functionRegisterIndex
))
592 profiler
->didExecute(callFrame
, callFrame
->r(functionRegisterIndex
).jsValue());
596 // Calculate an exception handler vPC, unwinding call frames as necessary.
598 HandlerInfo
* handler
= 0;
599 while (!(handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
))) {
600 if (!unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
))
604 // Now unwind the scope chain within the exception handler's call frame.
606 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
607 ScopeChain
sc(scopeChain
);
608 int scopeDelta
= depth(codeBlock
, sc
) - handler
->scopeDepth
;
609 ASSERT(scopeDelta
>= 0);
611 scopeChain
= scopeChain
->pop();
612 callFrame
->setScopeChain(scopeChain
);
617 JSValue
Interpreter::execute(ProgramNode
* programNode
, CallFrame
* callFrame
, ScopeChainNode
* scopeChain
, JSObject
* thisObj
, JSValue
* exception
)
619 ASSERT(!scopeChain
->globalData
->exception
);
621 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
622 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
623 *exception
= createStackOverflowError(callFrame
);
628 CodeBlock
* codeBlock
= &programNode
->bytecode(scopeChain
);
630 Register
* oldEnd
= m_registerFile
.end();
631 Register
* newEnd
= oldEnd
+ codeBlock
->m_numParameters
+ RegisterFile::CallFrameHeaderSize
+ codeBlock
->m_numCalleeRegisters
;
632 if (!m_registerFile
.grow(newEnd
)) {
633 *exception
= createStackOverflowError(callFrame
);
637 DynamicGlobalObjectScope
globalObjectScope(callFrame
, scopeChain
->globalObject());
639 JSGlobalObject
* lastGlobalObject
= m_registerFile
.globalObject();
640 JSGlobalObject
* globalObject
= callFrame
->dynamicGlobalObject();
641 globalObject
->copyGlobalsTo(m_registerFile
);
643 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
+ codeBlock
->m_numParameters
+ RegisterFile::CallFrameHeaderSize
);
644 newCallFrame
->r(codeBlock
->thisRegister()) = JSValue(thisObj
);
645 newCallFrame
->init(codeBlock
, 0, scopeChain
, CallFrame::noCaller(), 0, 0, 0);
647 if (codeBlock
->needsFullScopeChain())
650 Profiler
** profiler
= Profiler::enabledProfilerReference();
652 (*profiler
)->willExecute(newCallFrame
, programNode
->sourceURL(), programNode
->lineNo());
656 SamplingTool::CallRecord
callRecord(m_sampler
);
660 result
= programNode
->jitCode(scopeChain
).execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
, exception
);
662 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
, exception
);
668 (*profiler
)->didExecute(callFrame
, programNode
->sourceURL(), programNode
->lineNo());
670 if (m_reentryDepth
&& lastGlobalObject
&& globalObject
!= lastGlobalObject
)
671 lastGlobalObject
->copyGlobalsTo(m_registerFile
);
673 m_registerFile
.shrink(oldEnd
);
678 JSValue
Interpreter::execute(FunctionBodyNode
* functionBodyNode
, CallFrame
* callFrame
, JSFunction
* function
, JSObject
* thisObj
, const ArgList
& args
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
680 ASSERT(!scopeChain
->globalData
->exception
);
682 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
683 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
684 *exception
= createStackOverflowError(callFrame
);
689 Register
* oldEnd
= m_registerFile
.end();
690 int argc
= 1 + args
.size(); // implicit "this" parameter
692 if (!m_registerFile
.grow(oldEnd
+ argc
)) {
693 *exception
= createStackOverflowError(callFrame
);
697 DynamicGlobalObjectScope
globalObjectScope(callFrame
, callFrame
->globalData().dynamicGlobalObject
? callFrame
->globalData().dynamicGlobalObject
: scopeChain
->globalObject());
699 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
);
701 newCallFrame
->r(0) = JSValue(thisObj
);
702 ArgList::const_iterator end
= args
.end();
703 for (ArgList::const_iterator it
= args
.begin(); it
!= end
; ++it
)
704 newCallFrame
->r(++dst
) = *it
;
706 CodeBlock
* codeBlock
= &functionBodyNode
->bytecode(scopeChain
);
707 newCallFrame
= slideRegisterWindowForCall(codeBlock
, &m_registerFile
, newCallFrame
, argc
+ RegisterFile::CallFrameHeaderSize
, argc
);
708 if (UNLIKELY(!newCallFrame
)) {
709 *exception
= createStackOverflowError(callFrame
);
710 m_registerFile
.shrink(oldEnd
);
713 // a 0 codeBlock indicates a built-in caller
714 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), 0, argc
, function
);
716 Profiler
** profiler
= Profiler::enabledProfilerReference();
718 (*profiler
)->willExecute(callFrame
, function
);
722 SamplingTool::CallRecord
callRecord(m_sampler
);
726 result
= functionBodyNode
->jitCode(scopeChain
).execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
, exception
);
728 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
, exception
);
734 (*profiler
)->didExecute(callFrame
, function
);
736 m_registerFile
.shrink(oldEnd
);
740 CallFrameClosure
Interpreter::prepareForRepeatCall(FunctionBodyNode
* functionBodyNode
, CallFrame
* callFrame
, JSFunction
* function
, int argCount
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
742 ASSERT(!scopeChain
->globalData
->exception
);
744 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
745 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
746 *exception
= createStackOverflowError(callFrame
);
747 return CallFrameClosure();
751 Register
* oldEnd
= m_registerFile
.end();
752 int argc
= 1 + argCount
; // implicit "this" parameter
754 if (!m_registerFile
.grow(oldEnd
+ argc
)) {
755 *exception
= createStackOverflowError(callFrame
);
756 return CallFrameClosure();
759 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
);
761 for (int i
= 0; i
< argc
; ++i
)
762 newCallFrame
->r(++dst
) = jsUndefined();
764 CodeBlock
* codeBlock
= &functionBodyNode
->bytecode(scopeChain
);
765 newCallFrame
= slideRegisterWindowForCall(codeBlock
, &m_registerFile
, newCallFrame
, argc
+ RegisterFile::CallFrameHeaderSize
, argc
);
766 if (UNLIKELY(!newCallFrame
)) {
767 *exception
= createStackOverflowError(callFrame
);
768 m_registerFile
.shrink(oldEnd
);
769 return CallFrameClosure();
771 // a 0 codeBlock indicates a built-in caller
772 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), 0, argc
, function
);
774 functionBodyNode
->jitCode(scopeChain
);
777 CallFrameClosure result
= { callFrame
, newCallFrame
, function
, functionBodyNode
, scopeChain
->globalData
, oldEnd
, scopeChain
, codeBlock
->m_numParameters
, argc
};
781 JSValue
Interpreter::execute(CallFrameClosure
& closure
, JSValue
* exception
)
783 closure
.resetCallFrame();
784 Profiler
** profiler
= Profiler::enabledProfilerReference();
786 (*profiler
)->willExecute(closure
.oldCallFrame
, closure
.function
);
790 SamplingTool::CallRecord
callRecord(m_sampler
);
794 result
= closure
.functionBody
->generatedJITCode().execute(&m_registerFile
, closure
.newCallFrame
, closure
.globalData
, exception
);
796 result
= privateExecute(Normal
, &m_registerFile
, closure
.newCallFrame
, exception
);
802 (*profiler
)->didExecute(closure
.oldCallFrame
, closure
.function
);
806 void Interpreter::endRepeatCall(CallFrameClosure
& closure
)
808 m_registerFile
.shrink(closure
.oldEnd
);
811 JSValue
Interpreter::execute(EvalNode
* evalNode
, CallFrame
* callFrame
, JSObject
* thisObj
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
813 return execute(evalNode
, callFrame
, thisObj
, m_registerFile
.size() + evalNode
->bytecode(scopeChain
).m_numParameters
+ RegisterFile::CallFrameHeaderSize
, scopeChain
, exception
);
816 JSValue
Interpreter::execute(EvalNode
* evalNode
, CallFrame
* callFrame
, JSObject
* thisObj
, int globalRegisterOffset
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
818 ASSERT(!scopeChain
->globalData
->exception
);
820 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
821 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
822 *exception
= createStackOverflowError(callFrame
);
827 DynamicGlobalObjectScope
globalObjectScope(callFrame
, callFrame
->globalData().dynamicGlobalObject
? callFrame
->globalData().dynamicGlobalObject
: scopeChain
->globalObject());
829 EvalCodeBlock
* codeBlock
= &evalNode
->bytecode(scopeChain
);
831 JSVariableObject
* variableObject
;
832 for (ScopeChainNode
* node
= scopeChain
; ; node
= node
->next
) {
834 if (node
->object
->isVariableObject()) {
835 variableObject
= static_cast<JSVariableObject
*>(node
->object
);
840 { // Scope for BatchedTransitionOptimizer
842 BatchedTransitionOptimizer
optimizer(variableObject
);
844 const DeclarationStacks::VarStack
& varStack
= codeBlock
->ownerNode()->varStack();
845 DeclarationStacks::VarStack::const_iterator varStackEnd
= varStack
.end();
846 for (DeclarationStacks::VarStack::const_iterator it
= varStack
.begin(); it
!= varStackEnd
; ++it
) {
847 const Identifier
& ident
= (*it
).first
;
848 if (!variableObject
->hasProperty(callFrame
, ident
)) {
849 PutPropertySlot slot
;
850 variableObject
->put(callFrame
, ident
, jsUndefined(), slot
);
854 const DeclarationStacks::FunctionStack
& functionStack
= codeBlock
->ownerNode()->functionStack();
855 DeclarationStacks::FunctionStack::const_iterator functionStackEnd
= functionStack
.end();
856 for (DeclarationStacks::FunctionStack::const_iterator it
= functionStack
.begin(); it
!= functionStackEnd
; ++it
) {
857 PutPropertySlot slot
;
858 variableObject
->put(callFrame
, (*it
)->m_ident
, (*it
)->makeFunction(callFrame
, scopeChain
), slot
);
863 Register
* oldEnd
= m_registerFile
.end();
864 Register
* newEnd
= m_registerFile
.start() + globalRegisterOffset
+ codeBlock
->m_numCalleeRegisters
;
865 if (!m_registerFile
.grow(newEnd
)) {
866 *exception
= createStackOverflowError(callFrame
);
870 CallFrame
* newCallFrame
= CallFrame::create(m_registerFile
.start() + globalRegisterOffset
);
872 // a 0 codeBlock indicates a built-in caller
873 newCallFrame
->r(codeBlock
->thisRegister()) = JSValue(thisObj
);
874 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), 0, 0, 0);
876 if (codeBlock
->needsFullScopeChain())
879 Profiler
** profiler
= Profiler::enabledProfilerReference();
881 (*profiler
)->willExecute(newCallFrame
, evalNode
->sourceURL(), evalNode
->lineNo());
885 SamplingTool::CallRecord
callRecord(m_sampler
);
889 result
= evalNode
->jitCode(scopeChain
).execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
, exception
);
891 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
, exception
);
897 (*profiler
)->didExecute(callFrame
, evalNode
->sourceURL(), evalNode
->lineNo());
899 m_registerFile
.shrink(oldEnd
);
903 NEVER_INLINE
void Interpreter::debug(CallFrame
* callFrame
, DebugHookID debugHookID
, int firstLine
, int lastLine
)
905 Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger();
909 switch (debugHookID
) {
910 case DidEnterCallFrame
:
911 debugger
->callEvent(callFrame
, callFrame
->codeBlock()->ownerNode()->sourceID(), firstLine
);
913 case WillLeaveCallFrame
:
914 debugger
->returnEvent(callFrame
, callFrame
->codeBlock()->ownerNode()->sourceID(), lastLine
);
916 case WillExecuteStatement
:
917 debugger
->atStatement(callFrame
, callFrame
->codeBlock()->ownerNode()->sourceID(), firstLine
);
919 case WillExecuteProgram
:
920 debugger
->willExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerNode()->sourceID(), firstLine
);
922 case DidExecuteProgram
:
923 debugger
->didExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerNode()->sourceID(), lastLine
);
925 case DidReachBreakpoint
:
926 debugger
->didReachBreakpoint(callFrame
, callFrame
->codeBlock()->ownerNode()->sourceID(), lastLine
);
932 NEVER_INLINE ScopeChainNode
* Interpreter::createExceptionScope(CallFrame
* callFrame
, const Instruction
* vPC
)
934 int dst
= (++vPC
)->u
.operand
;
935 CodeBlock
* codeBlock
= callFrame
->codeBlock();
936 Identifier
& property
= codeBlock
->identifier((++vPC
)->u
.operand
);
937 JSValue value
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
938 JSObject
* scope
= new (callFrame
) JSStaticScopeObject(callFrame
, property
, value
, DontDelete
);
939 callFrame
->r(dst
) = JSValue(scope
);
941 return callFrame
->scopeChain()->push(scope
);
944 NEVER_INLINE
void Interpreter::tryCachePutByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const PutPropertySlot
& slot
)
946 // Recursive invocation may already have specialized this instruction.
947 if (vPC
[0].u
.opcode
!= getOpcode(op_put_by_id
))
950 if (!baseValue
.isCell())
953 // Uncacheable: give up.
954 if (!slot
.isCacheable()) {
955 vPC
[0] = getOpcode(op_put_by_id_generic
);
959 JSCell
* baseCell
= asCell(baseValue
);
960 Structure
* structure
= baseCell
->structure();
962 if (structure
->isUncacheableDictionary()) {
963 vPC
[0] = getOpcode(op_put_by_id_generic
);
967 // Cache miss: record Structure to compare against next time.
968 Structure
* lastStructure
= vPC
[4].u
.structure
;
969 if (structure
!= lastStructure
) {
970 // First miss: record Structure to compare against next time.
971 if (!lastStructure
) {
976 // Second miss: give up.
977 vPC
[0] = getOpcode(op_put_by_id_generic
);
981 // Cache hit: Specialize instruction and ref Structures.
983 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
984 if (baseCell
!= slot
.base()) {
985 vPC
[0] = getOpcode(op_put_by_id_generic
);
989 StructureChain
* protoChain
= structure
->prototypeChain(callFrame
);
990 if (!protoChain
->isCacheable()) {
991 vPC
[0] = getOpcode(op_put_by_id_generic
);
995 // Structure transition, cache transition info
996 if (slot
.type() == PutPropertySlot::NewProperty
) {
997 if (structure
->isDictionary()) {
998 vPC
[0] = getOpcode(op_put_by_id_generic
);
1001 vPC
[0] = getOpcode(op_put_by_id_transition
);
1002 vPC
[4] = structure
->previousID();
1004 vPC
[6] = protoChain
;
1005 vPC
[7] = slot
.cachedOffset();
1006 codeBlock
->refStructures(vPC
);
1010 vPC
[0] = getOpcode(op_put_by_id_replace
);
1011 vPC
[5] = slot
.cachedOffset();
1012 codeBlock
->refStructures(vPC
);
1015 NEVER_INLINE
void Interpreter::uncachePutByID(CodeBlock
* codeBlock
, Instruction
* vPC
)
1017 codeBlock
->derefStructures(vPC
);
1018 vPC
[0] = getOpcode(op_put_by_id
);
1022 NEVER_INLINE
void Interpreter::tryCacheGetByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const Identifier
& propertyName
, const PropertySlot
& slot
)
1024 // Recursive invocation may already have specialized this instruction.
1025 if (vPC
[0].u
.opcode
!= getOpcode(op_get_by_id
))
1028 // FIXME: Cache property access for immediates.
1029 if (!baseValue
.isCell()) {
1030 vPC
[0] = getOpcode(op_get_by_id_generic
);
1034 JSGlobalData
* globalData
= &callFrame
->globalData();
1035 if (isJSArray(globalData
, baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
1036 vPC
[0] = getOpcode(op_get_array_length
);
1040 if (isJSString(globalData
, baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
1041 vPC
[0] = getOpcode(op_get_string_length
);
1045 // Uncacheable: give up.
1046 if (!slot
.isCacheable()) {
1047 vPC
[0] = getOpcode(op_get_by_id_generic
);
1051 Structure
* structure
= asCell(baseValue
)->structure();
1053 if (structure
->isUncacheableDictionary()) {
1054 vPC
[0] = getOpcode(op_get_by_id_generic
);
1059 Structure
* lastStructure
= vPC
[4].u
.structure
;
1060 if (structure
!= lastStructure
) {
1061 // First miss: record Structure to compare against next time.
1062 if (!lastStructure
) {
1067 // Second miss: give up.
1068 vPC
[0] = getOpcode(op_get_by_id_generic
);
1072 // Cache hit: Specialize instruction and ref Structures.
1074 if (slot
.slotBase() == baseValue
) {
1075 vPC
[0] = getOpcode(op_get_by_id_self
);
1076 vPC
[5] = slot
.cachedOffset();
1078 codeBlock
->refStructures(vPC
);
1082 if (structure
->isDictionary()) {
1083 vPC
[0] = getOpcode(op_get_by_id_generic
);
1087 if (slot
.slotBase() == structure
->prototypeForLookup(callFrame
)) {
1088 ASSERT(slot
.slotBase().isObject());
1090 JSObject
* baseObject
= asObject(slot
.slotBase());
1091 size_t offset
= slot
.cachedOffset();
1093 // Since we're accessing a prototype in a loop, it's a good bet that it
1094 // should not be treated as a dictionary.
1095 if (baseObject
->structure()->isDictionary()) {
1096 baseObject
->flattenDictionaryObject();
1097 offset
= baseObject
->structure()->get(propertyName
);
1100 ASSERT(!baseObject
->structure()->isUncacheableDictionary());
1102 vPC
[0] = getOpcode(op_get_by_id_proto
);
1103 vPC
[5] = baseObject
->structure();
1106 codeBlock
->refStructures(vPC
);
1110 size_t offset
= slot
.cachedOffset();
1111 size_t count
= normalizePrototypeChain(callFrame
, baseValue
, slot
.slotBase(), propertyName
, offset
);
1113 vPC
[0] = getOpcode(op_get_by_id_generic
);
1117 StructureChain
* protoChain
= structure
->prototypeChain(callFrame
);
1118 if (!protoChain
->isCacheable()) {
1119 vPC
[0] = getOpcode(op_get_by_id_generic
);
1123 vPC
[0] = getOpcode(op_get_by_id_chain
);
1125 vPC
[5] = protoChain
;
1128 codeBlock
->refStructures(vPC
);
1131 NEVER_INLINE
void Interpreter::uncacheGetByID(CodeBlock
* codeBlock
, Instruction
* vPC
)
1133 codeBlock
->derefStructures(vPC
);
1134 vPC
[0] = getOpcode(op_get_by_id
);
1138 #endif // USE(INTERPRETER)
1140 JSValue
Interpreter::privateExecute(ExecutionFlag flag
, RegisterFile
* registerFile
, CallFrame
* callFrame
, JSValue
* exception
)
1142 // One-time initialization of our address tables. We have to put this code
1143 // here because our labels are only in scope inside this function.
1144 if (UNLIKELY(flag
== InitializeAndReturn
)) {
1145 #if HAVE(COMPUTED_GOTO)
1146 #define LIST_OPCODE_LABEL(id, length) &&id,
1147 static Opcode labels
[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL
) };
1148 for (size_t i
= 0; i
< sizeof(labels
) / sizeof(Opcode
); ++i
)
1149 m_opcodeTable
[i
] = labels
[i
];
1150 #undef LIST_OPCODE_LABEL
1151 #endif // HAVE(COMPUTED_GOTO)
1156 // Mixing Interpreter + JIT is not supported.
1157 ASSERT_NOT_REACHED();
1159 #if !USE(INTERPRETER)
1160 UNUSED_PARAM(registerFile
);
1161 UNUSED_PARAM(callFrame
);
1162 UNUSED_PARAM(exception
);
1166 JSGlobalData
* globalData
= &callFrame
->globalData();
1167 JSValue exceptionValue
;
1168 HandlerInfo
* handler
= 0;
1170 Instruction
* vPC
= callFrame
->codeBlock()->instructions().begin();
1171 Profiler
** enabledProfilerReference
= Profiler::enabledProfilerReference();
1172 unsigned tickCount
= globalData
->timeoutChecker
.ticksUntilNextCheck();
1174 #define CHECK_FOR_EXCEPTION() \
1176 if (UNLIKELY(globalData->exception != JSValue())) { \
1177 exceptionValue = globalData->exception; \
1182 #if ENABLE(OPCODE_STATS)
1183 OpcodeStats::resetLastInstruction();
1186 #define CHECK_FOR_TIMEOUT() \
1187 if (!--tickCount) { \
1188 if (globalData->timeoutChecker.didTimeOut(callFrame)) { \
1189 exceptionValue = jsNull(); \
1192 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1195 #if ENABLE(OPCODE_SAMPLING)
1196 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1198 #define SAMPLE(codeBlock, vPC)
1201 #if HAVE(COMPUTED_GOTO)
1202 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
1203 #if ENABLE(OPCODE_STATS)
1204 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1206 #define DEFINE_OPCODE(opcode) opcode:
1210 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
1211 #if ENABLE(OPCODE_STATS)
1212 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1214 #define DEFINE_OPCODE(opcode) case opcode:
1216 while (1) { // iterator loop begins
1217 interpreterLoopStart
:;
1218 switch (vPC
->u
.opcode
)
1221 DEFINE_OPCODE(op_new_object
) {
1222 /* new_object dst(r)
1224 Constructs a new empty Object instance using the original
1225 constructor, and puts the result in register dst.
1227 int dst
= (++vPC
)->u
.operand
;
1228 callFrame
->r(dst
) = JSValue(constructEmptyObject(callFrame
));
1233 DEFINE_OPCODE(op_new_array
) {
1234 /* new_array dst(r) firstArg(r) argCount(n)
1236 Constructs a new Array instance using the original
1237 constructor, and puts the result in register dst.
1238 The array will contain argCount elements with values
1239 taken from registers starting at register firstArg.
1241 int dst
= (++vPC
)->u
.operand
;
1242 int firstArg
= (++vPC
)->u
.operand
;
1243 int argCount
= (++vPC
)->u
.operand
;
1244 ArgList
args(callFrame
->registers() + firstArg
, argCount
);
1245 callFrame
->r(dst
) = JSValue(constructArray(callFrame
, args
));
1250 DEFINE_OPCODE(op_new_regexp
) {
1251 /* new_regexp dst(r) regExp(re)
1253 Constructs a new RegExp instance using the original
1254 constructor from regexp regExp, and puts the result in
1257 int dst
= (++vPC
)->u
.operand
;
1258 int regExp
= (++vPC
)->u
.operand
;
1259 callFrame
->r(dst
) = JSValue(new (globalData
) RegExpObject(callFrame
->scopeChain()->globalObject()->regExpStructure(), callFrame
->codeBlock()->regexp(regExp
)));
1264 DEFINE_OPCODE(op_mov
) {
1265 /* mov dst(r) src(r)
1267 Copies register src to register dst.
1269 int dst
= (++vPC
)->u
.operand
;
1270 int src
= (++vPC
)->u
.operand
;
1271 callFrame
->r(dst
) = callFrame
->r(src
);
1276 DEFINE_OPCODE(op_eq
) {
1277 /* eq dst(r) src1(r) src2(r)
1279 Checks whether register src1 and register src2 are equal,
1280 as with the ECMAScript '==' operator, and puts the result
1281 as a boolean in register dst.
1283 int dst
= (++vPC
)->u
.operand
;
1284 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1285 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1286 if (src1
.isInt32() && src2
.isInt32())
1287 callFrame
->r(dst
) = jsBoolean(src1
.asInt32() == src2
.asInt32());
1289 JSValue result
= jsBoolean(JSValue::equalSlowCase(callFrame
, src1
, src2
));
1290 CHECK_FOR_EXCEPTION();
1291 callFrame
->r(dst
) = result
;
1297 DEFINE_OPCODE(op_eq_null
) {
1298 /* eq_null dst(r) src(r)
1300 Checks whether register src is null, as with the ECMAScript '!='
1301 operator, and puts the result as a boolean in register dst.
1303 int dst
= (++vPC
)->u
.operand
;
1304 JSValue src
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1306 if (src
.isUndefinedOrNull()) {
1307 callFrame
->r(dst
) = jsBoolean(true);
1312 callFrame
->r(dst
) = jsBoolean(src
.isCell() && src
.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1316 DEFINE_OPCODE(op_neq
) {
1317 /* neq dst(r) src1(r) src2(r)
1319 Checks whether register src1 and register src2 are not
1320 equal, as with the ECMAScript '!=' operator, and puts the
1321 result as a boolean in register dst.
1323 int dst
= (++vPC
)->u
.operand
;
1324 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1325 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1326 if (src1
.isInt32() && src2
.isInt32())
1327 callFrame
->r(dst
) = jsBoolean(src1
.asInt32() != src2
.asInt32());
1329 JSValue result
= jsBoolean(!JSValue::equalSlowCase(callFrame
, src1
, src2
));
1330 CHECK_FOR_EXCEPTION();
1331 callFrame
->r(dst
) = result
;
1337 DEFINE_OPCODE(op_neq_null
) {
1338 /* neq_null dst(r) src(r)
1340 Checks whether register src is not null, as with the ECMAScript '!='
1341 operator, and puts the result as a boolean in register dst.
1343 int dst
= (++vPC
)->u
.operand
;
1344 JSValue src
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1346 if (src
.isUndefinedOrNull()) {
1347 callFrame
->r(dst
) = jsBoolean(false);
1352 callFrame
->r(dst
) = jsBoolean(!src
.isCell() || !asCell(src
)->structure()->typeInfo().masqueradesAsUndefined());
1356 DEFINE_OPCODE(op_stricteq
) {
1357 /* stricteq dst(r) src1(r) src2(r)
1359 Checks whether register src1 and register src2 are strictly
1360 equal, as with the ECMAScript '===' operator, and puts the
1361 result as a boolean in register dst.
1363 int dst
= (++vPC
)->u
.operand
;
1364 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1365 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1366 callFrame
->r(dst
) = jsBoolean(JSValue::strictEqual(src1
, src2
));
1371 DEFINE_OPCODE(op_nstricteq
) {
1372 /* nstricteq dst(r) src1(r) src2(r)
1374 Checks whether register src1 and register src2 are not
1375 strictly equal, as with the ECMAScript '!==' operator, and
1376 puts the result as a boolean in register dst.
1378 int dst
= (++vPC
)->u
.operand
;
1379 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1380 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1381 callFrame
->r(dst
) = jsBoolean(!JSValue::strictEqual(src1
, src2
));
1386 DEFINE_OPCODE(op_less
) {
1387 /* less dst(r) src1(r) src2(r)
1389 Checks whether register src1 is less than register src2, as
1390 with the ECMAScript '<' operator, and puts the result as
1391 a boolean in register dst.
1393 int dst
= (++vPC
)->u
.operand
;
1394 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1395 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1396 JSValue result
= jsBoolean(jsLess(callFrame
, src1
, src2
));
1397 CHECK_FOR_EXCEPTION();
1398 callFrame
->r(dst
) = result
;
1403 DEFINE_OPCODE(op_lesseq
) {
1404 /* lesseq dst(r) src1(r) src2(r)
1406 Checks whether register src1 is less than or equal to
1407 register src2, as with the ECMAScript '<=' operator, and
1408 puts the result as a boolean in register dst.
1410 int dst
= (++vPC
)->u
.operand
;
1411 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1412 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1413 JSValue result
= jsBoolean(jsLessEq(callFrame
, src1
, src2
));
1414 CHECK_FOR_EXCEPTION();
1415 callFrame
->r(dst
) = result
;
1420 DEFINE_OPCODE(op_pre_inc
) {
1421 /* pre_inc srcDst(r)
1423 Converts register srcDst to number, adds one, and puts the result
1424 back in register srcDst.
1426 int srcDst
= (++vPC
)->u
.operand
;
1427 JSValue v
= callFrame
->r(srcDst
).jsValue();
1428 if (v
.isInt32() && v
.asInt32() < INT_MAX
)
1429 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() + 1);
1431 JSValue result
= jsNumber(callFrame
, v
.toNumber(callFrame
) + 1);
1432 CHECK_FOR_EXCEPTION();
1433 callFrame
->r(srcDst
) = result
;
1439 DEFINE_OPCODE(op_pre_dec
) {
1440 /* pre_dec srcDst(r)
1442 Converts register srcDst to number, subtracts one, and puts the result
1443 back in register srcDst.
1445 int srcDst
= (++vPC
)->u
.operand
;
1446 JSValue v
= callFrame
->r(srcDst
).jsValue();
1447 if (v
.isInt32() && v
.asInt32() > INT_MIN
)
1448 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() - 1);
1450 JSValue result
= jsNumber(callFrame
, v
.toNumber(callFrame
) - 1);
1451 CHECK_FOR_EXCEPTION();
1452 callFrame
->r(srcDst
) = result
;
1458 DEFINE_OPCODE(op_post_inc
) {
1459 /* post_inc dst(r) srcDst(r)
1461 Converts register srcDst to number. The number itself is
1462 written to register dst, and the number plus one is written
1463 back to register srcDst.
1465 int dst
= (++vPC
)->u
.operand
;
1466 int srcDst
= (++vPC
)->u
.operand
;
1467 JSValue v
= callFrame
->r(srcDst
).jsValue();
1468 if (v
.isInt32() && v
.asInt32() < INT_MAX
) {
1469 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() + 1);
1470 callFrame
->r(dst
) = v
;
1472 JSValue number
= callFrame
->r(srcDst
).jsValue().toJSNumber(callFrame
);
1473 CHECK_FOR_EXCEPTION();
1474 callFrame
->r(srcDst
) = jsNumber(callFrame
, number
.uncheckedGetNumber() + 1);
1475 callFrame
->r(dst
) = number
;
1481 DEFINE_OPCODE(op_post_dec
) {
1482 /* post_dec dst(r) srcDst(r)
1484 Converts register srcDst to number. The number itself is
1485 written to register dst, and the number minus one is written
1486 back to register srcDst.
1488 int dst
= (++vPC
)->u
.operand
;
1489 int srcDst
= (++vPC
)->u
.operand
;
1490 JSValue v
= callFrame
->r(srcDst
).jsValue();
1491 if (v
.isInt32() && v
.asInt32() > INT_MIN
) {
1492 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() - 1);
1493 callFrame
->r(dst
) = v
;
1495 JSValue number
= callFrame
->r(srcDst
).jsValue().toJSNumber(callFrame
);
1496 CHECK_FOR_EXCEPTION();
1497 callFrame
->r(srcDst
) = jsNumber(callFrame
, number
.uncheckedGetNumber() - 1);
1498 callFrame
->r(dst
) = number
;
1504 DEFINE_OPCODE(op_to_jsnumber
) {
1505 /* to_jsnumber dst(r) src(r)
1507 Converts register src to number, and puts the result
1510 int dst
= (++vPC
)->u
.operand
;
1511 int src
= (++vPC
)->u
.operand
;
1513 JSValue srcVal
= callFrame
->r(src
).jsValue();
1515 if (LIKELY(srcVal
.isNumber()))
1516 callFrame
->r(dst
) = callFrame
->r(src
);
1518 JSValue result
= srcVal
.toJSNumber(callFrame
);
1519 CHECK_FOR_EXCEPTION();
1520 callFrame
->r(dst
) = result
;
1526 DEFINE_OPCODE(op_negate
) {
1527 /* negate dst(r) src(r)
1529 Converts register src to number, negates it, and puts the
1530 result in register dst.
1532 int dst
= (++vPC
)->u
.operand
;
1533 JSValue src
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1534 if (src
.isInt32() && src
.asInt32())
1535 callFrame
->r(dst
) = jsNumber(callFrame
, -src
.asInt32());
1537 JSValue result
= jsNumber(callFrame
, -src
.toNumber(callFrame
));
1538 CHECK_FOR_EXCEPTION();
1539 callFrame
->r(dst
) = result
;
1545 DEFINE_OPCODE(op_add
) {
1546 /* add dst(r) src1(r) src2(r)
1548 Adds register src1 and register src2, and puts the result
1549 in register dst. (JS add may be string concatenation or
1550 numeric add, depending on the types of the operands.)
1552 int dst
= (++vPC
)->u
.operand
;
1553 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1554 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1555 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | src2
.asInt32() & 0xc0000000)) // no overflow
1556 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() + src2
.asInt32());
1558 JSValue result
= jsAdd(callFrame
, src1
, src2
);
1559 CHECK_FOR_EXCEPTION();
1560 callFrame
->r(dst
) = result
;
1565 DEFINE_OPCODE(op_mul
) {
1566 /* mul dst(r) src1(r) src2(r)
1568 Multiplies register src1 and register src2 (converted to
1569 numbers), and puts the product in register dst.
1571 int dst
= (++vPC
)->u
.operand
;
1572 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1573 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1574 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | src2
.asInt32() >> 15)) // no overflow
1575 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() * src2
.asInt32());
1577 JSValue result
= jsNumber(callFrame
, src1
.toNumber(callFrame
) * src2
.toNumber(callFrame
));
1578 CHECK_FOR_EXCEPTION();
1579 callFrame
->r(dst
) = result
;
1585 DEFINE_OPCODE(op_div
) {
1586 /* div dst(r) dividend(r) divisor(r)
1588 Divides register dividend (converted to number) by the
1589 register divisor (converted to number), and puts the
1590 quotient in register dst.
1592 int dst
= (++vPC
)->u
.operand
;
1593 JSValue dividend
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1594 JSValue divisor
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1596 JSValue result
= jsNumber(callFrame
, dividend
.toNumber(callFrame
) / divisor
.toNumber(callFrame
));
1597 CHECK_FOR_EXCEPTION();
1598 callFrame
->r(dst
) = result
;
1603 DEFINE_OPCODE(op_mod
) {
1604 /* mod dst(r) dividend(r) divisor(r)
1606 Divides register dividend (converted to number) by
1607 register divisor (converted to number), and puts the
1608 remainder in register dst.
1610 int dst
= (++vPC
)->u
.operand
;
1611 JSValue dividend
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1612 JSValue divisor
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1614 if (dividend
.isInt32() && divisor
.isInt32() && divisor
.asInt32() != 0) {
1615 JSValue result
= jsNumber(callFrame
, dividend
.asInt32() % divisor
.asInt32());
1617 callFrame
->r(dst
) = result
;
1622 // Conversion to double must happen outside the call to fmod since the
1623 // order of argument evaluation is not guaranteed.
1624 double d1
= dividend
.toNumber(callFrame
);
1625 double d2
= divisor
.toNumber(callFrame
);
1626 JSValue result
= jsNumber(callFrame
, fmod(d1
, d2
));
1627 CHECK_FOR_EXCEPTION();
1628 callFrame
->r(dst
) = result
;
1632 DEFINE_OPCODE(op_sub
) {
1633 /* sub dst(r) src1(r) src2(r)
1635 Subtracts register src2 (converted to number) from register
1636 src1 (converted to number), and puts the difference in
1639 int dst
= (++vPC
)->u
.operand
;
1640 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1641 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1642 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | src2
.asInt32() & 0xc0000000)) // no overflow
1643 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() - src2
.asInt32());
1645 JSValue result
= jsNumber(callFrame
, src1
.toNumber(callFrame
) - src2
.toNumber(callFrame
));
1646 CHECK_FOR_EXCEPTION();
1647 callFrame
->r(dst
) = result
;
1652 DEFINE_OPCODE(op_lshift
) {
1653 /* lshift dst(r) val(r) shift(r)
1655 Performs left shift of register val (converted to int32) by
1656 register shift (converted to uint32), and puts the result
1659 int dst
= (++vPC
)->u
.operand
;
1660 JSValue val
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1661 JSValue shift
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1663 if (val
.isInt32() && shift
.isInt32())
1664 callFrame
->r(dst
) = jsNumber(callFrame
, val
.asInt32() << (shift
.asInt32() & 0x1f));
1666 JSValue result
= jsNumber(callFrame
, (val
.toInt32(callFrame
)) << (shift
.toUInt32(callFrame
) & 0x1f));
1667 CHECK_FOR_EXCEPTION();
1668 callFrame
->r(dst
) = result
;
1674 DEFINE_OPCODE(op_rshift
) {
1675 /* rshift dst(r) val(r) shift(r)
1677 Performs arithmetic right shift of register val (converted
1678 to int32) by register shift (converted to
1679 uint32), and puts the result in register dst.
1681 int dst
= (++vPC
)->u
.operand
;
1682 JSValue val
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1683 JSValue shift
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1685 if (val
.isInt32() && shift
.isInt32())
1686 callFrame
->r(dst
) = jsNumber(callFrame
, val
.asInt32() >> (shift
.asInt32() & 0x1f));
1688 JSValue result
= jsNumber(callFrame
, (val
.toInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
1689 CHECK_FOR_EXCEPTION();
1690 callFrame
->r(dst
) = result
;
1696 DEFINE_OPCODE(op_urshift
) {
1697 /* rshift dst(r) val(r) shift(r)
1699 Performs logical right shift of register val (converted
1700 to uint32) by register shift (converted to
1701 uint32), and puts the result in register dst.
1703 int dst
= (++vPC
)->u
.operand
;
1704 JSValue val
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1705 JSValue shift
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1706 if (val
.isUInt32() && shift
.isInt32())
1707 callFrame
->r(dst
) = jsNumber(callFrame
, val
.asInt32() >> (shift
.asInt32() & 0x1f));
1709 JSValue result
= jsNumber(callFrame
, (val
.toUInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
1710 CHECK_FOR_EXCEPTION();
1711 callFrame
->r(dst
) = result
;
1717 DEFINE_OPCODE(op_bitand
) {
1718 /* bitand dst(r) src1(r) src2(r)
1720 Computes bitwise AND of register src1 (converted to int32)
1721 and register src2 (converted to int32), and puts the result
1724 int dst
= (++vPC
)->u
.operand
;
1725 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1726 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1727 if (src1
.isInt32() && src2
.isInt32())
1728 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() & src2
.asInt32());
1730 JSValue result
= jsNumber(callFrame
, src1
.toInt32(callFrame
) & src2
.toInt32(callFrame
));
1731 CHECK_FOR_EXCEPTION();
1732 callFrame
->r(dst
) = result
;
1738 DEFINE_OPCODE(op_bitxor
) {
1739 /* bitxor dst(r) src1(r) src2(r)
1741 Computes bitwise XOR of register src1 (converted to int32)
1742 and register src2 (converted to int32), and puts the result
1745 int dst
= (++vPC
)->u
.operand
;
1746 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1747 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1748 if (src1
.isInt32() && src2
.isInt32())
1749 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() ^ src2
.asInt32());
1751 JSValue result
= jsNumber(callFrame
, src1
.toInt32(callFrame
) ^ src2
.toInt32(callFrame
));
1752 CHECK_FOR_EXCEPTION();
1753 callFrame
->r(dst
) = result
;
1759 DEFINE_OPCODE(op_bitor
) {
1760 /* bitor dst(r) src1(r) src2(r)
1762 Computes bitwise OR of register src1 (converted to int32)
1763 and register src2 (converted to int32), and puts the
1764 result in register dst.
1766 int dst
= (++vPC
)->u
.operand
;
1767 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1768 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1769 if (src1
.isInt32() && src2
.isInt32())
1770 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() | src2
.asInt32());
1772 JSValue result
= jsNumber(callFrame
, src1
.toInt32(callFrame
) | src2
.toInt32(callFrame
));
1773 CHECK_FOR_EXCEPTION();
1774 callFrame
->r(dst
) = result
;
1780 DEFINE_OPCODE(op_bitnot
) {
1781 /* bitnot dst(r) src(r)
1783 Computes bitwise NOT of register src1 (converted to int32),
1784 and puts the result in register dst.
1786 int dst
= (++vPC
)->u
.operand
;
1787 JSValue src
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
1789 callFrame
->r(dst
) = jsNumber(callFrame
, ~src
.asInt32());
1791 JSValue result
= jsNumber(callFrame
, ~src
.toInt32(callFrame
));
1792 CHECK_FOR_EXCEPTION();
1793 callFrame
->r(dst
) = result
;
1798 DEFINE_OPCODE(op_not
) {
1799 /* not dst(r) src(r)
1801 Computes logical NOT of register src (converted to
1802 boolean), and puts the result in register dst.
1804 int dst
= (++vPC
)->u
.operand
;
1805 int src
= (++vPC
)->u
.operand
;
1806 JSValue result
= jsBoolean(!callFrame
->r(src
).jsValue().toBoolean(callFrame
));
1807 CHECK_FOR_EXCEPTION();
1808 callFrame
->r(dst
) = result
;
1813 DEFINE_OPCODE(op_instanceof
) {
1814 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
1816 Tests whether register value is an instance of register
1817 constructor, and puts the boolean result in register
1818 dst. Register constructorProto must contain the "prototype"
1819 property (not the actual prototype) of the object in
1820 register constructor. This lookup is separated so that
1821 polymorphic inline caching can apply.
1823 Raises an exception if register constructor is not an
1826 int dst
= vPC
[1].u
.operand
;
1827 int value
= vPC
[2].u
.operand
;
1828 int base
= vPC
[3].u
.operand
;
1829 int baseProto
= vPC
[4].u
.operand
;
1831 JSValue baseVal
= callFrame
->r(base
).jsValue();
1833 if (isInvalidParamForInstanceOf(callFrame
, callFrame
->codeBlock(), vPC
, baseVal
, exceptionValue
))
1836 bool result
= asObject(baseVal
)->hasInstance(callFrame
, callFrame
->r(value
).jsValue(), callFrame
->r(baseProto
).jsValue());
1837 CHECK_FOR_EXCEPTION();
1838 callFrame
->r(dst
) = jsBoolean(result
);
1843 DEFINE_OPCODE(op_typeof
) {
1844 /* typeof dst(r) src(r)
1846 Determines the type string for src according to ECMAScript
1847 rules, and puts the result in register dst.
1849 int dst
= (++vPC
)->u
.operand
;
1850 int src
= (++vPC
)->u
.operand
;
1851 callFrame
->r(dst
) = JSValue(jsTypeStringForValue(callFrame
, callFrame
->r(src
).jsValue()));
1856 DEFINE_OPCODE(op_is_undefined
) {
1857 /* is_undefined dst(r) src(r)
1859 Determines whether the type string for src according to
1860 the ECMAScript rules is "undefined", and puts the result
1863 int dst
= (++vPC
)->u
.operand
;
1864 int src
= (++vPC
)->u
.operand
;
1865 JSValue v
= callFrame
->r(src
).jsValue();
1866 callFrame
->r(dst
) = jsBoolean(v
.isCell() ? v
.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v
.isUndefined());
1871 DEFINE_OPCODE(op_is_boolean
) {
1872 /* is_boolean dst(r) src(r)
1874 Determines whether the type string for src according to
1875 the ECMAScript rules is "boolean", and puts the result
1878 int dst
= (++vPC
)->u
.operand
;
1879 int src
= (++vPC
)->u
.operand
;
1880 callFrame
->r(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isBoolean());
1885 DEFINE_OPCODE(op_is_number
) {
1886 /* is_number dst(r) src(r)
1888 Determines whether the type string for src according to
1889 the ECMAScript rules is "number", and puts the result
1892 int dst
= (++vPC
)->u
.operand
;
1893 int src
= (++vPC
)->u
.operand
;
1894 callFrame
->r(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isNumber());
1899 DEFINE_OPCODE(op_is_string
) {
1900 /* is_string dst(r) src(r)
1902 Determines whether the type string for src according to
1903 the ECMAScript rules is "string", and puts the result
1906 int dst
= (++vPC
)->u
.operand
;
1907 int src
= (++vPC
)->u
.operand
;
1908 callFrame
->r(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isString());
1913 DEFINE_OPCODE(op_is_object
) {
1914 /* is_object dst(r) src(r)
1916 Determines whether the type string for src according to
1917 the ECMAScript rules is "object", and puts the result
1920 int dst
= (++vPC
)->u
.operand
;
1921 int src
= (++vPC
)->u
.operand
;
1922 callFrame
->r(dst
) = jsBoolean(jsIsObjectType(callFrame
->r(src
).jsValue()));
1927 DEFINE_OPCODE(op_is_function
) {
1928 /* is_function dst(r) src(r)
1930 Determines whether the type string for src according to
1931 the ECMAScript rules is "function", and puts the result
1934 int dst
= (++vPC
)->u
.operand
;
1935 int src
= (++vPC
)->u
.operand
;
1936 callFrame
->r(dst
) = jsBoolean(jsIsFunctionType(callFrame
->r(src
).jsValue()));
1941 DEFINE_OPCODE(op_in
) {
1942 /* in dst(r) property(r) base(r)
1944 Tests whether register base has a property named register
1945 property, and puts the boolean result in register dst.
1947 Raises an exception if register constructor is not an
1950 int dst
= (++vPC
)->u
.operand
;
1951 int property
= (++vPC
)->u
.operand
;
1952 int base
= (++vPC
)->u
.operand
;
1954 JSValue baseVal
= callFrame
->r(base
).jsValue();
1955 if (isInvalidParamForIn(callFrame
, callFrame
->codeBlock(), vPC
, baseVal
, exceptionValue
))
1958 JSObject
* baseObj
= asObject(baseVal
);
1960 JSValue propName
= callFrame
->r(property
).jsValue();
1963 if (propName
.getUInt32(i
))
1964 callFrame
->r(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, i
));
1966 Identifier
property(callFrame
, propName
.toString(callFrame
));
1967 CHECK_FOR_EXCEPTION();
1968 callFrame
->r(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, property
));
1974 DEFINE_OPCODE(op_resolve
) {
1975 /* resolve dst(r) property(id)
1977 Looks up the property named by identifier property in the
1978 scope chain, and writes the resulting value to register
1979 dst. If the property is not found, raises an exception.
1981 if (UNLIKELY(!resolve(callFrame
, vPC
, exceptionValue
)))
1987 DEFINE_OPCODE(op_resolve_skip
) {
1988 /* resolve_skip dst(r) property(id) skip(n)
1990 Looks up the property named by identifier property in the
1991 scope chain skipping the top 'skip' levels, and writes the resulting
1992 value to register dst. If the property is not found, raises an exception.
1994 if (UNLIKELY(!resolveSkip(callFrame
, vPC
, exceptionValue
)))
2001 DEFINE_OPCODE(op_resolve_global
) {
2002 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
2004 Performs a dynamic property lookup for the given property, on the provided
2005 global object. If structure matches the Structure of the global then perform
2006 a fast lookup using the case offset, otherwise fall back to a full resolve and
2007 cache the new structure and offset
2009 if (UNLIKELY(!resolveGlobal(callFrame
, vPC
, exceptionValue
)))
2016 DEFINE_OPCODE(op_get_global_var
) {
2017 /* get_global_var dst(r) globalObject(c) index(n)
2019 Gets the global var at global slot index and places it in register dst.
2021 int dst
= (++vPC
)->u
.operand
;
2022 JSGlobalObject
* scope
= static_cast<JSGlobalObject
*>((++vPC
)->u
.jsCell
);
2023 ASSERT(scope
->isGlobalObject());
2024 int index
= (++vPC
)->u
.operand
;
2026 callFrame
->r(dst
) = scope
->registerAt(index
);
2030 DEFINE_OPCODE(op_put_global_var
) {
2031 /* put_global_var globalObject(c) index(n) value(r)
2033 Puts value into global slot index.
2035 JSGlobalObject
* scope
= static_cast<JSGlobalObject
*>((++vPC
)->u
.jsCell
);
2036 ASSERT(scope
->isGlobalObject());
2037 int index
= (++vPC
)->u
.operand
;
2038 int value
= (++vPC
)->u
.operand
;
2040 scope
->registerAt(index
) = JSValue(callFrame
->r(value
).jsValue());
2044 DEFINE_OPCODE(op_get_scoped_var
) {
2045 /* get_scoped_var dst(r) index(n) skip(n)
2047 Loads the contents of the index-th local from the scope skip nodes from
2048 the top of the scope chain, and places it in register dst
2050 int dst
= (++vPC
)->u
.operand
;
2051 int index
= (++vPC
)->u
.operand
;
2052 int skip
= (++vPC
)->u
.operand
+ callFrame
->codeBlock()->needsFullScopeChain();
2054 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2055 ScopeChainIterator iter
= scopeChain
->begin();
2056 ScopeChainIterator end
= scopeChain
->end();
2057 ASSERT(iter
!= end
);
2060 ASSERT(iter
!= end
);
2063 ASSERT((*iter
)->isVariableObject());
2064 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(*iter
);
2065 callFrame
->r(dst
) = scope
->registerAt(index
);
2069 DEFINE_OPCODE(op_put_scoped_var
) {
2070 /* put_scoped_var index(n) skip(n) value(r)
2073 int index
= (++vPC
)->u
.operand
;
2074 int skip
= (++vPC
)->u
.operand
+ callFrame
->codeBlock()->needsFullScopeChain();
2075 int value
= (++vPC
)->u
.operand
;
2077 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2078 ScopeChainIterator iter
= scopeChain
->begin();
2079 ScopeChainIterator end
= scopeChain
->end();
2080 ASSERT(iter
!= end
);
2083 ASSERT(iter
!= end
);
2086 ASSERT((*iter
)->isVariableObject());
2087 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(*iter
);
2088 scope
->registerAt(index
) = JSValue(callFrame
->r(value
).jsValue());
2092 DEFINE_OPCODE(op_resolve_base
) {
2093 /* resolve_base dst(r) property(id)
2095 Searches the scope chain for an object containing
2096 identifier property, and if one is found, writes it to
2097 register dst. If none is found, the outermost scope (which
2098 will be the global object) is stored in register dst.
2100 resolveBase(callFrame
, vPC
);
2105 DEFINE_OPCODE(op_resolve_with_base
) {
2106 /* resolve_with_base baseDst(r) propDst(r) property(id)
2108 Searches the scope chain for an object containing
2109 identifier property, and if one is found, writes it to
2110 register srcDst, and the retrieved property value to register
2111 propDst. If the property is not found, raises an exception.
2113 This is more efficient than doing resolve_base followed by
2114 resolve, or resolve_base followed by get_by_id, as it
2115 avoids duplicate hash lookups.
2117 if (UNLIKELY(!resolveBaseAndProperty(callFrame
, vPC
, exceptionValue
)))
2123 DEFINE_OPCODE(op_get_by_id
) {
2124 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2126 Generic property access: Gets the property named by identifier
2127 property from the value base, and puts the result in register dst.
2129 int dst
= vPC
[1].u
.operand
;
2130 int base
= vPC
[2].u
.operand
;
2131 int property
= vPC
[3].u
.operand
;
2133 CodeBlock
* codeBlock
= callFrame
->codeBlock();
2134 Identifier
& ident
= codeBlock
->identifier(property
);
2135 JSValue baseValue
= callFrame
->r(base
).jsValue();
2136 PropertySlot
slot(baseValue
);
2137 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
2138 CHECK_FOR_EXCEPTION();
2140 tryCacheGetByID(callFrame
, codeBlock
, vPC
, baseValue
, ident
, slot
);
2142 callFrame
->r(dst
) = result
;
2146 DEFINE_OPCODE(op_get_by_id_self
) {
2147 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2149 Cached property access: Attempts to get a cached property from the
2150 value base. If the cache misses, op_get_by_id_self reverts to
2153 int base
= vPC
[2].u
.operand
;
2154 JSValue baseValue
= callFrame
->r(base
).jsValue();
2156 if (LIKELY(baseValue
.isCell())) {
2157 JSCell
* baseCell
= asCell(baseValue
);
2158 Structure
* structure
= vPC
[4].u
.structure
;
2160 if (LIKELY(baseCell
->structure() == structure
)) {
2161 ASSERT(baseCell
->isObject());
2162 JSObject
* baseObject
= asObject(baseCell
);
2163 int dst
= vPC
[1].u
.operand
;
2164 int offset
= vPC
[5].u
.operand
;
2166 ASSERT(baseObject
->get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2167 callFrame
->r(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
2174 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2177 DEFINE_OPCODE(op_get_by_id_proto
) {
2178 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2180 Cached property access: Attempts to get a cached property from the
2181 value base's prototype. If the cache misses, op_get_by_id_proto
2182 reverts to op_get_by_id.
2184 int base
= vPC
[2].u
.operand
;
2185 JSValue baseValue
= callFrame
->r(base
).jsValue();
2187 if (LIKELY(baseValue
.isCell())) {
2188 JSCell
* baseCell
= asCell(baseValue
);
2189 Structure
* structure
= vPC
[4].u
.structure
;
2191 if (LIKELY(baseCell
->structure() == structure
)) {
2192 ASSERT(structure
->prototypeForLookup(callFrame
).isObject());
2193 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
2194 Structure
* prototypeStructure
= vPC
[5].u
.structure
;
2196 if (LIKELY(protoObject
->structure() == prototypeStructure
)) {
2197 int dst
= vPC
[1].u
.operand
;
2198 int offset
= vPC
[6].u
.operand
;
2200 ASSERT(protoObject
->get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
2201 ASSERT(baseValue
.get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
2202 callFrame
->r(dst
) = JSValue(protoObject
->getDirectOffset(offset
));
2210 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2213 DEFINE_OPCODE(op_get_by_id_self_list
) {
2214 // Polymorphic self access caching currently only supported when JITting.
2215 ASSERT_NOT_REACHED();
2216 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2220 DEFINE_OPCODE(op_get_by_id_proto_list
) {
2221 // Polymorphic prototype access caching currently only supported when JITting.
2222 ASSERT_NOT_REACHED();
2223 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2227 DEFINE_OPCODE(op_get_by_id_chain
) {
2228 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2230 Cached property access: Attempts to get a cached property from the
2231 value base's prototype chain. If the cache misses, op_get_by_id_chain
2232 reverts to op_get_by_id.
2234 int base
= vPC
[2].u
.operand
;
2235 JSValue baseValue
= callFrame
->r(base
).jsValue();
2237 if (LIKELY(baseValue
.isCell())) {
2238 JSCell
* baseCell
= asCell(baseValue
);
2239 Structure
* structure
= vPC
[4].u
.structure
;
2241 if (LIKELY(baseCell
->structure() == structure
)) {
2242 RefPtr
<Structure
>* it
= vPC
[5].u
.structureChain
->head();
2243 size_t count
= vPC
[6].u
.operand
;
2244 RefPtr
<Structure
>* end
= it
+ count
;
2247 JSObject
* baseObject
= asObject(baseCell
->structure()->prototypeForLookup(callFrame
));
2249 if (UNLIKELY(baseObject
->structure() != (*it
).get()))
2253 int dst
= vPC
[1].u
.operand
;
2254 int offset
= vPC
[7].u
.operand
;
2256 ASSERT(baseObject
->get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2257 ASSERT(baseValue
.get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2258 callFrame
->r(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
2264 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2265 baseCell
= baseObject
;
2270 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2273 DEFINE_OPCODE(op_get_by_id_generic
) {
2274 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2276 Generic property access: Gets the property named by identifier
2277 property from the value base, and puts the result in register dst.
2279 int dst
= vPC
[1].u
.operand
;
2280 int base
= vPC
[2].u
.operand
;
2281 int property
= vPC
[3].u
.operand
;
2283 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
2284 JSValue baseValue
= callFrame
->r(base
).jsValue();
2285 PropertySlot
slot(baseValue
);
2286 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
2287 CHECK_FOR_EXCEPTION();
2289 callFrame
->r(dst
) = result
;
2293 DEFINE_OPCODE(op_get_array_length
) {
2294 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2296 Cached property access: Gets the length of the array in register base,
2297 and puts the result in register dst. If register base does not hold
2298 an array, op_get_array_length reverts to op_get_by_id.
2301 int base
= vPC
[2].u
.operand
;
2302 JSValue baseValue
= callFrame
->r(base
).jsValue();
2303 if (LIKELY(isJSArray(globalData
, baseValue
))) {
2304 int dst
= vPC
[1].u
.operand
;
2305 callFrame
->r(dst
) = jsNumber(callFrame
, asArray(baseValue
)->length());
2310 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2313 DEFINE_OPCODE(op_get_string_length
) {
2314 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2316 Cached property access: Gets the length of the string in register base,
2317 and puts the result in register dst. If register base does not hold
2318 a string, op_get_string_length reverts to op_get_by_id.
2321 int base
= vPC
[2].u
.operand
;
2322 JSValue baseValue
= callFrame
->r(base
).jsValue();
2323 if (LIKELY(isJSString(globalData
, baseValue
))) {
2324 int dst
= vPC
[1].u
.operand
;
2325 callFrame
->r(dst
) = jsNumber(callFrame
, asString(baseValue
)->value().size());
2330 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2333 DEFINE_OPCODE(op_put_by_id
) {
2334 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2336 Generic property access: Sets the property named by identifier
2337 property, belonging to register base, to register value.
2339 Unlike many opcodes, this one does not write any output to
2343 int base
= vPC
[1].u
.operand
;
2344 int property
= vPC
[2].u
.operand
;
2345 int value
= vPC
[3].u
.operand
;
2347 CodeBlock
* codeBlock
= callFrame
->codeBlock();
2348 JSValue baseValue
= callFrame
->r(base
).jsValue();
2349 Identifier
& ident
= codeBlock
->identifier(property
);
2350 PutPropertySlot slot
;
2351 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
2352 CHECK_FOR_EXCEPTION();
2354 tryCachePutByID(callFrame
, codeBlock
, vPC
, baseValue
, slot
);
2359 DEFINE_OPCODE(op_put_by_id_transition
) {
2360 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)
2362 Cached property access: Attempts to set a new property with a cached transition
2363 property named by identifier property, belonging to register base,
2364 to register value. If the cache misses, op_put_by_id_transition
2365 reverts to op_put_by_id_generic.
2367 Unlike many opcodes, this one does not write any output to
2370 int base
= vPC
[1].u
.operand
;
2371 JSValue baseValue
= callFrame
->r(base
).jsValue();
2373 if (LIKELY(baseValue
.isCell())) {
2374 JSCell
* baseCell
= asCell(baseValue
);
2375 Structure
* oldStructure
= vPC
[4].u
.structure
;
2376 Structure
* newStructure
= vPC
[5].u
.structure
;
2378 if (LIKELY(baseCell
->structure() == oldStructure
)) {
2379 ASSERT(baseCell
->isObject());
2380 JSObject
* baseObject
= asObject(baseCell
);
2382 RefPtr
<Structure
>* it
= vPC
[6].u
.structureChain
->head();
2384 JSValue proto
= baseObject
->structure()->prototypeForLookup(callFrame
);
2385 while (!proto
.isNull()) {
2386 if (UNLIKELY(asObject(proto
)->structure() != (*it
).get())) {
2387 uncachePutByID(callFrame
->codeBlock(), vPC
);
2391 proto
= asObject(proto
)->structure()->prototypeForLookup(callFrame
);
2394 baseObject
->transitionTo(newStructure
);
2396 int value
= vPC
[3].u
.operand
;
2397 unsigned offset
= vPC
[7].u
.operand
;
2398 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(callFrame
->codeBlock()->identifier(vPC
[2].u
.operand
))) == offset
);
2399 baseObject
->putDirectOffset(offset
, callFrame
->r(value
).jsValue());
2406 uncachePutByID(callFrame
->codeBlock(), vPC
);
2409 DEFINE_OPCODE(op_put_by_id_replace
) {
2410 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)
2412 Cached property access: Attempts to set a pre-existing, cached
2413 property named by identifier property, belonging to register base,
2414 to register value. If the cache misses, op_put_by_id_replace
2415 reverts to op_put_by_id.
2417 Unlike many opcodes, this one does not write any output to
2420 int base
= vPC
[1].u
.operand
;
2421 JSValue baseValue
= callFrame
->r(base
).jsValue();
2423 if (LIKELY(baseValue
.isCell())) {
2424 JSCell
* baseCell
= asCell(baseValue
);
2425 Structure
* structure
= vPC
[4].u
.structure
;
2427 if (LIKELY(baseCell
->structure() == structure
)) {
2428 ASSERT(baseCell
->isObject());
2429 JSObject
* baseObject
= asObject(baseCell
);
2430 int value
= vPC
[3].u
.operand
;
2431 unsigned offset
= vPC
[5].u
.operand
;
2433 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(callFrame
->codeBlock()->identifier(vPC
[2].u
.operand
))) == offset
);
2434 baseObject
->putDirectOffset(offset
, callFrame
->r(value
).jsValue());
2441 uncachePutByID(callFrame
->codeBlock(), vPC
);
2444 DEFINE_OPCODE(op_put_by_id_generic
) {
2445 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2447 Generic property access: Sets the property named by identifier
2448 property, belonging to register base, to register value.
2450 Unlike many opcodes, this one does not write any output to
2453 int base
= vPC
[1].u
.operand
;
2454 int property
= vPC
[2].u
.operand
;
2455 int value
= vPC
[3].u
.operand
;
2457 JSValue baseValue
= callFrame
->r(base
).jsValue();
2458 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
2459 PutPropertySlot slot
;
2460 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
2461 CHECK_FOR_EXCEPTION();
2466 DEFINE_OPCODE(op_del_by_id
) {
2467 /* del_by_id dst(r) base(r) property(id)
2469 Converts register base to Object, deletes the property
2470 named by identifier property from the object, and writes a
2471 boolean indicating success (if true) or failure (if false)
2474 int dst
= (++vPC
)->u
.operand
;
2475 int base
= (++vPC
)->u
.operand
;
2476 int property
= (++vPC
)->u
.operand
;
2478 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
);
2479 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
2480 JSValue result
= jsBoolean(baseObj
->deleteProperty(callFrame
, ident
));
2481 CHECK_FOR_EXCEPTION();
2482 callFrame
->r(dst
) = result
;
2486 DEFINE_OPCODE(op_get_by_val
) {
2487 /* get_by_val dst(r) base(r) property(r)
2489 Converts register base to Object, gets the property named
2490 by register property from the object, and puts the result
2491 in register dst. property is nominally converted to string
2492 but numbers are treated more efficiently.
2494 int dst
= (++vPC
)->u
.operand
;
2495 int base
= (++vPC
)->u
.operand
;
2496 int property
= (++vPC
)->u
.operand
;
2498 JSValue baseValue
= callFrame
->r(base
).jsValue();
2499 JSValue subscript
= callFrame
->r(property
).jsValue();
2503 if (LIKELY(subscript
.isUInt32())) {
2504 uint32_t i
= subscript
.asUInt32();
2505 if (isJSArray(globalData
, baseValue
)) {
2506 JSArray
* jsArray
= asArray(baseValue
);
2507 if (jsArray
->canGetIndex(i
))
2508 result
= jsArray
->getIndex(i
);
2510 result
= jsArray
->JSArray::get(callFrame
, i
);
2511 } else if (isJSString(globalData
, baseValue
) && asString(baseValue
)->canGetIndex(i
))
2512 result
= asString(baseValue
)->getIndex(&callFrame
->globalData(), i
);
2513 else if (isJSByteArray(globalData
, baseValue
) && asByteArray(baseValue
)->canAccessIndex(i
))
2514 result
= asByteArray(baseValue
)->getIndex(callFrame
, i
);
2516 result
= baseValue
.get(callFrame
, i
);
2518 Identifier
property(callFrame
, subscript
.toString(callFrame
));
2519 result
= baseValue
.get(callFrame
, property
);
2522 CHECK_FOR_EXCEPTION();
2523 callFrame
->r(dst
) = result
;
2527 DEFINE_OPCODE(op_put_by_val
) {
2528 /* put_by_val base(r) property(r) value(r)
2530 Sets register value on register base as the property named
2531 by register property. Base is converted to object
2532 first. register property is nominally converted to string
2533 but numbers are treated more efficiently.
2535 Unlike many opcodes, this one does not write any output to
2538 int base
= (++vPC
)->u
.operand
;
2539 int property
= (++vPC
)->u
.operand
;
2540 int value
= (++vPC
)->u
.operand
;
2542 JSValue baseValue
= callFrame
->r(base
).jsValue();
2543 JSValue subscript
= callFrame
->r(property
).jsValue();
2545 if (LIKELY(subscript
.isUInt32())) {
2546 uint32_t i
= subscript
.asUInt32();
2547 if (isJSArray(globalData
, baseValue
)) {
2548 JSArray
* jsArray
= asArray(baseValue
);
2549 if (jsArray
->canSetIndex(i
))
2550 jsArray
->setIndex(i
, callFrame
->r(value
).jsValue());
2552 jsArray
->JSArray::put(callFrame
, i
, callFrame
->r(value
).jsValue());
2553 } else if (isJSByteArray(globalData
, baseValue
) && asByteArray(baseValue
)->canAccessIndex(i
)) {
2554 JSByteArray
* jsByteArray
= asByteArray(baseValue
);
2556 JSValue jsValue
= callFrame
->r(value
).jsValue();
2557 if (jsValue
.isInt32())
2558 jsByteArray
->setIndex(i
, jsValue
.asInt32());
2559 else if (jsValue
.getNumber(dValue
))
2560 jsByteArray
->setIndex(i
, dValue
);
2562 baseValue
.put(callFrame
, i
, jsValue
);
2564 baseValue
.put(callFrame
, i
, callFrame
->r(value
).jsValue());
2566 Identifier
property(callFrame
, subscript
.toString(callFrame
));
2567 if (!globalData
->exception
) { // Don't put to an object if toString threw an exception.
2568 PutPropertySlot slot
;
2569 baseValue
.put(callFrame
, property
, callFrame
->r(value
).jsValue(), slot
);
2573 CHECK_FOR_EXCEPTION();
2577 DEFINE_OPCODE(op_del_by_val
) {
2578 /* del_by_val dst(r) base(r) property(r)
2580 Converts register base to Object, deletes the property
2581 named by register property from the object, and writes a
2582 boolean indicating success (if true) or failure (if false)
2585 int dst
= (++vPC
)->u
.operand
;
2586 int base
= (++vPC
)->u
.operand
;
2587 int property
= (++vPC
)->u
.operand
;
2589 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
); // may throw
2591 JSValue subscript
= callFrame
->r(property
).jsValue();
2594 if (subscript
.getUInt32(i
))
2595 result
= jsBoolean(baseObj
->deleteProperty(callFrame
, i
));
2597 CHECK_FOR_EXCEPTION();
2598 Identifier
property(callFrame
, subscript
.toString(callFrame
));
2599 CHECK_FOR_EXCEPTION();
2600 result
= jsBoolean(baseObj
->deleteProperty(callFrame
, property
));
2603 CHECK_FOR_EXCEPTION();
2604 callFrame
->r(dst
) = result
;
2608 DEFINE_OPCODE(op_put_by_index
) {
2609 /* put_by_index base(r) property(n) value(r)
2611 Sets register value on register base as the property named
2612 by the immediate number property. Base is converted to
2615 Unlike many opcodes, this one does not write any output to
2618 This opcode is mainly used to initialize array literals.
2620 int base
= (++vPC
)->u
.operand
;
2621 unsigned property
= (++vPC
)->u
.operand
;
2622 int value
= (++vPC
)->u
.operand
;
2624 callFrame
->r(base
).jsValue().put(callFrame
, property
, callFrame
->r(value
).jsValue());
2629 DEFINE_OPCODE(op_loop
) {
2630 /* loop target(offset)
2632 Jumps unconditionally to offset target from the current
2635 Additionally this loop instruction may terminate JS execution is
2636 the JS timeout is reached.
2638 #if ENABLE(OPCODE_STATS)
2639 OpcodeStats::resetLastInstruction();
2641 int target
= (++vPC
)->u
.operand
;
2642 CHECK_FOR_TIMEOUT();
2646 DEFINE_OPCODE(op_jmp
) {
2647 /* jmp target(offset)
2649 Jumps unconditionally to offset target from the current
2652 #if ENABLE(OPCODE_STATS)
2653 OpcodeStats::resetLastInstruction();
2655 int target
= (++vPC
)->u
.operand
;
2660 DEFINE_OPCODE(op_loop_if_true
) {
2661 /* loop_if_true cond(r) target(offset)
2663 Jumps to offset target from the current instruction, if and
2664 only if register cond converts to boolean as true.
2666 Additionally this loop instruction may terminate JS execution is
2667 the JS timeout is reached.
2669 int cond
= (++vPC
)->u
.operand
;
2670 int target
= (++vPC
)->u
.operand
;
2671 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2673 CHECK_FOR_TIMEOUT();
2680 DEFINE_OPCODE(op_jtrue
) {
2681 /* jtrue cond(r) target(offset)
2683 Jumps to offset target from the current instruction, if and
2684 only if register cond converts to boolean as true.
2686 int cond
= (++vPC
)->u
.operand
;
2687 int target
= (++vPC
)->u
.operand
;
2688 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2696 DEFINE_OPCODE(op_jfalse
) {
2697 /* jfalse cond(r) target(offset)
2699 Jumps to offset target from the current instruction, if and
2700 only if register cond converts to boolean as false.
2702 int cond
= (++vPC
)->u
.operand
;
2703 int target
= (++vPC
)->u
.operand
;
2704 if (!callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2712 DEFINE_OPCODE(op_jeq_null
) {
2713 /* jeq_null src(r) target(offset)
2715 Jumps to offset target from the current instruction, if and
2716 only if register src is null.
2718 int src
= (++vPC
)->u
.operand
;
2719 int target
= (++vPC
)->u
.operand
;
2720 JSValue srcValue
= callFrame
->r(src
).jsValue();
2722 if (srcValue
.isUndefinedOrNull() || (srcValue
.isCell() && srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2730 DEFINE_OPCODE(op_jneq_null
) {
2731 /* jneq_null src(r) target(offset)
2733 Jumps to offset target from the current instruction, if and
2734 only if register src is not null.
2736 int src
= (++vPC
)->u
.operand
;
2737 int target
= (++vPC
)->u
.operand
;
2738 JSValue srcValue
= callFrame
->r(src
).jsValue();
2740 if (!srcValue
.isUndefinedOrNull() || (srcValue
.isCell() && !srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2748 DEFINE_OPCODE(op_jneq_ptr
) {
2749 /* jneq_ptr src(r) ptr(jsCell) target(offset)
2751 Jumps to offset target from the current instruction, if the value r is equal
2752 to ptr, using pointer equality.
2754 int src
= (++vPC
)->u
.operand
;
2755 JSValue ptr
= JSValue((++vPC
)->u
.jsCell
);
2756 int target
= (++vPC
)->u
.operand
;
2757 JSValue srcValue
= callFrame
->r(src
).jsValue();
2758 if (srcValue
!= ptr
) {
2766 DEFINE_OPCODE(op_loop_if_less
) {
2767 /* loop_if_less src1(r) src2(r) target(offset)
2769 Checks whether register src1 is less than register src2, as
2770 with the ECMAScript '<' operator, and then jumps to offset
2771 target from the current instruction, if and only if the
2772 result of the comparison is true.
2774 Additionally this loop instruction may terminate JS execution is
2775 the JS timeout is reached.
2777 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2778 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2779 int target
= (++vPC
)->u
.operand
;
2781 bool result
= jsLess(callFrame
, src1
, src2
);
2782 CHECK_FOR_EXCEPTION();
2786 CHECK_FOR_TIMEOUT();
2793 DEFINE_OPCODE(op_loop_if_lesseq
) {
2794 /* loop_if_lesseq src1(r) src2(r) target(offset)
2796 Checks whether register src1 is less than or equal to register
2797 src2, as with the ECMAScript '<=' operator, and then jumps to
2798 offset target from the current instruction, if and only if the
2799 result of the comparison is true.
2801 Additionally this loop instruction may terminate JS execution is
2802 the JS timeout is reached.
2804 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2805 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2806 int target
= (++vPC
)->u
.operand
;
2808 bool result
= jsLessEq(callFrame
, src1
, src2
);
2809 CHECK_FOR_EXCEPTION();
2813 CHECK_FOR_TIMEOUT();
2820 DEFINE_OPCODE(op_jnless
) {
2821 /* jnless src1(r) src2(r) target(offset)
2823 Checks whether register src1 is less than register src2, as
2824 with the ECMAScript '<' operator, and then jumps to offset
2825 target from the current instruction, if and only if the
2826 result of the comparison is false.
2828 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2829 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2830 int target
= (++vPC
)->u
.operand
;
2832 bool result
= jsLess(callFrame
, src1
, src2
);
2833 CHECK_FOR_EXCEPTION();
2843 DEFINE_OPCODE(op_jnlesseq
) {
2844 /* jnlesseq src1(r) src2(r) target(offset)
2846 Checks whether register src1 is less than or equal to
2847 register src2, as with the ECMAScript '<=' operator,
2848 and then jumps to offset target from the current instruction,
2849 if and only if theresult of the comparison is false.
2851 JSValue src1
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2852 JSValue src2
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2853 int target
= (++vPC
)->u
.operand
;
2855 bool result
= jsLessEq(callFrame
, src1
, src2
);
2856 CHECK_FOR_EXCEPTION();
2866 DEFINE_OPCODE(op_switch_imm
) {
2867 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2869 Performs a range checked switch on the scrutinee value, using
2870 the tableIndex-th immediate switch jump table. If the scrutinee value
2871 is an immediate number in the range covered by the referenced jump
2872 table, and the value at jumpTable[scrutinee value] is non-zero, then
2873 that value is used as the jump offset, otherwise defaultOffset is used.
2875 int tableIndex
= (++vPC
)->u
.operand
;
2876 int defaultOffset
= (++vPC
)->u
.operand
;
2877 JSValue scrutinee
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2878 if (scrutinee
.isInt32())
2879 vPC
+= callFrame
->codeBlock()->immediateSwitchJumpTable(tableIndex
).offsetForValue(scrutinee
.asInt32(), defaultOffset
);
2883 if (scrutinee
.getNumber(value
) && ((intValue
= static_cast<int32_t>(value
)) == value
))
2884 vPC
+= callFrame
->codeBlock()->immediateSwitchJumpTable(tableIndex
).offsetForValue(intValue
, defaultOffset
);
2886 vPC
+= defaultOffset
;
2890 DEFINE_OPCODE(op_switch_char
) {
2891 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2893 Performs a range checked switch on the scrutinee value, using
2894 the tableIndex-th character switch jump table. If the scrutinee value
2895 is a single character string in the range covered by the referenced jump
2896 table, and the value at jumpTable[scrutinee value] is non-zero, then
2897 that value is used as the jump offset, otherwise defaultOffset is used.
2899 int tableIndex
= (++vPC
)->u
.operand
;
2900 int defaultOffset
= (++vPC
)->u
.operand
;
2901 JSValue scrutinee
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2902 if (!scrutinee
.isString())
2903 vPC
+= defaultOffset
;
2905 UString::Rep
* value
= asString(scrutinee
)->value().rep();
2906 if (value
->size() != 1)
2907 vPC
+= defaultOffset
;
2909 vPC
+= callFrame
->codeBlock()->characterSwitchJumpTable(tableIndex
).offsetForValue(value
->data()[0], defaultOffset
);
2913 DEFINE_OPCODE(op_switch_string
) {
2914 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2916 Performs a sparse hashmap based switch on the value in the scrutinee
2917 register, using the tableIndex-th string switch jump table. If the
2918 scrutinee value is a string that exists as a key in the referenced
2919 jump table, then the value associated with the string is used as the
2920 jump offset, otherwise defaultOffset is used.
2922 int tableIndex
= (++vPC
)->u
.operand
;
2923 int defaultOffset
= (++vPC
)->u
.operand
;
2924 JSValue scrutinee
= callFrame
->r((++vPC
)->u
.operand
).jsValue();
2925 if (!scrutinee
.isString())
2926 vPC
+= defaultOffset
;
2928 vPC
+= callFrame
->codeBlock()->stringSwitchJumpTable(tableIndex
).offsetForValue(asString(scrutinee
)->value().rep(), defaultOffset
);
2931 DEFINE_OPCODE(op_new_func
) {
2932 /* new_func dst(r) func(f)
2934 Constructs a new Function instance from function func and
2935 the current scope chain using the original Function
2936 constructor, using the rules for function declarations, and
2937 puts the result in register dst.
2939 int dst
= (++vPC
)->u
.operand
;
2940 int func
= (++vPC
)->u
.operand
;
2942 callFrame
->r(dst
) = JSValue(callFrame
->codeBlock()->function(func
)->makeFunction(callFrame
, callFrame
->scopeChain()));
2947 DEFINE_OPCODE(op_new_func_exp
) {
2948 /* new_func_exp dst(r) func(f)
2950 Constructs a new Function instance from function func and
2951 the current scope chain using the original Function
2952 constructor, using the rules for function expressions, and
2953 puts the result in register dst.
2955 int dst
= (++vPC
)->u
.operand
;
2956 int func
= (++vPC
)->u
.operand
;
2958 callFrame
->r(dst
) = JSValue(callFrame
->codeBlock()->functionExpression(func
)->makeFunction(callFrame
, callFrame
->scopeChain()));
2963 DEFINE_OPCODE(op_call_eval
) {
2964 /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
2966 Call a function named "eval" with no explicit "this" value
2967 (which may therefore be the eval operator). If register
2968 thisVal is the global object, and register func contains
2969 that global object's original global eval function, then
2970 perform the eval operator in local scope (interpreting
2971 the argument registers as for the "call"
2972 opcode). Otherwise, act exactly as the "call" opcode would.
2975 int dst
= vPC
[1].u
.operand
;
2976 int func
= vPC
[2].u
.operand
;
2977 int argCount
= vPC
[3].u
.operand
;
2978 int registerOffset
= vPC
[4].u
.operand
;
2980 JSValue funcVal
= callFrame
->r(func
).jsValue();
2982 Register
* newCallFrame
= callFrame
->registers() + registerOffset
;
2983 Register
* argv
= newCallFrame
- RegisterFile::CallFrameHeaderSize
- argCount
;
2984 JSValue thisValue
= argv
[0].jsValue();
2985 JSGlobalObject
* globalObject
= callFrame
->scopeChain()->globalObject();
2987 if (thisValue
== globalObject
&& funcVal
== globalObject
->evalFunction()) {
2988 JSValue result
= callEval(callFrame
, registerFile
, argv
, argCount
, registerOffset
, exceptionValue
);
2991 callFrame
->r(dst
) = result
;
2997 // We didn't find the blessed version of eval, so process this
2998 // instruction as a normal function call.
2999 // fall through to op_call
3001 DEFINE_OPCODE(op_call
) {
3002 /* call dst(r) func(r) argCount(n) registerOffset(n)
3004 Perform a function call.
3006 registerOffset is the distance the callFrame pointer should move
3007 before the VM initializes the new call frame's header.
3009 dst is where op_ret should store its result.
3012 int dst
= vPC
[1].u
.operand
;
3013 int func
= vPC
[2].u
.operand
;
3014 int argCount
= vPC
[3].u
.operand
;
3015 int registerOffset
= vPC
[4].u
.operand
;
3017 JSValue v
= callFrame
->r(func
).jsValue();
3020 CallType callType
= v
.getCallData(callData
);
3022 if (callType
== CallTypeJS
) {
3023 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
3024 FunctionBodyNode
* functionBodyNode
= callData
.js
.functionBody
;
3025 CodeBlock
* newCodeBlock
= &functionBodyNode
->bytecode(callDataScopeChain
);
3027 CallFrame
* previousCallFrame
= callFrame
;
3029 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
3030 if (UNLIKELY(!callFrame
)) {
3031 callFrame
= previousCallFrame
;
3032 exceptionValue
= createStackOverflowError(callFrame
);
3036 callFrame
->init(newCodeBlock
, vPC
+ 5, callDataScopeChain
, previousCallFrame
, dst
, argCount
, asFunction(v
));
3037 vPC
= newCodeBlock
->instructions().begin();
3039 #if ENABLE(OPCODE_STATS)
3040 OpcodeStats::resetLastInstruction();
3046 if (callType
== CallTypeHost
) {
3047 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3048 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
3049 newCallFrame
->init(0, vPC
+ 5, scopeChain
, callFrame
, dst
, argCount
, 0);
3051 Register
* thisRegister
= newCallFrame
->registers() - RegisterFile::CallFrameHeaderSize
- argCount
;
3052 ArgList
args(thisRegister
+ 1, argCount
- 1);
3054 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3055 JSValue thisValue
= thisRegister
->jsValue();
3056 if (thisValue
== jsNull())
3057 thisValue
= callFrame
->globalThisValue();
3059 JSValue returnValue
;
3061 SamplingTool::HostCallRecord
callRecord(m_sampler
);
3062 returnValue
= callData
.native
.function(newCallFrame
, asObject(v
), thisValue
, args
);
3064 CHECK_FOR_EXCEPTION();
3066 callFrame
->r(dst
) = returnValue
;
3072 ASSERT(callType
== CallTypeNone
);
3074 exceptionValue
= createNotAFunctionError(callFrame
, v
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3077 DEFINE_OPCODE(op_load_varargs
) {
3078 int argCountDst
= (++vPC
)->u
.operand
;
3079 int argsOffset
= (++vPC
)->u
.operand
;
3081 JSValue arguments
= callFrame
->r(argsOffset
).jsValue();
3082 int32_t argCount
= 0;
3084 argCount
= (uint32_t)(callFrame
->argumentCount()) - 1;
3085 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3086 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3087 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3088 exceptionValue
= createStackOverflowError(callFrame
);
3091 int32_t expectedParams
= callFrame
->callee()->body()->parameterCount();
3092 int32_t inplaceArgs
= min(argCount
, expectedParams
);
3094 Register
* argStore
= callFrame
->registers() + argsOffset
;
3096 // First step is to copy the "expected" parameters from their normal location relative to the callframe
3097 for (; i
< inplaceArgs
; i
++)
3098 argStore
[i
] = callFrame
->registers()[i
- RegisterFile::CallFrameHeaderSize
- expectedParams
];
3099 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
3100 for (; i
< argCount
; i
++)
3101 argStore
[i
] = callFrame
->registers()[i
- RegisterFile::CallFrameHeaderSize
- expectedParams
- argCount
- 1];
3102 } else if (!arguments
.isUndefinedOrNull()) {
3103 if (!arguments
.isObject()) {
3104 exceptionValue
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3107 if (asObject(arguments
)->classInfo() == &Arguments::info
) {
3108 Arguments
* args
= asArguments(arguments
);
3109 argCount
= args
->numProvidedArguments(callFrame
);
3110 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3111 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3112 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3113 exceptionValue
= createStackOverflowError(callFrame
);
3116 args
->copyToRegisters(callFrame
, callFrame
->registers() + argsOffset
, argCount
);
3117 } else if (isJSArray(&callFrame
->globalData(), arguments
)) {
3118 JSArray
* array
= asArray(arguments
);
3119 argCount
= array
->length();
3120 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3121 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3122 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3123 exceptionValue
= createStackOverflowError(callFrame
);
3126 array
->copyToRegisters(callFrame
, callFrame
->registers() + argsOffset
, argCount
);
3127 } else if (asObject(arguments
)->inherits(&JSArray::info
)) {
3128 JSObject
* argObject
= asObject(arguments
);
3129 argCount
= argObject
->get(callFrame
, callFrame
->propertyNames().length
).toUInt32(callFrame
);
3130 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3131 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3132 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3133 exceptionValue
= createStackOverflowError(callFrame
);
3136 Register
* argsBuffer
= callFrame
->registers() + argsOffset
;
3137 for (int32_t i
= 0; i
< argCount
; ++i
) {
3138 argsBuffer
[i
] = asObject(arguments
)->get(callFrame
, i
);
3139 CHECK_FOR_EXCEPTION();
3142 if (!arguments
.isObject()) {
3143 exceptionValue
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3148 CHECK_FOR_EXCEPTION();
3149 callFrame
->r(argCountDst
) = Register::withInt(argCount
+ 1);
3153 DEFINE_OPCODE(op_call_varargs
) {
3154 /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
3156 Perform a function call with a dynamic set of arguments.
3158 registerOffset is the distance the callFrame pointer should move
3159 before the VM initializes the new call frame's header, excluding
3160 space for arguments.
3162 dst is where op_ret should store its result.
3165 int dst
= vPC
[1].u
.operand
;
3166 int func
= vPC
[2].u
.operand
;
3167 int argCountReg
= vPC
[3].u
.operand
;
3168 int registerOffset
= vPC
[4].u
.operand
;
3170 JSValue v
= callFrame
->r(func
).jsValue();
3171 int argCount
= callFrame
->r(argCountReg
).i();
3172 registerOffset
+= argCount
;
3174 CallType callType
= v
.getCallData(callData
);
3176 if (callType
== CallTypeJS
) {
3177 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
3178 FunctionBodyNode
* functionBodyNode
= callData
.js
.functionBody
;
3179 CodeBlock
* newCodeBlock
= &functionBodyNode
->bytecode(callDataScopeChain
);
3181 CallFrame
* previousCallFrame
= callFrame
;
3183 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
3184 if (UNLIKELY(!callFrame
)) {
3185 callFrame
= previousCallFrame
;
3186 exceptionValue
= createStackOverflowError(callFrame
);
3190 callFrame
->init(newCodeBlock
, vPC
+ 5, callDataScopeChain
, previousCallFrame
, dst
, argCount
, asFunction(v
));
3191 vPC
= newCodeBlock
->instructions().begin();
3193 #if ENABLE(OPCODE_STATS)
3194 OpcodeStats::resetLastInstruction();
3200 if (callType
== CallTypeHost
) {
3201 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3202 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
3203 newCallFrame
->init(0, vPC
+ 5, scopeChain
, callFrame
, dst
, argCount
, 0);
3205 Register
* thisRegister
= newCallFrame
->registers() - RegisterFile::CallFrameHeaderSize
- argCount
;
3206 ArgList
args(thisRegister
+ 1, argCount
- 1);
3208 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3209 JSValue thisValue
= thisRegister
->jsValue();
3210 if (thisValue
== jsNull())
3211 thisValue
= callFrame
->globalThisValue();
3213 JSValue returnValue
;
3215 SamplingTool::HostCallRecord
callRecord(m_sampler
);
3216 returnValue
= callData
.native
.function(newCallFrame
, asObject(v
), thisValue
, args
);
3218 CHECK_FOR_EXCEPTION();
3220 callFrame
->r(dst
) = returnValue
;
3226 ASSERT(callType
== CallTypeNone
);
3228 exceptionValue
= createNotAFunctionError(callFrame
, v
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3231 DEFINE_OPCODE(op_tear_off_activation
) {
3232 /* tear_off_activation activation(r)
3234 Copy all locals and parameters to new memory allocated on
3235 the heap, and make the passed activation use this memory
3236 in the future when looking up entries in the symbol table.
3237 If there is an 'arguments' object, then it will also use
3238 this memory for storing the named parameters, but not any
3241 This opcode should only be used immediately before op_ret.
3244 int src
= (++vPC
)->u
.operand
;
3245 ASSERT(callFrame
->codeBlock()->needsFullScopeChain());
3247 asActivation(callFrame
->r(src
).jsValue())->copyRegisters(callFrame
->optionalCalleeArguments());
3252 DEFINE_OPCODE(op_tear_off_arguments
) {
3253 /* tear_off_arguments
3255 Copy all arguments to new memory allocated on the heap,
3256 and make the 'arguments' object use this memory in the
3257 future when looking up named parameters, but not any
3258 extra arguments. If an activation object exists for the
3259 current function context, then the tear_off_activation
3260 opcode should be used instead.
3262 This opcode should only be used immediately before op_ret.
3265 ASSERT(callFrame
->codeBlock()->usesArguments() && !callFrame
->codeBlock()->needsFullScopeChain());
3267 if (callFrame
->optionalCalleeArguments())
3268 callFrame
->optionalCalleeArguments()->copyRegisters();
3273 DEFINE_OPCODE(op_ret
) {
3276 Return register result as the return value of the current
3277 function call, writing it into the caller's expected return
3278 value register. In addition, unwind one call frame and
3279 restore the scope chain, code block instruction pointer and
3280 register base to those of the calling function.
3283 int result
= (++vPC
)->u
.operand
;
3285 if (callFrame
->codeBlock()->needsFullScopeChain())
3286 callFrame
->scopeChain()->deref();
3288 JSValue returnValue
= callFrame
->r(result
).jsValue();
3290 vPC
= callFrame
->returnPC();
3291 int dst
= callFrame
->returnValueRegister();
3292 callFrame
= callFrame
->callerFrame();
3294 if (callFrame
->hasHostCallFrameFlag())
3297 callFrame
->r(dst
) = returnValue
;
3301 DEFINE_OPCODE(op_enter
) {
3304 Initializes local variables to undefined and fills constant
3305 registers with their values. If the code block requires an
3306 activation, enter_with_activation should be used instead.
3308 This opcode should only be used at the beginning of a code
3313 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3315 for (size_t count
= codeBlock
->m_numVars
; i
< count
; ++i
)
3316 callFrame
->r(i
) = jsUndefined();
3321 DEFINE_OPCODE(op_enter_with_activation
) {
3322 /* enter_with_activation dst(r)
3324 Initializes local variables to undefined, fills constant
3325 registers with their values, creates an activation object,
3326 and places the new activation both in dst and at the top
3327 of the scope chain. If the code block does not require an
3328 activation, enter should be used instead.
3330 This opcode should only be used at the beginning of a code
3335 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3337 for (size_t count
= codeBlock
->m_numVars
; i
< count
; ++i
)
3338 callFrame
->r(i
) = jsUndefined();
3340 int dst
= (++vPC
)->u
.operand
;
3341 JSActivation
* activation
= new (globalData
) JSActivation(callFrame
, static_cast<FunctionBodyNode
*>(codeBlock
->ownerNode()));
3342 callFrame
->r(dst
) = JSValue(activation
);
3343 callFrame
->setScopeChain(callFrame
->scopeChain()->copy()->push(activation
));
3348 DEFINE_OPCODE(op_convert_this
) {
3349 /* convert_this this(r)
3351 Takes the value in the 'this' register, converts it to a
3352 value that is suitable for use as the 'this' value, and
3353 stores it in the 'this' register. This opcode is emitted
3354 to avoid doing the conversion in the caller unnecessarily.
3356 This opcode should only be used at the beginning of a code
3360 int thisRegister
= (++vPC
)->u
.operand
;
3361 JSValue thisVal
= callFrame
->r(thisRegister
).jsValue();
3362 if (thisVal
.needsThisConversion())
3363 callFrame
->r(thisRegister
) = JSValue(thisVal
.toThisObject(callFrame
));
3368 DEFINE_OPCODE(op_init_arguments
) {
3371 Initialises the arguments object reference to null to ensure
3372 we can correctly detect that we need to create it later (or
3373 avoid creating it altogether).
3375 This opcode should only be used at the beginning of a code
3378 callFrame
->r(RegisterFile::ArgumentsRegister
) = JSValue();
3382 DEFINE_OPCODE(op_create_arguments
) {
3385 Creates the 'arguments' object and places it in both the
3386 'arguments' call frame slot and the local 'arguments'
3387 register, if it has not already been initialised.
3390 if (!callFrame
->r(RegisterFile::ArgumentsRegister
).jsValue()) {
3391 Arguments
* arguments
= new (globalData
) Arguments(callFrame
);
3392 callFrame
->setCalleeArguments(arguments
);
3393 callFrame
->r(RegisterFile::ArgumentsRegister
) = JSValue(arguments
);
3398 DEFINE_OPCODE(op_construct
) {
3399 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
3401 Invoke register "func" as a constructor. For JS
3402 functions, the calling convention is exactly as for the
3403 "call" opcode, except that the "this" value is a newly
3404 created Object. For native constructors, no "this"
3405 value is passed. In either case, the argCount and registerOffset
3406 registers are interpreted as for the "call" opcode.
3408 Register proto must contain the prototype property of
3409 register func. This is to enable polymorphic inline
3410 caching of this lookup.
3413 int dst
= vPC
[1].u
.operand
;
3414 int func
= vPC
[2].u
.operand
;
3415 int argCount
= vPC
[3].u
.operand
;
3416 int registerOffset
= vPC
[4].u
.operand
;
3417 int proto
= vPC
[5].u
.operand
;
3418 int thisRegister
= vPC
[6].u
.operand
;
3420 JSValue v
= callFrame
->r(func
).jsValue();
3422 ConstructData constructData
;
3423 ConstructType constructType
= v
.getConstructData(constructData
);
3425 if (constructType
== ConstructTypeJS
) {
3426 ScopeChainNode
* callDataScopeChain
= constructData
.js
.scopeChain
;
3427 FunctionBodyNode
* functionBodyNode
= constructData
.js
.functionBody
;
3428 CodeBlock
* newCodeBlock
= &functionBodyNode
->bytecode(callDataScopeChain
);
3430 Structure
* structure
;
3431 JSValue prototype
= callFrame
->r(proto
).jsValue();
3432 if (prototype
.isObject())
3433 structure
= asObject(prototype
)->inheritorID();
3435 structure
= callDataScopeChain
->globalObject()->emptyObjectStructure();
3436 JSObject
* newObject
= new (globalData
) JSObject(structure
);
3438 callFrame
->r(thisRegister
) = JSValue(newObject
); // "this" value
3440 CallFrame
* previousCallFrame
= callFrame
;
3442 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
3443 if (UNLIKELY(!callFrame
)) {
3444 callFrame
= previousCallFrame
;
3445 exceptionValue
= createStackOverflowError(callFrame
);
3449 callFrame
->init(newCodeBlock
, vPC
+ 7, callDataScopeChain
, previousCallFrame
, dst
, argCount
, asFunction(v
));
3450 vPC
= newCodeBlock
->instructions().begin();
3452 #if ENABLE(OPCODE_STATS)
3453 OpcodeStats::resetLastInstruction();
3459 if (constructType
== ConstructTypeHost
) {
3460 ArgList
args(callFrame
->registers() + thisRegister
+ 1, argCount
- 1);
3462 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3463 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
3464 newCallFrame
->init(0, vPC
+ 7, scopeChain
, callFrame
, dst
, argCount
, 0);
3466 JSValue returnValue
;
3468 SamplingTool::HostCallRecord
callRecord(m_sampler
);
3469 returnValue
= constructData
.native
.function(newCallFrame
, asObject(v
), args
);
3471 CHECK_FOR_EXCEPTION();
3472 callFrame
->r(dst
) = JSValue(returnValue
);
3478 ASSERT(constructType
== ConstructTypeNone
);
3480 exceptionValue
= createNotAConstructorError(callFrame
, v
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3483 DEFINE_OPCODE(op_construct_verify
) {
3484 /* construct_verify dst(r) override(r)
3486 Verifies that register dst holds an object. If not, moves
3487 the object in register override to register dst.
3490 int dst
= vPC
[1].u
.operand
;
3491 if (LIKELY(callFrame
->r(dst
).jsValue().isObject())) {
3496 int override
= vPC
[2].u
.operand
;
3497 callFrame
->r(dst
) = callFrame
->r(override
);
3502 DEFINE_OPCODE(op_strcat
) {
3503 int dst
= (++vPC
)->u
.operand
;
3504 int src
= (++vPC
)->u
.operand
;
3505 int count
= (++vPC
)->u
.operand
;
3507 callFrame
->r(dst
) = concatenateStrings(callFrame
, &callFrame
->registers()[src
], count
);
3512 DEFINE_OPCODE(op_to_primitive
) {
3513 int dst
= (++vPC
)->u
.operand
;
3514 int src
= (++vPC
)->u
.operand
;
3516 callFrame
->r(dst
) = callFrame
->r(src
).jsValue().toPrimitive(callFrame
);
3521 DEFINE_OPCODE(op_push_scope
) {
3522 /* push_scope scope(r)
3524 Converts register scope to object, and pushes it onto the top
3525 of the current scope chain. The contents of the register scope
3526 are replaced by the result of toObject conversion of the scope.
3528 int scope
= (++vPC
)->u
.operand
;
3529 JSValue v
= callFrame
->r(scope
).jsValue();
3530 JSObject
* o
= v
.toObject(callFrame
);
3531 CHECK_FOR_EXCEPTION();
3533 callFrame
->r(scope
) = JSValue(o
);
3534 callFrame
->setScopeChain(callFrame
->scopeChain()->push(o
));
3539 DEFINE_OPCODE(op_pop_scope
) {
3542 Removes the top item from the current scope chain.
3544 callFrame
->setScopeChain(callFrame
->scopeChain()->pop());
3549 DEFINE_OPCODE(op_get_pnames
) {
3550 /* get_pnames dst(r) base(r)
3552 Creates a property name list for register base and puts it
3553 in register dst. This is not a true JavaScript value, just
3554 a synthetic value used to keep the iteration state in a
3557 int dst
= (++vPC
)->u
.operand
;
3558 int base
= (++vPC
)->u
.operand
;
3560 callFrame
->r(dst
) = JSPropertyNameIterator::create(callFrame
, callFrame
->r(base
).jsValue());
3564 DEFINE_OPCODE(op_next_pname
) {
3565 /* next_pname dst(r) iter(r) target(offset)
3567 Tries to copies the next name from property name list in
3568 register iter. If there are names left, then copies one to
3569 register dst, and jumps to offset target. If there are none
3570 left, invalidates the iterator and continues to the next
3573 int dst
= (++vPC
)->u
.operand
;
3574 int iter
= (++vPC
)->u
.operand
;
3575 int target
= (++vPC
)->u
.operand
;
3577 JSPropertyNameIterator
* it
= callFrame
->r(iter
).propertyNameIterator();
3578 if (JSValue temp
= it
->next(callFrame
)) {
3579 CHECK_FOR_TIMEOUT();
3580 callFrame
->r(dst
) = JSValue(temp
);
3589 DEFINE_OPCODE(op_jmp_scopes
) {
3590 /* jmp_scopes count(n) target(offset)
3592 Removes the a number of items from the current scope chain
3593 specified by immediate number count, then jumps to offset
3596 int count
= (++vPC
)->u
.operand
;
3597 int target
= (++vPC
)->u
.operand
;
3599 ScopeChainNode
* tmp
= callFrame
->scopeChain();
3602 callFrame
->setScopeChain(tmp
);
3607 #if HAVE(COMPUTED_GOTO)
3609 goto *(&&skip_new_scope
);
3611 DEFINE_OPCODE(op_push_new_scope
) {
3612 /* new_scope dst(r) property(id) value(r)
3614 Constructs a new StaticScopeObject with property set to value. That scope
3615 object is then pushed onto the ScopeChain. The scope object is then stored
3618 callFrame
->setScopeChain(createExceptionScope(callFrame
, vPC
));
3623 #if HAVE(COMPUTED_GOTO)
3626 DEFINE_OPCODE(op_catch
) {
3629 Retrieves the VM's current exception and puts it in register
3630 ex. This is only valid after an exception has been raised,
3631 and usually forms the beginning of an exception handler.
3633 ASSERT(exceptionValue
);
3634 ASSERT(!globalData
->exception
);
3635 int ex
= (++vPC
)->u
.operand
;
3636 callFrame
->r(ex
) = exceptionValue
;
3637 exceptionValue
= JSValue();
3642 DEFINE_OPCODE(op_throw
) {
3645 Throws register ex as an exception. This involves three
3646 steps: first, it is set as the current exception in the
3647 VM's internal state, then the stack is unwound until an
3648 exception handler or a native code boundary is found, and
3649 then control resumes at the exception handler if any or
3650 else the script returns control to the nearest native caller.
3653 int ex
= (++vPC
)->u
.operand
;
3654 exceptionValue
= callFrame
->r(ex
).jsValue();
3656 handler
= throwException(callFrame
, exceptionValue
, vPC
- callFrame
->codeBlock()->instructions().begin(), true);
3658 *exception
= exceptionValue
;
3662 vPC
= callFrame
->codeBlock()->instructions().begin() + handler
->target
;
3665 DEFINE_OPCODE(op_new_error
) {
3666 /* new_error dst(r) type(n) message(k)
3668 Constructs a new Error instance using the original
3669 constructor, using immediate number n as the type and
3670 constant message as the message string. The result is
3671 written to register dst.
3673 int dst
= (++vPC
)->u
.operand
;
3674 int type
= (++vPC
)->u
.operand
;
3675 int message
= (++vPC
)->u
.operand
;
3677 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3678 callFrame
->r(dst
) = JSValue(Error::create(callFrame
, (ErrorType
)type
, callFrame
->r(message
).jsValue().toString(callFrame
), codeBlock
->lineNumberForBytecodeOffset(callFrame
, vPC
- codeBlock
->instructions().begin()), codeBlock
->ownerNode()->sourceID(), codeBlock
->ownerNode()->sourceURL()));
3683 DEFINE_OPCODE(op_end
) {
3686 Return register result as the value of a global or eval
3687 program. Return control to the calling native code.
3690 if (callFrame
->codeBlock()->needsFullScopeChain()) {
3691 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3692 ASSERT(scopeChain
->refCount
> 1);
3693 scopeChain
->deref();
3695 int result
= (++vPC
)->u
.operand
;
3696 return callFrame
->r(result
).jsValue();
3698 DEFINE_OPCODE(op_put_getter
) {
3699 /* put_getter base(r) property(id) function(r)
3701 Sets register function on register base as the getter named
3702 by identifier property. Base and function are assumed to be
3703 objects as this op should only be used for getters defined
3704 in object literal form.
3706 Unlike many opcodes, this one does not write any output to
3709 int base
= (++vPC
)->u
.operand
;
3710 int property
= (++vPC
)->u
.operand
;
3711 int function
= (++vPC
)->u
.operand
;
3713 ASSERT(callFrame
->r(base
).jsValue().isObject());
3714 JSObject
* baseObj
= asObject(callFrame
->r(base
).jsValue());
3715 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
3716 ASSERT(callFrame
->r(function
).jsValue().isObject());
3717 baseObj
->defineGetter(callFrame
, ident
, asObject(callFrame
->r(function
).jsValue()));
3722 DEFINE_OPCODE(op_put_setter
) {
3723 /* put_setter base(r) property(id) function(r)
3725 Sets register function on register base as the setter named
3726 by identifier property. Base and function are assumed to be
3727 objects as this op should only be used for setters defined
3728 in object literal form.
3730 Unlike many opcodes, this one does not write any output to
3733 int base
= (++vPC
)->u
.operand
;
3734 int property
= (++vPC
)->u
.operand
;
3735 int function
= (++vPC
)->u
.operand
;
3737 ASSERT(callFrame
->r(base
).jsValue().isObject());
3738 JSObject
* baseObj
= asObject(callFrame
->r(base
).jsValue());
3739 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
3740 ASSERT(callFrame
->r(function
).jsValue().isObject());
3741 baseObj
->defineSetter(callFrame
, ident
, asObject(callFrame
->r(function
).jsValue()));
3746 DEFINE_OPCODE(op_method_check
) {
3750 DEFINE_OPCODE(op_jsr
) {
3751 /* jsr retAddrDst(r) target(offset)
3753 Places the address of the next instruction into the retAddrDst
3754 register and jumps to offset target from the current instruction.
3756 int retAddrDst
= (++vPC
)->u
.operand
;
3757 int target
= (++vPC
)->u
.operand
;
3758 callFrame
->r(retAddrDst
) = vPC
+ 1;
3763 DEFINE_OPCODE(op_sret
) {
3764 /* sret retAddrSrc(r)
3766 Jumps to the address stored in the retAddrSrc register. This
3767 differs from op_jmp because the target address is stored in a
3768 register, not as an immediate.
3770 int retAddrSrc
= (++vPC
)->u
.operand
;
3771 vPC
= callFrame
->r(retAddrSrc
).vPC();
3774 DEFINE_OPCODE(op_debug
) {
3775 /* debug debugHookID(n) firstLine(n) lastLine(n)
3777 Notifies the debugger of the current state of execution. This opcode
3778 is only generated while the debugger is attached.
3780 int debugHookID
= (++vPC
)->u
.operand
;
3781 int firstLine
= (++vPC
)->u
.operand
;
3782 int lastLine
= (++vPC
)->u
.operand
;
3784 debug(callFrame
, static_cast<DebugHookID
>(debugHookID
), firstLine
, lastLine
);
3789 DEFINE_OPCODE(op_profile_will_call
) {
3790 /* op_profile_will_call function(r)
3792 Notifies the profiler of the beginning of a function call. This opcode
3793 is only generated if developer tools are enabled.
3795 int function
= vPC
[1].u
.operand
;
3797 if (*enabledProfilerReference
)
3798 (*enabledProfilerReference
)->willExecute(callFrame
, callFrame
->r(function
).jsValue());
3803 DEFINE_OPCODE(op_profile_did_call
) {
3804 /* op_profile_did_call function(r)
3806 Notifies the profiler of the end of a function call. This opcode
3807 is only generated if developer tools are enabled.
3809 int function
= vPC
[1].u
.operand
;
3811 if (*enabledProfilerReference
)
3812 (*enabledProfilerReference
)->didExecute(callFrame
, callFrame
->r(function
).jsValue());
3818 globalData
->exception
= JSValue();
3820 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3821 // cannot fathom if we don't assign to the exceptionValue before branching)
3822 exceptionValue
= createInterruptedExecutionException(globalData
);
3824 handler
= throwException(callFrame
, exceptionValue
, vPC
- callFrame
->codeBlock()->instructions().begin(), false);
3826 *exception
= exceptionValue
;
3830 vPC
= callFrame
->codeBlock()->instructions().begin() + handler
->target
;
3834 #if !HAVE(COMPUTED_GOTO)
3835 } // iterator loop ends
3837 #endif // USE(INTERPRETER)
3838 #undef NEXT_INSTRUCTION
3839 #undef DEFINE_OPCODE
3840 #undef CHECK_FOR_EXCEPTION
3841 #undef CHECK_FOR_TIMEOUT
3844 JSValue
Interpreter::retrieveArguments(CallFrame
* callFrame
, JSFunction
* function
) const
3846 CallFrame
* functionCallFrame
= findFunctionCallFrame(callFrame
, function
);
3847 if (!functionCallFrame
)
3850 CodeBlock
* codeBlock
= functionCallFrame
->codeBlock();
3851 if (codeBlock
->usesArguments()) {
3852 ASSERT(codeBlock
->codeType() == FunctionCode
);
3853 SymbolTable
& symbolTable
= codeBlock
->symbolTable();
3854 int argumentsIndex
= symbolTable
.get(functionCallFrame
->propertyNames().arguments
.ustring().rep()).getIndex();
3855 if (!functionCallFrame
->r(argumentsIndex
).jsValue()) {
3856 Arguments
* arguments
= new (callFrame
) Arguments(functionCallFrame
);
3857 functionCallFrame
->setCalleeArguments(arguments
);
3858 functionCallFrame
->r(RegisterFile::ArgumentsRegister
) = JSValue(arguments
);
3860 return functionCallFrame
->r(argumentsIndex
).jsValue();
3863 Arguments
* arguments
= functionCallFrame
->optionalCalleeArguments();
3865 arguments
= new (functionCallFrame
) Arguments(functionCallFrame
);
3866 arguments
->copyRegisters();
3867 callFrame
->setCalleeArguments(arguments
);
3873 JSValue
Interpreter::retrieveCaller(CallFrame
* callFrame
, InternalFunction
* function
) const
3875 CallFrame
* functionCallFrame
= findFunctionCallFrame(callFrame
, function
);
3876 if (!functionCallFrame
)
3879 CallFrame
* callerFrame
= functionCallFrame
->callerFrame();
3880 if (callerFrame
->hasHostCallFrameFlag())
3883 JSValue caller
= callerFrame
->callee();
3890 void Interpreter::retrieveLastCaller(CallFrame
* callFrame
, int& lineNumber
, intptr_t& sourceID
, UString
& sourceURL
, JSValue
& function
) const
3892 function
= JSValue();
3894 sourceURL
= UString();
3896 CallFrame
* callerFrame
= callFrame
->callerFrame();
3897 if (callerFrame
->hasHostCallFrameFlag())
3900 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
3901 if (!callerCodeBlock
)
3904 unsigned bytecodeOffset
= bytecodeOffsetForPC(callerFrame
, callerCodeBlock
, callFrame
->returnPC());
3905 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(callerFrame
, bytecodeOffset
- 1);
3906 sourceID
= callerCodeBlock
->ownerNode()->sourceID();
3907 sourceURL
= callerCodeBlock
->ownerNode()->sourceURL();
3908 function
= callerFrame
->callee();
3911 CallFrame
* Interpreter::findFunctionCallFrame(CallFrame
* callFrame
, InternalFunction
* function
)
3913 for (CallFrame
* candidate
= callFrame
; candidate
; candidate
= candidate
->callerFrame()->removeHostCallFrameFlag()) {
3914 if (candidate
->callee() == function
)