2 * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "Interpreter.h"
33 #include "Arguments.h"
34 #include "BatchedTransitionOptimizer.h"
35 #include "CallFrame.h"
36 #include "CallFrameClosure.h"
37 #include "CodeBlock.h"
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"
63 #include <wtf/Threading.h>
73 static ALWAYS_INLINE
unsigned bytecodeOffsetForPC(CallFrame
* callFrame
, CodeBlock
* codeBlock
, void* pc
)
76 return codeBlock
->getBytecodeIndex(callFrame
, ReturnAddressPtr(pc
));
78 UNUSED_PARAM(callFrame
);
79 return static_cast<Instruction
*>(pc
) - codeBlock
->instructions().begin();
83 // Returns the depth of the scope chain within a given call frame.
84 static int depth(CodeBlock
* codeBlock
, ScopeChain
& sc
)
86 if (!codeBlock
->needsFullScopeChain())
88 return sc
.localDepth();
92 NEVER_INLINE
bool Interpreter::resolve(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
94 int dst
= vPC
[1].u
.operand
;
95 int property
= vPC
[2].u
.operand
;
97 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
98 ScopeChainIterator iter
= scopeChain
->begin();
99 ScopeChainIterator end
= scopeChain
->end();
102 CodeBlock
* codeBlock
= callFrame
->codeBlock();
103 Identifier
& ident
= codeBlock
->identifier(property
);
106 PropertySlot
slot(o
);
107 if (o
->getPropertySlot(callFrame
, ident
, slot
)) {
108 JSValue result
= slot
.getValue(callFrame
, ident
);
109 exceptionValue
= callFrame
->globalData().exception
;
112 callFrame
->r(dst
) = JSValue(result
);
115 } while (++iter
!= end
);
116 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
120 NEVER_INLINE
bool Interpreter::resolveSkip(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
122 CodeBlock
* codeBlock
= callFrame
->codeBlock();
124 int dst
= vPC
[1].u
.operand
;
125 int property
= vPC
[2].u
.operand
;
126 int skip
= vPC
[3].u
.operand
+ codeBlock
->needsFullScopeChain();
128 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
129 ScopeChainIterator iter
= scopeChain
->begin();
130 ScopeChainIterator end
= scopeChain
->end();
136 Identifier
& ident
= codeBlock
->identifier(property
);
139 PropertySlot
slot(o
);
140 if (o
->getPropertySlot(callFrame
, ident
, slot
)) {
141 JSValue result
= slot
.getValue(callFrame
, ident
);
142 exceptionValue
= callFrame
->globalData().exception
;
145 callFrame
->r(dst
) = JSValue(result
);
148 } while (++iter
!= end
);
149 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
153 NEVER_INLINE
bool Interpreter::resolveGlobal(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
155 int dst
= vPC
[1].u
.operand
;
156 JSGlobalObject
* globalObject
= static_cast<JSGlobalObject
*>(vPC
[2].u
.jsCell
);
157 ASSERT(globalObject
->isGlobalObject());
158 int property
= vPC
[3].u
.operand
;
159 Structure
* structure
= vPC
[4].u
.structure
;
160 int offset
= vPC
[5].u
.operand
;
162 if (structure
== globalObject
->structure()) {
163 callFrame
->r(dst
) = JSValue(globalObject
->getDirectOffset(offset
));
167 CodeBlock
* codeBlock
= callFrame
->codeBlock();
168 Identifier
& ident
= codeBlock
->identifier(property
);
169 PropertySlot
slot(globalObject
);
170 if (globalObject
->getPropertySlot(callFrame
, ident
, slot
)) {
171 JSValue result
= slot
.getValue(callFrame
, ident
);
172 if (slot
.isCacheable() && !globalObject
->structure()->isUncacheableDictionary() && slot
.slotBase() == globalObject
) {
173 if (vPC
[4].u
.structure
)
174 vPC
[4].u
.structure
->deref();
175 globalObject
->structure()->ref();
176 vPC
[4] = globalObject
->structure();
177 vPC
[5] = slot
.cachedOffset();
178 callFrame
->r(dst
) = JSValue(result
);
182 exceptionValue
= callFrame
->globalData().exception
;
185 callFrame
->r(dst
) = JSValue(result
);
189 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
193 NEVER_INLINE
void Interpreter::resolveBase(CallFrame
* callFrame
, Instruction
* vPC
)
195 int dst
= vPC
[1].u
.operand
;
196 int property
= vPC
[2].u
.operand
;
197 callFrame
->r(dst
) = JSValue(JSC::resolveBase(callFrame
, callFrame
->codeBlock()->identifier(property
), callFrame
->scopeChain()));
200 NEVER_INLINE
bool Interpreter::resolveBaseAndProperty(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
202 int baseDst
= vPC
[1].u
.operand
;
203 int propDst
= vPC
[2].u
.operand
;
204 int property
= vPC
[3].u
.operand
;
206 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
207 ScopeChainIterator iter
= scopeChain
->begin();
208 ScopeChainIterator end
= scopeChain
->end();
210 // FIXME: add scopeDepthIsZero optimization
214 CodeBlock
* codeBlock
= callFrame
->codeBlock();
215 Identifier
& ident
= codeBlock
->identifier(property
);
219 PropertySlot
slot(base
);
220 if (base
->getPropertySlot(callFrame
, ident
, slot
)) {
221 JSValue result
= slot
.getValue(callFrame
, ident
);
222 exceptionValue
= callFrame
->globalData().exception
;
225 callFrame
->r(propDst
) = JSValue(result
);
226 callFrame
->r(baseDst
) = JSValue(base
);
230 } while (iter
!= end
);
232 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
236 #endif // USE(INTERPRETER)
238 ALWAYS_INLINE CallFrame
* Interpreter::slideRegisterWindowForCall(CodeBlock
* newCodeBlock
, RegisterFile
* registerFile
, CallFrame
* callFrame
, size_t registerOffset
, int argc
)
240 Register
* r
= callFrame
->registers();
241 Register
* newEnd
= r
+ registerOffset
+ newCodeBlock
->m_numCalleeRegisters
;
243 if (LIKELY(argc
== newCodeBlock
->m_numParameters
)) { // correct number of arguments
244 if (UNLIKELY(!registerFile
->grow(newEnd
)))
247 } else if (argc
< newCodeBlock
->m_numParameters
) { // too few arguments -- fill in the blanks
248 size_t omittedArgCount
= newCodeBlock
->m_numParameters
- argc
;
249 registerOffset
+= omittedArgCount
;
250 newEnd
+= omittedArgCount
;
251 if (!registerFile
->grow(newEnd
))
255 Register
* argv
= r
- RegisterFile::CallFrameHeaderSize
- omittedArgCount
;
256 for (size_t i
= 0; i
< omittedArgCount
; ++i
)
257 argv
[i
] = jsUndefined();
258 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
259 size_t numParameters
= newCodeBlock
->m_numParameters
;
260 registerOffset
+= numParameters
;
261 newEnd
+= numParameters
;
263 if (!registerFile
->grow(newEnd
))
267 Register
* argv
= r
- RegisterFile::CallFrameHeaderSize
- numParameters
- argc
;
268 for (size_t i
= 0; i
< numParameters
; ++i
)
269 argv
[i
+ argc
] = argv
[i
];
272 return CallFrame::create(r
);
276 static NEVER_INLINE
bool isInvalidParamForIn(CallFrame
* callFrame
, CodeBlock
* codeBlock
, const Instruction
* vPC
, JSValue value
, JSValue
& exceptionData
)
278 if (value
.isObject())
280 exceptionData
= createInvalidParamError(callFrame
, "in" , value
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
284 static NEVER_INLINE
bool isInvalidParamForInstanceOf(CallFrame
* callFrame
, CodeBlock
* codeBlock
, const Instruction
* vPC
, JSValue value
, JSValue
& exceptionData
)
286 if (value
.isObject() && asObject(value
)->structure()->typeInfo().implementsHasInstance())
288 exceptionData
= createInvalidParamError(callFrame
, "instanceof" , value
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
293 NEVER_INLINE JSValue
Interpreter::callEval(CallFrame
* callFrame
, RegisterFile
* registerFile
, Register
* argv
, int argc
, int registerOffset
, JSValue
& exceptionValue
)
296 return jsUndefined();
298 JSValue program
= argv
[1].jsValue();
300 if (!program
.isString())
303 UString programSource
= asString(program
)->value(callFrame
);
305 LiteralParser
preparser(callFrame
, programSource
, LiteralParser::NonStrictJSON
);
306 if (JSValue parsedObject
= preparser
.tryLiteralParse())
309 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
310 CodeBlock
* codeBlock
= callFrame
->codeBlock();
311 RefPtr
<EvalExecutable
> eval
= codeBlock
->evalCodeCache().get(callFrame
, programSource
, scopeChain
, exceptionValue
);
313 JSValue result
= jsUndefined();
315 result
= callFrame
->globalData().interpreter
->execute(eval
.get(), callFrame
, callFrame
->thisValue().toThisObject(callFrame
), callFrame
->registers() - registerFile
->start() + registerOffset
, scopeChain
, &exceptionValue
);
320 Interpreter::Interpreter()
321 : m_sampleEntryDepth(0)
324 #if HAVE(COMPUTED_GOTO)
325 privateExecute(InitializeAndReturn
, 0, 0, 0);
327 for (int i
= 0; i
< numOpcodeIDs
; ++i
)
328 m_opcodeIDTable
.add(m_opcodeTable
[i
], static_cast<OpcodeID
>(i
));
329 #endif // HAVE(COMPUTED_GOTO)
331 #if ENABLE(OPCODE_SAMPLING)
338 void Interpreter::dumpCallFrame(CallFrame
* callFrame
)
340 callFrame
->codeBlock()->dump(callFrame
);
341 dumpRegisters(callFrame
);
344 void Interpreter::dumpRegisters(CallFrame
* callFrame
)
346 printf("Register frame: \n\n");
347 printf("-----------------------------------------------------------------------------\n");
348 printf(" use | address | value \n");
349 printf("-----------------------------------------------------------------------------\n");
351 CodeBlock
* codeBlock
= callFrame
->codeBlock();
352 RegisterFile
* registerFile
= &callFrame
->scopeChain()->globalObject
->globalData()->interpreter
->registerFile();
357 if (codeBlock
->codeType() == GlobalCode
) {
358 it
= registerFile
->lastGlobal();
359 end
= it
+ registerFile
->numGlobals();
362 #if USE(JSVALUE32_64)
363 printf("[global var] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
));
365 printf("[global var] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
));
369 printf("-----------------------------------------------------------------------------\n");
372 it
= callFrame
->registers() - RegisterFile::CallFrameHeaderSize
- codeBlock
->m_numParameters
;
374 #if USE(JSVALUE32_64)
375 printf("[this] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
)); ++it
;
377 printf("[this] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
)); ++it
;
379 end
= it
+ max(codeBlock
->m_numParameters
- 1, 0); // - 1 to skip "this"
383 #if USE(JSVALUE32_64)
384 printf("[param] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
));
386 printf("[param] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
));
391 printf("-----------------------------------------------------------------------------\n");
392 printf("[CodeBlock] | %10p | %p \n", it
, (*it
).codeBlock()); ++it
;
393 printf("[ScopeChain] | %10p | %p \n", it
, (*it
).scopeChain()); ++it
;
394 printf("[CallerRegisters] | %10p | %d \n", it
, (*it
).i()); ++it
;
395 printf("[ReturnPC] | %10p | %p \n", it
, (*it
).vPC()); ++it
;
396 printf("[ReturnValueRegister] | %10p | %d \n", it
, (*it
).i()); ++it
;
397 printf("[ArgumentCount] | %10p | %d \n", it
, (*it
).i()); ++it
;
398 printf("[Callee] | %10p | %p \n", it
, (*it
).function()); ++it
;
399 printf("[OptionalCalleeArguments] | %10p | %p \n", it
, (*it
).arguments()); ++it
;
400 printf("-----------------------------------------------------------------------------\n");
402 int registerCount
= 0;
404 end
= it
+ codeBlock
->m_numVars
;
408 #if USE(JSVALUE32_64)
409 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
411 printf("[r%2d] | %10p | %-16s %p \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
417 printf("-----------------------------------------------------------------------------\n");
419 end
= it
+ codeBlock
->m_numCalleeRegisters
- codeBlock
->m_numVars
;
423 #if USE(JSVALUE32_64)
424 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
426 printf("[r%2d] | %10p | %-16s %p \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
432 printf("-----------------------------------------------------------------------------\n");
437 bool Interpreter::isOpcode(Opcode opcode
)
439 #if HAVE(COMPUTED_GOTO)
440 return opcode
!= HashTraits
<Opcode
>::emptyValue()
441 && !HashTraits
<Opcode
>::isDeletedValue(opcode
)
442 && m_opcodeIDTable
.contains(opcode
);
444 return opcode
>= 0 && opcode
<= op_end
;
448 NEVER_INLINE
bool Interpreter::unwindCallFrame(CallFrame
*& callFrame
, JSValue exceptionValue
, unsigned& bytecodeOffset
, CodeBlock
*& codeBlock
)
450 CodeBlock
* oldCodeBlock
= codeBlock
;
451 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
453 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
454 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
455 if (callFrame
->callee())
456 debugger
->returnEvent(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->lastLine());
458 debugger
->didExecuteProgram(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->lastLine());
461 if (Profiler
* profiler
= *Profiler::enabledProfilerReference()) {
462 if (callFrame
->callee())
463 profiler
->didExecute(callFrame
, callFrame
->callee());
465 profiler
->didExecute(callFrame
, codeBlock
->ownerExecutable()->sourceURL(), codeBlock
->ownerExecutable()->lineNo());
468 // If this call frame created an activation or an 'arguments' object, tear it off.
469 if (oldCodeBlock
->codeType() == FunctionCode
&& oldCodeBlock
->needsFullScopeChain()) {
470 while (!scopeChain
->object
->inherits(&JSActivation::info
))
471 scopeChain
= scopeChain
->pop();
472 static_cast<JSActivation
*>(scopeChain
->object
)->copyRegisters(callFrame
->optionalCalleeArguments());
473 } else if (Arguments
* arguments
= callFrame
->optionalCalleeArguments()) {
474 if (!arguments
->isTornOff())
475 arguments
->copyRegisters();
478 if (oldCodeBlock
->needsFullScopeChain())
481 void* returnPC
= callFrame
->returnPC();
482 callFrame
= callFrame
->callerFrame();
483 if (callFrame
->hasHostCallFrameFlag())
486 codeBlock
= callFrame
->codeBlock();
487 bytecodeOffset
= bytecodeOffsetForPC(callFrame
, codeBlock
, returnPC
);
491 NEVER_INLINE HandlerInfo
* Interpreter::throwException(CallFrame
*& callFrame
, JSValue
& exceptionValue
, unsigned bytecodeOffset
, bool explicitThrow
)
493 // Set up the exception object
495 CodeBlock
* codeBlock
= callFrame
->codeBlock();
496 if (exceptionValue
.isObject()) {
497 JSObject
* exception
= asObject(exceptionValue
);
498 if (exception
->isNotAnObjectErrorStub()) {
499 exception
= createNotAnObjectError(callFrame
, static_cast<JSNotAnObjectErrorStub
*>(exception
), bytecodeOffset
, codeBlock
);
500 exceptionValue
= exception
;
502 if (!exception
->hasProperty(callFrame
, Identifier(callFrame
, "line")) &&
503 !exception
->hasProperty(callFrame
, Identifier(callFrame
, "sourceId")) &&
504 !exception
->hasProperty(callFrame
, Identifier(callFrame
, "sourceURL")) &&
505 !exception
->hasProperty(callFrame
, Identifier(callFrame
, expressionBeginOffsetPropertyName
)) &&
506 !exception
->hasProperty(callFrame
, Identifier(callFrame
, expressionCaretOffsetPropertyName
)) &&
507 !exception
->hasProperty(callFrame
, Identifier(callFrame
, expressionEndOffsetPropertyName
))) {
512 int line
= codeBlock
->expressionRangeForBytecodeOffset(callFrame
, bytecodeOffset
, divotPoint
, startOffset
, endOffset
);
513 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "line"), jsNumber(callFrame
, line
), ReadOnly
| DontDelete
);
515 // We only hit this path for error messages and throw statements, which don't have a specific failure position
516 // So we just give the full range of the error/throw statement.
517 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, expressionBeginOffsetPropertyName
), jsNumber(callFrame
, divotPoint
- startOffset
), ReadOnly
| DontDelete
);
518 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, expressionEndOffsetPropertyName
), jsNumber(callFrame
, divotPoint
+ endOffset
), ReadOnly
| DontDelete
);
520 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "line"), jsNumber(callFrame
, codeBlock
->lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
)), ReadOnly
| DontDelete
);
521 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "sourceId"), jsNumber(callFrame
, codeBlock
->ownerExecutable()->sourceID()), ReadOnly
| DontDelete
);
522 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "sourceURL"), jsOwnedString(callFrame
, codeBlock
->ownerExecutable()->sourceURL()), ReadOnly
| DontDelete
);
525 if (exception
->isWatchdogException()) {
526 while (unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
)) {
527 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
534 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
535 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
536 bool hasHandler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
);
537 debugger
->exception(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
), hasHandler
);
540 // If we throw in the middle of a call instruction, we need to notify
541 // the profiler manually that the call instruction has returned, since
542 // we'll never reach the relevant op_profile_did_call.
543 if (Profiler
* profiler
= *Profiler::enabledProfilerReference()) {
545 if (isCallBytecode(codeBlock
->instructions()[bytecodeOffset
].u
.opcode
))
546 profiler
->didExecute(callFrame
, callFrame
->r(codeBlock
->instructions()[bytecodeOffset
+ 2].u
.operand
).jsValue());
547 else if (codeBlock
->instructions().size() > (bytecodeOffset
+ 8) && codeBlock
->instructions()[bytecodeOffset
+ 8].u
.opcode
== getOpcode(op_construct
))
548 profiler
->didExecute(callFrame
, callFrame
->r(codeBlock
->instructions()[bytecodeOffset
+ 10].u
.operand
).jsValue());
550 int functionRegisterIndex
;
551 if (codeBlock
->functionRegisterForBytecodeOffset(bytecodeOffset
, functionRegisterIndex
))
552 profiler
->didExecute(callFrame
, callFrame
->r(functionRegisterIndex
).jsValue());
556 // Calculate an exception handler vPC, unwinding call frames as necessary.
558 HandlerInfo
* handler
= 0;
559 while (!(handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
))) {
560 if (!unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
))
564 // Now unwind the scope chain within the exception handler's call frame.
566 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
567 ScopeChain
sc(scopeChain
);
568 int scopeDelta
= depth(codeBlock
, sc
) - handler
->scopeDepth
;
569 ASSERT(scopeDelta
>= 0);
571 scopeChain
= scopeChain
->pop();
572 callFrame
->setScopeChain(scopeChain
);
577 JSValue
Interpreter::execute(ProgramExecutable
* program
, CallFrame
* callFrame
, ScopeChainNode
* scopeChain
, JSObject
* thisObj
, JSValue
* exception
)
579 ASSERT(!scopeChain
->globalData
->exception
);
581 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
582 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
583 *exception
= createStackOverflowError(callFrame
);
588 CodeBlock
* codeBlock
= &program
->bytecode(callFrame
, scopeChain
);
590 Register
* oldEnd
= m_registerFile
.end();
591 Register
* newEnd
= oldEnd
+ codeBlock
->m_numParameters
+ RegisterFile::CallFrameHeaderSize
+ codeBlock
->m_numCalleeRegisters
;
592 if (!m_registerFile
.grow(newEnd
)) {
593 *exception
= createStackOverflowError(callFrame
);
597 DynamicGlobalObjectScope
globalObjectScope(callFrame
, scopeChain
->globalObject
);
599 JSGlobalObject
* lastGlobalObject
= m_registerFile
.globalObject();
600 JSGlobalObject
* globalObject
= callFrame
->dynamicGlobalObject();
601 globalObject
->copyGlobalsTo(m_registerFile
);
603 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
+ codeBlock
->m_numParameters
+ RegisterFile::CallFrameHeaderSize
);
604 newCallFrame
->r(codeBlock
->thisRegister()) = JSValue(thisObj
);
605 newCallFrame
->init(codeBlock
, 0, scopeChain
, CallFrame::noCaller(), 0, 0, 0);
607 if (codeBlock
->needsFullScopeChain())
610 Profiler
** profiler
= Profiler::enabledProfilerReference();
612 (*profiler
)->willExecute(newCallFrame
, program
->sourceURL(), program
->lineNo());
616 SamplingTool::CallRecord
callRecord(m_sampler
.get());
620 result
= program
->jitCode(newCallFrame
, scopeChain
).execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
, exception
);
622 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
, exception
);
628 (*profiler
)->didExecute(callFrame
, program
->sourceURL(), program
->lineNo());
630 if (m_reentryDepth
&& lastGlobalObject
&& globalObject
!= lastGlobalObject
)
631 lastGlobalObject
->copyGlobalsTo(m_registerFile
);
633 m_registerFile
.shrink(oldEnd
);
638 JSValue
Interpreter::execute(FunctionExecutable
* functionExecutable
, CallFrame
* callFrame
, JSFunction
* function
, JSObject
* thisObj
, const ArgList
& args
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
640 ASSERT(!scopeChain
->globalData
->exception
);
642 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
643 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
644 *exception
= createStackOverflowError(callFrame
);
649 Register
* oldEnd
= m_registerFile
.end();
650 int argc
= 1 + args
.size(); // implicit "this" parameter
652 if (!m_registerFile
.grow(oldEnd
+ argc
)) {
653 *exception
= createStackOverflowError(callFrame
);
657 DynamicGlobalObjectScope
globalObjectScope(callFrame
, scopeChain
->globalObject
);
659 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
);
661 newCallFrame
->r(0) = JSValue(thisObj
);
662 ArgList::const_iterator end
= args
.end();
663 for (ArgList::const_iterator it
= args
.begin(); it
!= end
; ++it
)
664 newCallFrame
->r(++dst
) = *it
;
666 CodeBlock
* codeBlock
= &functionExecutable
->bytecode(callFrame
, scopeChain
);
667 newCallFrame
= slideRegisterWindowForCall(codeBlock
, &m_registerFile
, newCallFrame
, argc
+ RegisterFile::CallFrameHeaderSize
, argc
);
668 if (UNLIKELY(!newCallFrame
)) {
669 *exception
= createStackOverflowError(callFrame
);
670 m_registerFile
.shrink(oldEnd
);
673 // a 0 codeBlock indicates a built-in caller
674 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), 0, argc
, function
);
676 Profiler
** profiler
= Profiler::enabledProfilerReference();
678 (*profiler
)->willExecute(callFrame
, function
);
682 SamplingTool::CallRecord
callRecord(m_sampler
.get());
686 result
= functionExecutable
->jitCode(newCallFrame
, scopeChain
).execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
, exception
);
688 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
, exception
);
694 (*profiler
)->didExecute(callFrame
, function
);
696 m_registerFile
.shrink(oldEnd
);
700 CallFrameClosure
Interpreter::prepareForRepeatCall(FunctionExecutable
* FunctionExecutable
, CallFrame
* callFrame
, JSFunction
* function
, int argCount
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
702 ASSERT(!scopeChain
->globalData
->exception
);
704 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
705 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
706 *exception
= createStackOverflowError(callFrame
);
707 return CallFrameClosure();
711 Register
* oldEnd
= m_registerFile
.end();
712 int argc
= 1 + argCount
; // implicit "this" parameter
714 if (!m_registerFile
.grow(oldEnd
+ argc
)) {
715 *exception
= createStackOverflowError(callFrame
);
716 return CallFrameClosure();
719 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
);
721 for (int i
= 0; i
< argc
; ++i
)
722 newCallFrame
->r(++dst
) = jsUndefined();
724 CodeBlock
* codeBlock
= &FunctionExecutable
->bytecode(callFrame
, scopeChain
);
725 newCallFrame
= slideRegisterWindowForCall(codeBlock
, &m_registerFile
, newCallFrame
, argc
+ RegisterFile::CallFrameHeaderSize
, argc
);
726 if (UNLIKELY(!newCallFrame
)) {
727 *exception
= createStackOverflowError(callFrame
);
728 m_registerFile
.shrink(oldEnd
);
729 return CallFrameClosure();
731 // a 0 codeBlock indicates a built-in caller
732 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), 0, argc
, function
);
734 FunctionExecutable
->jitCode(newCallFrame
, scopeChain
);
737 CallFrameClosure result
= { callFrame
, newCallFrame
, function
, FunctionExecutable
, scopeChain
->globalData
, oldEnd
, scopeChain
, codeBlock
->m_numParameters
, argc
};
741 JSValue
Interpreter::execute(CallFrameClosure
& closure
, JSValue
* exception
)
743 closure
.resetCallFrame();
744 Profiler
** profiler
= Profiler::enabledProfilerReference();
746 (*profiler
)->willExecute(closure
.oldCallFrame
, closure
.function
);
750 SamplingTool::CallRecord
callRecord(m_sampler
.get());
754 result
= closure
.functionExecutable
->generatedJITCode().execute(&m_registerFile
, closure
.newCallFrame
, closure
.globalData
, exception
);
756 result
= privateExecute(Normal
, &m_registerFile
, closure
.newCallFrame
, exception
);
762 (*profiler
)->didExecute(closure
.oldCallFrame
, closure
.function
);
766 void Interpreter::endRepeatCall(CallFrameClosure
& closure
)
768 m_registerFile
.shrink(closure
.oldEnd
);
771 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSObject
* thisObj
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
773 return execute(eval
, callFrame
, thisObj
, m_registerFile
.size() + eval
->bytecode(callFrame
, scopeChain
).m_numParameters
+ RegisterFile::CallFrameHeaderSize
, scopeChain
, exception
);
776 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSObject
* thisObj
, int globalRegisterOffset
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
778 ASSERT(!scopeChain
->globalData
->exception
);
780 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
781 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
782 *exception
= createStackOverflowError(callFrame
);
787 DynamicGlobalObjectScope
globalObjectScope(callFrame
, scopeChain
->globalObject
);
789 EvalCodeBlock
* codeBlock
= &eval
->bytecode(callFrame
, scopeChain
);
791 JSVariableObject
* variableObject
;
792 for (ScopeChainNode
* node
= scopeChain
; ; node
= node
->next
) {
794 if (node
->object
->isVariableObject()) {
795 variableObject
= static_cast<JSVariableObject
*>(node
->object
);
800 { // Scope for BatchedTransitionOptimizer
802 BatchedTransitionOptimizer
optimizer(variableObject
);
804 unsigned numVariables
= codeBlock
->numVariables();
805 for (unsigned i
= 0; i
< numVariables
; ++i
) {
806 const Identifier
& ident
= codeBlock
->variable(i
);
807 if (!variableObject
->hasProperty(callFrame
, ident
)) {
808 PutPropertySlot slot
;
809 variableObject
->put(callFrame
, ident
, jsUndefined(), slot
);
813 int numFunctions
= codeBlock
->numberOfFunctionDecls();
814 for (int i
= 0; i
< numFunctions
; ++i
) {
815 FunctionExecutable
* function
= codeBlock
->functionDecl(i
);
816 PutPropertySlot slot
;
817 variableObject
->put(callFrame
, function
->name(), function
->make(callFrame
, scopeChain
), slot
);
822 Register
* oldEnd
= m_registerFile
.end();
823 Register
* newEnd
= m_registerFile
.start() + globalRegisterOffset
+ codeBlock
->m_numCalleeRegisters
;
824 if (!m_registerFile
.grow(newEnd
)) {
825 *exception
= createStackOverflowError(callFrame
);
829 CallFrame
* newCallFrame
= CallFrame::create(m_registerFile
.start() + globalRegisterOffset
);
831 // a 0 codeBlock indicates a built-in caller
832 newCallFrame
->r(codeBlock
->thisRegister()) = JSValue(thisObj
);
833 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), 0, 0, 0);
835 if (codeBlock
->needsFullScopeChain())
838 Profiler
** profiler
= Profiler::enabledProfilerReference();
840 (*profiler
)->willExecute(newCallFrame
, eval
->sourceURL(), eval
->lineNo());
844 SamplingTool::CallRecord
callRecord(m_sampler
.get());
848 result
= eval
->jitCode(newCallFrame
, scopeChain
).execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
, exception
);
850 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
, exception
);
856 (*profiler
)->didExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
858 m_registerFile
.shrink(oldEnd
);
862 NEVER_INLINE
void Interpreter::debug(CallFrame
* callFrame
, DebugHookID debugHookID
, int firstLine
, int lastLine
)
864 Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger();
868 switch (debugHookID
) {
869 case DidEnterCallFrame
:
870 debugger
->callEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
872 case WillLeaveCallFrame
:
873 debugger
->returnEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
875 case WillExecuteStatement
:
876 debugger
->atStatement(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
878 case WillExecuteProgram
:
879 debugger
->willExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
881 case DidExecuteProgram
:
882 debugger
->didExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
884 case DidReachBreakpoint
:
885 debugger
->didReachBreakpoint(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
891 NEVER_INLINE ScopeChainNode
* Interpreter::createExceptionScope(CallFrame
* callFrame
, const Instruction
* vPC
)
893 int dst
= vPC
[1].u
.operand
;
894 CodeBlock
* codeBlock
= callFrame
->codeBlock();
895 Identifier
& property
= codeBlock
->identifier(vPC
[2].u
.operand
);
896 JSValue value
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
897 JSObject
* scope
= new (callFrame
) JSStaticScopeObject(callFrame
, property
, value
, DontDelete
);
898 callFrame
->r(dst
) = JSValue(scope
);
900 return callFrame
->scopeChain()->push(scope
);
903 NEVER_INLINE
void Interpreter::tryCachePutByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const PutPropertySlot
& slot
)
905 // Recursive invocation may already have specialized this instruction.
906 if (vPC
[0].u
.opcode
!= getOpcode(op_put_by_id
))
909 if (!baseValue
.isCell())
912 // Uncacheable: give up.
913 if (!slot
.isCacheable()) {
914 vPC
[0] = getOpcode(op_put_by_id_generic
);
918 JSCell
* baseCell
= asCell(baseValue
);
919 Structure
* structure
= baseCell
->structure();
921 if (structure
->isUncacheableDictionary()) {
922 vPC
[0] = getOpcode(op_put_by_id_generic
);
926 // Cache miss: record Structure to compare against next time.
927 Structure
* lastStructure
= vPC
[4].u
.structure
;
928 if (structure
!= lastStructure
) {
929 // First miss: record Structure to compare against next time.
930 if (!lastStructure
) {
935 // Second miss: give up.
936 vPC
[0] = getOpcode(op_put_by_id_generic
);
940 // Cache hit: Specialize instruction and ref Structures.
942 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
943 if (baseCell
!= slot
.base()) {
944 vPC
[0] = getOpcode(op_put_by_id_generic
);
948 // Structure transition, cache transition info
949 if (slot
.type() == PutPropertySlot::NewProperty
) {
950 if (structure
->isDictionary()) {
951 vPC
[0] = getOpcode(op_put_by_id_generic
);
955 // put_by_id_transition checks the prototype chain for setters.
956 normalizePrototypeChain(callFrame
, baseCell
);
958 vPC
[0] = getOpcode(op_put_by_id_transition
);
959 vPC
[4] = structure
->previousID();
961 vPC
[6] = structure
->prototypeChain(callFrame
);
962 vPC
[7] = slot
.cachedOffset();
963 codeBlock
->refStructures(vPC
);
967 vPC
[0] = getOpcode(op_put_by_id_replace
);
968 vPC
[5] = slot
.cachedOffset();
969 codeBlock
->refStructures(vPC
);
972 NEVER_INLINE
void Interpreter::uncachePutByID(CodeBlock
* codeBlock
, Instruction
* vPC
)
974 codeBlock
->derefStructures(vPC
);
975 vPC
[0] = getOpcode(op_put_by_id
);
979 NEVER_INLINE
void Interpreter::tryCacheGetByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const Identifier
& propertyName
, const PropertySlot
& slot
)
981 // Recursive invocation may already have specialized this instruction.
982 if (vPC
[0].u
.opcode
!= getOpcode(op_get_by_id
))
985 // FIXME: Cache property access for immediates.
986 if (!baseValue
.isCell()) {
987 vPC
[0] = getOpcode(op_get_by_id_generic
);
991 JSGlobalData
* globalData
= &callFrame
->globalData();
992 if (isJSArray(globalData
, baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
993 vPC
[0] = getOpcode(op_get_array_length
);
997 if (isJSString(globalData
, baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
998 vPC
[0] = getOpcode(op_get_string_length
);
1002 // Uncacheable: give up.
1003 if (!slot
.isCacheable()) {
1004 vPC
[0] = getOpcode(op_get_by_id_generic
);
1008 Structure
* structure
= asCell(baseValue
)->structure();
1010 if (structure
->isUncacheableDictionary()) {
1011 vPC
[0] = getOpcode(op_get_by_id_generic
);
1016 Structure
* lastStructure
= vPC
[4].u
.structure
;
1017 if (structure
!= lastStructure
) {
1018 // First miss: record Structure to compare against next time.
1019 if (!lastStructure
) {
1024 // Second miss: give up.
1025 vPC
[0] = getOpcode(op_get_by_id_generic
);
1029 // Cache hit: Specialize instruction and ref Structures.
1031 if (slot
.slotBase() == baseValue
) {
1032 vPC
[0] = getOpcode(op_get_by_id_self
);
1033 vPC
[5] = slot
.cachedOffset();
1035 codeBlock
->refStructures(vPC
);
1039 if (structure
->isDictionary()) {
1040 vPC
[0] = getOpcode(op_get_by_id_generic
);
1044 if (slot
.slotBase() == structure
->prototypeForLookup(callFrame
)) {
1045 ASSERT(slot
.slotBase().isObject());
1047 JSObject
* baseObject
= asObject(slot
.slotBase());
1048 size_t offset
= slot
.cachedOffset();
1050 // Since we're accessing a prototype in a loop, it's a good bet that it
1051 // should not be treated as a dictionary.
1052 if (baseObject
->structure()->isDictionary()) {
1053 baseObject
->flattenDictionaryObject();
1054 offset
= baseObject
->structure()->get(propertyName
);
1057 ASSERT(!baseObject
->structure()->isUncacheableDictionary());
1059 vPC
[0] = getOpcode(op_get_by_id_proto
);
1060 vPC
[5] = baseObject
->structure();
1063 codeBlock
->refStructures(vPC
);
1067 size_t offset
= slot
.cachedOffset();
1068 size_t count
= normalizePrototypeChain(callFrame
, baseValue
, slot
.slotBase(), propertyName
, offset
);
1070 vPC
[0] = getOpcode(op_get_by_id_generic
);
1074 vPC
[0] = getOpcode(op_get_by_id_chain
);
1076 vPC
[5] = structure
->prototypeChain(callFrame
);
1079 codeBlock
->refStructures(vPC
);
1082 NEVER_INLINE
void Interpreter::uncacheGetByID(CodeBlock
* codeBlock
, Instruction
* vPC
)
1084 codeBlock
->derefStructures(vPC
);
1085 vPC
[0] = getOpcode(op_get_by_id
);
1089 #endif // USE(INTERPRETER)
1091 JSValue
Interpreter::privateExecute(ExecutionFlag flag
, RegisterFile
* registerFile
, CallFrame
* callFrame
, JSValue
* exception
)
1093 // One-time initialization of our address tables. We have to put this code
1094 // here because our labels are only in scope inside this function.
1095 if (UNLIKELY(flag
== InitializeAndReturn
)) {
1096 #if HAVE(COMPUTED_GOTO)
1097 #define LIST_OPCODE_LABEL(id, length) &&id,
1098 static Opcode labels
[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL
) };
1099 for (size_t i
= 0; i
< sizeof(labels
) / sizeof(Opcode
); ++i
)
1100 m_opcodeTable
[i
] = labels
[i
];
1101 #undef LIST_OPCODE_LABEL
1102 #endif // HAVE(COMPUTED_GOTO)
1107 // Mixing Interpreter + JIT is not supported.
1108 ASSERT_NOT_REACHED();
1110 #if !USE(INTERPRETER)
1111 UNUSED_PARAM(registerFile
);
1112 UNUSED_PARAM(callFrame
);
1113 UNUSED_PARAM(exception
);
1117 JSGlobalData
* globalData
= &callFrame
->globalData();
1118 JSValue exceptionValue
;
1119 HandlerInfo
* handler
= 0;
1121 Instruction
* vPC
= callFrame
->codeBlock()->instructions().begin();
1122 Profiler
** enabledProfilerReference
= Profiler::enabledProfilerReference();
1123 unsigned tickCount
= globalData
->timeoutChecker
.ticksUntilNextCheck();
1125 #define CHECK_FOR_EXCEPTION() \
1127 if (UNLIKELY(globalData->exception != JSValue())) { \
1128 exceptionValue = globalData->exception; \
1133 #if ENABLE(OPCODE_STATS)
1134 OpcodeStats::resetLastInstruction();
1137 #define CHECK_FOR_TIMEOUT() \
1138 if (!--tickCount) { \
1139 if (globalData->timeoutChecker.didTimeOut(callFrame)) { \
1140 exceptionValue = jsNull(); \
1143 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1146 #if ENABLE(OPCODE_SAMPLING)
1147 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1149 #define SAMPLE(codeBlock, vPC)
1152 #if HAVE(COMPUTED_GOTO)
1153 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
1154 #if ENABLE(OPCODE_STATS)
1155 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1157 #define DEFINE_OPCODE(opcode) opcode:
1161 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
1162 #if ENABLE(OPCODE_STATS)
1163 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1165 #define DEFINE_OPCODE(opcode) case opcode:
1167 while (1) { // iterator loop begins
1168 interpreterLoopStart
:;
1169 switch (vPC
->u
.opcode
)
1172 DEFINE_OPCODE(op_new_object
) {
1173 /* new_object dst(r)
1175 Constructs a new empty Object instance using the original
1176 constructor, and puts the result in register dst.
1178 int dst
= vPC
[1].u
.operand
;
1179 callFrame
->r(dst
) = JSValue(constructEmptyObject(callFrame
));
1181 vPC
+= OPCODE_LENGTH(op_new_object
);
1184 DEFINE_OPCODE(op_new_array
) {
1185 /* new_array dst(r) firstArg(r) argCount(n)
1187 Constructs a new Array instance using the original
1188 constructor, and puts the result in register dst.
1189 The array will contain argCount elements with values
1190 taken from registers starting at register firstArg.
1192 int dst
= vPC
[1].u
.operand
;
1193 int firstArg
= vPC
[2].u
.operand
;
1194 int argCount
= vPC
[3].u
.operand
;
1195 ArgList
args(callFrame
->registers() + firstArg
, argCount
);
1196 callFrame
->r(dst
) = JSValue(constructArray(callFrame
, args
));
1198 vPC
+= OPCODE_LENGTH(op_new_array
);
1201 DEFINE_OPCODE(op_new_regexp
) {
1202 /* new_regexp dst(r) regExp(re)
1204 Constructs a new RegExp instance using the original
1205 constructor from regexp regExp, and puts the result in
1208 int dst
= vPC
[1].u
.operand
;
1209 int regExp
= vPC
[2].u
.operand
;
1210 callFrame
->r(dst
) = JSValue(new (globalData
) RegExpObject(callFrame
->scopeChain()->globalObject
->regExpStructure(), callFrame
->codeBlock()->regexp(regExp
)));
1212 vPC
+= OPCODE_LENGTH(op_new_regexp
);
1215 DEFINE_OPCODE(op_mov
) {
1216 /* mov dst(r) src(r)
1218 Copies register src to register dst.
1220 int dst
= vPC
[1].u
.operand
;
1221 int src
= vPC
[2].u
.operand
;
1222 callFrame
->r(dst
) = callFrame
->r(src
);
1224 vPC
+= OPCODE_LENGTH(op_mov
);
1227 DEFINE_OPCODE(op_eq
) {
1228 /* eq dst(r) src1(r) src2(r)
1230 Checks whether register src1 and register src2 are equal,
1231 as with the ECMAScript '==' operator, and puts the result
1232 as a boolean in register dst.
1234 int dst
= vPC
[1].u
.operand
;
1235 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1236 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1237 if (src1
.isInt32() && src2
.isInt32())
1238 callFrame
->r(dst
) = jsBoolean(src1
.asInt32() == src2
.asInt32());
1240 JSValue result
= jsBoolean(JSValue::equalSlowCase(callFrame
, src1
, src2
));
1241 CHECK_FOR_EXCEPTION();
1242 callFrame
->r(dst
) = result
;
1245 vPC
+= OPCODE_LENGTH(op_eq
);
1248 DEFINE_OPCODE(op_eq_null
) {
1249 /* eq_null dst(r) src(r)
1251 Checks whether register src is null, as with the ECMAScript '!='
1252 operator, and puts the result as a boolean in register dst.
1254 int dst
= vPC
[1].u
.operand
;
1255 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1257 if (src
.isUndefinedOrNull()) {
1258 callFrame
->r(dst
) = jsBoolean(true);
1259 vPC
+= OPCODE_LENGTH(op_eq_null
);
1263 callFrame
->r(dst
) = jsBoolean(src
.isCell() && src
.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1264 vPC
+= OPCODE_LENGTH(op_eq_null
);
1267 DEFINE_OPCODE(op_neq
) {
1268 /* neq dst(r) src1(r) src2(r)
1270 Checks whether register src1 and register src2 are not
1271 equal, as with the ECMAScript '!=' operator, and puts the
1272 result as a boolean in register dst.
1274 int dst
= vPC
[1].u
.operand
;
1275 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1276 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1277 if (src1
.isInt32() && src2
.isInt32())
1278 callFrame
->r(dst
) = jsBoolean(src1
.asInt32() != src2
.asInt32());
1280 JSValue result
= jsBoolean(!JSValue::equalSlowCase(callFrame
, src1
, src2
));
1281 CHECK_FOR_EXCEPTION();
1282 callFrame
->r(dst
) = result
;
1285 vPC
+= OPCODE_LENGTH(op_neq
);
1288 DEFINE_OPCODE(op_neq_null
) {
1289 /* neq_null dst(r) src(r)
1291 Checks whether register src is not null, as with the ECMAScript '!='
1292 operator, and puts the result as a boolean in register dst.
1294 int dst
= vPC
[1].u
.operand
;
1295 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1297 if (src
.isUndefinedOrNull()) {
1298 callFrame
->r(dst
) = jsBoolean(false);
1299 vPC
+= OPCODE_LENGTH(op_neq_null
);
1303 callFrame
->r(dst
) = jsBoolean(!src
.isCell() || !asCell(src
)->structure()->typeInfo().masqueradesAsUndefined());
1304 vPC
+= OPCODE_LENGTH(op_neq_null
);
1307 DEFINE_OPCODE(op_stricteq
) {
1308 /* stricteq dst(r) src1(r) src2(r)
1310 Checks whether register src1 and register src2 are strictly
1311 equal, as with the ECMAScript '===' operator, and puts the
1312 result as a boolean in register dst.
1314 int dst
= vPC
[1].u
.operand
;
1315 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1316 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1317 callFrame
->r(dst
) = jsBoolean(JSValue::strictEqual(callFrame
, src1
, src2
));
1319 vPC
+= OPCODE_LENGTH(op_stricteq
);
1322 DEFINE_OPCODE(op_nstricteq
) {
1323 /* nstricteq dst(r) src1(r) src2(r)
1325 Checks whether register src1 and register src2 are not
1326 strictly equal, as with the ECMAScript '!==' operator, and
1327 puts the result as a boolean in register dst.
1329 int dst
= vPC
[1].u
.operand
;
1330 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1331 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1332 callFrame
->r(dst
) = jsBoolean(!JSValue::strictEqual(callFrame
, src1
, src2
));
1334 vPC
+= OPCODE_LENGTH(op_nstricteq
);
1337 DEFINE_OPCODE(op_less
) {
1338 /* less dst(r) src1(r) src2(r)
1340 Checks whether register src1 is less than register src2, as
1341 with the ECMAScript '<' operator, and puts the result as
1342 a boolean in register dst.
1344 int dst
= vPC
[1].u
.operand
;
1345 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1346 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1347 JSValue result
= jsBoolean(jsLess(callFrame
, src1
, src2
));
1348 CHECK_FOR_EXCEPTION();
1349 callFrame
->r(dst
) = result
;
1351 vPC
+= OPCODE_LENGTH(op_less
);
1354 DEFINE_OPCODE(op_lesseq
) {
1355 /* lesseq dst(r) src1(r) src2(r)
1357 Checks whether register src1 is less than or equal to
1358 register src2, as with the ECMAScript '<=' operator, and
1359 puts the result as a boolean in register dst.
1361 int dst
= vPC
[1].u
.operand
;
1362 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1363 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1364 JSValue result
= jsBoolean(jsLessEq(callFrame
, src1
, src2
));
1365 CHECK_FOR_EXCEPTION();
1366 callFrame
->r(dst
) = result
;
1368 vPC
+= OPCODE_LENGTH(op_lesseq
);
1371 DEFINE_OPCODE(op_pre_inc
) {
1372 /* pre_inc srcDst(r)
1374 Converts register srcDst to number, adds one, and puts the result
1375 back in register srcDst.
1377 int srcDst
= vPC
[1].u
.operand
;
1378 JSValue v
= callFrame
->r(srcDst
).jsValue();
1379 if (v
.isInt32() && v
.asInt32() < INT_MAX
)
1380 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() + 1);
1382 JSValue result
= jsNumber(callFrame
, v
.toNumber(callFrame
) + 1);
1383 CHECK_FOR_EXCEPTION();
1384 callFrame
->r(srcDst
) = result
;
1387 vPC
+= OPCODE_LENGTH(op_pre_inc
);
1390 DEFINE_OPCODE(op_pre_dec
) {
1391 /* pre_dec srcDst(r)
1393 Converts register srcDst to number, subtracts one, and puts the result
1394 back in register srcDst.
1396 int srcDst
= vPC
[1].u
.operand
;
1397 JSValue v
= callFrame
->r(srcDst
).jsValue();
1398 if (v
.isInt32() && v
.asInt32() > INT_MIN
)
1399 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() - 1);
1401 JSValue result
= jsNumber(callFrame
, v
.toNumber(callFrame
) - 1);
1402 CHECK_FOR_EXCEPTION();
1403 callFrame
->r(srcDst
) = result
;
1406 vPC
+= OPCODE_LENGTH(op_pre_dec
);
1409 DEFINE_OPCODE(op_post_inc
) {
1410 /* post_inc dst(r) srcDst(r)
1412 Converts register srcDst to number. The number itself is
1413 written to register dst, and the number plus one is written
1414 back to register srcDst.
1416 int dst
= vPC
[1].u
.operand
;
1417 int srcDst
= vPC
[2].u
.operand
;
1418 JSValue v
= callFrame
->r(srcDst
).jsValue();
1419 if (v
.isInt32() && v
.asInt32() < INT_MAX
) {
1420 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() + 1);
1421 callFrame
->r(dst
) = v
;
1423 JSValue number
= callFrame
->r(srcDst
).jsValue().toJSNumber(callFrame
);
1424 CHECK_FOR_EXCEPTION();
1425 callFrame
->r(srcDst
) = jsNumber(callFrame
, number
.uncheckedGetNumber() + 1);
1426 callFrame
->r(dst
) = number
;
1429 vPC
+= OPCODE_LENGTH(op_post_inc
);
1432 DEFINE_OPCODE(op_post_dec
) {
1433 /* post_dec dst(r) srcDst(r)
1435 Converts register srcDst to number. The number itself is
1436 written to register dst, and the number minus one is written
1437 back to register srcDst.
1439 int dst
= vPC
[1].u
.operand
;
1440 int srcDst
= vPC
[2].u
.operand
;
1441 JSValue v
= callFrame
->r(srcDst
).jsValue();
1442 if (v
.isInt32() && v
.asInt32() > INT_MIN
) {
1443 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() - 1);
1444 callFrame
->r(dst
) = v
;
1446 JSValue number
= callFrame
->r(srcDst
).jsValue().toJSNumber(callFrame
);
1447 CHECK_FOR_EXCEPTION();
1448 callFrame
->r(srcDst
) = jsNumber(callFrame
, number
.uncheckedGetNumber() - 1);
1449 callFrame
->r(dst
) = number
;
1452 vPC
+= OPCODE_LENGTH(op_post_dec
);
1455 DEFINE_OPCODE(op_to_jsnumber
) {
1456 /* to_jsnumber dst(r) src(r)
1458 Converts register src to number, and puts the result
1461 int dst
= vPC
[1].u
.operand
;
1462 int src
= vPC
[2].u
.operand
;
1464 JSValue srcVal
= callFrame
->r(src
).jsValue();
1466 if (LIKELY(srcVal
.isNumber()))
1467 callFrame
->r(dst
) = callFrame
->r(src
);
1469 JSValue result
= srcVal
.toJSNumber(callFrame
);
1470 CHECK_FOR_EXCEPTION();
1471 callFrame
->r(dst
) = result
;
1474 vPC
+= OPCODE_LENGTH(op_to_jsnumber
);
1477 DEFINE_OPCODE(op_negate
) {
1478 /* negate dst(r) src(r)
1480 Converts register src to number, negates it, and puts the
1481 result in register dst.
1483 int dst
= vPC
[1].u
.operand
;
1484 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1485 if (src
.isInt32() && src
.asInt32())
1486 callFrame
->r(dst
) = jsNumber(callFrame
, -src
.asInt32());
1488 JSValue result
= jsNumber(callFrame
, -src
.toNumber(callFrame
));
1489 CHECK_FOR_EXCEPTION();
1490 callFrame
->r(dst
) = result
;
1493 vPC
+= OPCODE_LENGTH(op_negate
);
1496 DEFINE_OPCODE(op_add
) {
1497 /* add dst(r) src1(r) src2(r)
1499 Adds register src1 and register src2, and puts the result
1500 in register dst. (JS add may be string concatenation or
1501 numeric add, depending on the types of the operands.)
1503 int dst
= vPC
[1].u
.operand
;
1504 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1505 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1506 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | (src2
.asInt32() & 0xc0000000))) // no overflow
1507 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() + src2
.asInt32());
1509 JSValue result
= jsAdd(callFrame
, src1
, src2
);
1510 CHECK_FOR_EXCEPTION();
1511 callFrame
->r(dst
) = result
;
1513 vPC
+= OPCODE_LENGTH(op_add
);
1516 DEFINE_OPCODE(op_mul
) {
1517 /* mul dst(r) src1(r) src2(r)
1519 Multiplies register src1 and register src2 (converted to
1520 numbers), and puts the product in register dst.
1522 int dst
= vPC
[1].u
.operand
;
1523 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1524 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1525 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | src2
.asInt32() >> 15)) // no overflow
1526 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() * src2
.asInt32());
1528 JSValue result
= jsNumber(callFrame
, src1
.toNumber(callFrame
) * src2
.toNumber(callFrame
));
1529 CHECK_FOR_EXCEPTION();
1530 callFrame
->r(dst
) = result
;
1533 vPC
+= OPCODE_LENGTH(op_mul
);
1536 DEFINE_OPCODE(op_div
) {
1537 /* div dst(r) dividend(r) divisor(r)
1539 Divides register dividend (converted to number) by the
1540 register divisor (converted to number), and puts the
1541 quotient in register dst.
1543 int dst
= vPC
[1].u
.operand
;
1544 JSValue dividend
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1545 JSValue divisor
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1547 JSValue result
= jsNumber(callFrame
, dividend
.toNumber(callFrame
) / divisor
.toNumber(callFrame
));
1548 CHECK_FOR_EXCEPTION();
1549 callFrame
->r(dst
) = result
;
1551 vPC
+= OPCODE_LENGTH(op_div
);
1554 DEFINE_OPCODE(op_mod
) {
1555 /* mod dst(r) dividend(r) divisor(r)
1557 Divides register dividend (converted to number) by
1558 register divisor (converted to number), and puts the
1559 remainder in register dst.
1561 int dst
= vPC
[1].u
.operand
;
1562 JSValue dividend
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1563 JSValue divisor
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1565 if (dividend
.isInt32() && divisor
.isInt32() && divisor
.asInt32() != 0) {
1566 JSValue result
= jsNumber(callFrame
, dividend
.asInt32() % divisor
.asInt32());
1568 callFrame
->r(dst
) = result
;
1569 vPC
+= OPCODE_LENGTH(op_mod
);
1573 // Conversion to double must happen outside the call to fmod since the
1574 // order of argument evaluation is not guaranteed.
1575 double d1
= dividend
.toNumber(callFrame
);
1576 double d2
= divisor
.toNumber(callFrame
);
1577 JSValue result
= jsNumber(callFrame
, fmod(d1
, d2
));
1578 CHECK_FOR_EXCEPTION();
1579 callFrame
->r(dst
) = result
;
1580 vPC
+= OPCODE_LENGTH(op_mod
);
1583 DEFINE_OPCODE(op_sub
) {
1584 /* sub dst(r) src1(r) src2(r)
1586 Subtracts register src2 (converted to number) from register
1587 src1 (converted to number), and puts the difference in
1590 int dst
= vPC
[1].u
.operand
;
1591 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1592 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1593 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | (src2
.asInt32() & 0xc0000000))) // no overflow
1594 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() - src2
.asInt32());
1596 JSValue result
= jsNumber(callFrame
, src1
.toNumber(callFrame
) - src2
.toNumber(callFrame
));
1597 CHECK_FOR_EXCEPTION();
1598 callFrame
->r(dst
) = result
;
1600 vPC
+= OPCODE_LENGTH(op_sub
);
1603 DEFINE_OPCODE(op_lshift
) {
1604 /* lshift dst(r) val(r) shift(r)
1606 Performs left shift of register val (converted to int32) by
1607 register shift (converted to uint32), and puts the result
1610 int dst
= vPC
[1].u
.operand
;
1611 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1612 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1614 if (val
.isInt32() && shift
.isInt32())
1615 callFrame
->r(dst
) = jsNumber(callFrame
, val
.asInt32() << (shift
.asInt32() & 0x1f));
1617 JSValue result
= jsNumber(callFrame
, (val
.toInt32(callFrame
)) << (shift
.toUInt32(callFrame
) & 0x1f));
1618 CHECK_FOR_EXCEPTION();
1619 callFrame
->r(dst
) = result
;
1622 vPC
+= OPCODE_LENGTH(op_lshift
);
1625 DEFINE_OPCODE(op_rshift
) {
1626 /* rshift dst(r) val(r) shift(r)
1628 Performs arithmetic right shift of register val (converted
1629 to int32) by register shift (converted to
1630 uint32), and puts the result in register dst.
1632 int dst
= vPC
[1].u
.operand
;
1633 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1634 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1636 if (val
.isInt32() && shift
.isInt32())
1637 callFrame
->r(dst
) = jsNumber(callFrame
, val
.asInt32() >> (shift
.asInt32() & 0x1f));
1639 JSValue result
= jsNumber(callFrame
, (val
.toInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
1640 CHECK_FOR_EXCEPTION();
1641 callFrame
->r(dst
) = result
;
1644 vPC
+= OPCODE_LENGTH(op_rshift
);
1647 DEFINE_OPCODE(op_urshift
) {
1648 /* rshift dst(r) val(r) shift(r)
1650 Performs logical right shift of register val (converted
1651 to uint32) by register shift (converted to
1652 uint32), and puts the result in register dst.
1654 int dst
= vPC
[1].u
.operand
;
1655 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1656 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1657 if (val
.isUInt32() && shift
.isInt32())
1658 callFrame
->r(dst
) = jsNumber(callFrame
, val
.asInt32() >> (shift
.asInt32() & 0x1f));
1660 JSValue result
= jsNumber(callFrame
, (val
.toUInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
1661 CHECK_FOR_EXCEPTION();
1662 callFrame
->r(dst
) = result
;
1665 vPC
+= OPCODE_LENGTH(op_urshift
);
1668 DEFINE_OPCODE(op_bitand
) {
1669 /* bitand dst(r) src1(r) src2(r)
1671 Computes bitwise AND of register src1 (converted to int32)
1672 and register src2 (converted to int32), and puts the result
1675 int dst
= vPC
[1].u
.operand
;
1676 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1677 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1678 if (src1
.isInt32() && src2
.isInt32())
1679 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() & src2
.asInt32());
1681 JSValue result
= jsNumber(callFrame
, src1
.toInt32(callFrame
) & src2
.toInt32(callFrame
));
1682 CHECK_FOR_EXCEPTION();
1683 callFrame
->r(dst
) = result
;
1686 vPC
+= OPCODE_LENGTH(op_bitand
);
1689 DEFINE_OPCODE(op_bitxor
) {
1690 /* bitxor dst(r) src1(r) src2(r)
1692 Computes bitwise XOR of register src1 (converted to int32)
1693 and register src2 (converted to int32), and puts the result
1696 int dst
= vPC
[1].u
.operand
;
1697 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1698 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1699 if (src1
.isInt32() && src2
.isInt32())
1700 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() ^ src2
.asInt32());
1702 JSValue result
= jsNumber(callFrame
, src1
.toInt32(callFrame
) ^ src2
.toInt32(callFrame
));
1703 CHECK_FOR_EXCEPTION();
1704 callFrame
->r(dst
) = result
;
1707 vPC
+= OPCODE_LENGTH(op_bitxor
);
1710 DEFINE_OPCODE(op_bitor
) {
1711 /* bitor dst(r) src1(r) src2(r)
1713 Computes bitwise OR of register src1 (converted to int32)
1714 and register src2 (converted to int32), and puts the
1715 result in register dst.
1717 int dst
= vPC
[1].u
.operand
;
1718 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1719 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1720 if (src1
.isInt32() && src2
.isInt32())
1721 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() | src2
.asInt32());
1723 JSValue result
= jsNumber(callFrame
, src1
.toInt32(callFrame
) | src2
.toInt32(callFrame
));
1724 CHECK_FOR_EXCEPTION();
1725 callFrame
->r(dst
) = result
;
1728 vPC
+= OPCODE_LENGTH(op_bitor
);
1731 DEFINE_OPCODE(op_bitnot
) {
1732 /* bitnot dst(r) src(r)
1734 Computes bitwise NOT of register src1 (converted to int32),
1735 and puts the result in register dst.
1737 int dst
= vPC
[1].u
.operand
;
1738 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1740 callFrame
->r(dst
) = jsNumber(callFrame
, ~src
.asInt32());
1742 JSValue result
= jsNumber(callFrame
, ~src
.toInt32(callFrame
));
1743 CHECK_FOR_EXCEPTION();
1744 callFrame
->r(dst
) = result
;
1746 vPC
+= OPCODE_LENGTH(op_bitnot
);
1749 DEFINE_OPCODE(op_not
) {
1750 /* not dst(r) src(r)
1752 Computes logical NOT of register src (converted to
1753 boolean), and puts the result in register dst.
1755 int dst
= vPC
[1].u
.operand
;
1756 int src
= vPC
[2].u
.operand
;
1757 JSValue result
= jsBoolean(!callFrame
->r(src
).jsValue().toBoolean(callFrame
));
1758 CHECK_FOR_EXCEPTION();
1759 callFrame
->r(dst
) = result
;
1761 vPC
+= OPCODE_LENGTH(op_not
);
1764 DEFINE_OPCODE(op_instanceof
) {
1765 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
1767 Tests whether register value is an instance of register
1768 constructor, and puts the boolean result in register
1769 dst. Register constructorProto must contain the "prototype"
1770 property (not the actual prototype) of the object in
1771 register constructor. This lookup is separated so that
1772 polymorphic inline caching can apply.
1774 Raises an exception if register constructor is not an
1777 int dst
= vPC
[1].u
.operand
;
1778 int value
= vPC
[2].u
.operand
;
1779 int base
= vPC
[3].u
.operand
;
1780 int baseProto
= vPC
[4].u
.operand
;
1782 JSValue baseVal
= callFrame
->r(base
).jsValue();
1784 if (isInvalidParamForInstanceOf(callFrame
, callFrame
->codeBlock(), vPC
, baseVal
, exceptionValue
))
1787 bool result
= asObject(baseVal
)->hasInstance(callFrame
, callFrame
->r(value
).jsValue(), callFrame
->r(baseProto
).jsValue());
1788 CHECK_FOR_EXCEPTION();
1789 callFrame
->r(dst
) = jsBoolean(result
);
1791 vPC
+= OPCODE_LENGTH(op_instanceof
);
1794 DEFINE_OPCODE(op_typeof
) {
1795 /* typeof dst(r) src(r)
1797 Determines the type string for src according to ECMAScript
1798 rules, and puts the result in register dst.
1800 int dst
= vPC
[1].u
.operand
;
1801 int src
= vPC
[2].u
.operand
;
1802 callFrame
->r(dst
) = JSValue(jsTypeStringForValue(callFrame
, callFrame
->r(src
).jsValue()));
1804 vPC
+= OPCODE_LENGTH(op_typeof
);
1807 DEFINE_OPCODE(op_is_undefined
) {
1808 /* is_undefined dst(r) src(r)
1810 Determines whether the type string for src according to
1811 the ECMAScript rules is "undefined", and puts the result
1814 int dst
= vPC
[1].u
.operand
;
1815 int src
= vPC
[2].u
.operand
;
1816 JSValue v
= callFrame
->r(src
).jsValue();
1817 callFrame
->r(dst
) = jsBoolean(v
.isCell() ? v
.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v
.isUndefined());
1819 vPC
+= OPCODE_LENGTH(op_is_undefined
);
1822 DEFINE_OPCODE(op_is_boolean
) {
1823 /* is_boolean dst(r) src(r)
1825 Determines whether the type string for src according to
1826 the ECMAScript rules is "boolean", and puts the result
1829 int dst
= vPC
[1].u
.operand
;
1830 int src
= vPC
[2].u
.operand
;
1831 callFrame
->r(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isBoolean());
1833 vPC
+= OPCODE_LENGTH(op_is_boolean
);
1836 DEFINE_OPCODE(op_is_number
) {
1837 /* is_number dst(r) src(r)
1839 Determines whether the type string for src according to
1840 the ECMAScript rules is "number", and puts the result
1843 int dst
= vPC
[1].u
.operand
;
1844 int src
= vPC
[2].u
.operand
;
1845 callFrame
->r(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isNumber());
1847 vPC
+= OPCODE_LENGTH(op_is_number
);
1850 DEFINE_OPCODE(op_is_string
) {
1851 /* is_string dst(r) src(r)
1853 Determines whether the type string for src according to
1854 the ECMAScript rules is "string", and puts the result
1857 int dst
= vPC
[1].u
.operand
;
1858 int src
= vPC
[2].u
.operand
;
1859 callFrame
->r(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isString());
1861 vPC
+= OPCODE_LENGTH(op_is_string
);
1864 DEFINE_OPCODE(op_is_object
) {
1865 /* is_object dst(r) src(r)
1867 Determines whether the type string for src according to
1868 the ECMAScript rules is "object", and puts the result
1871 int dst
= vPC
[1].u
.operand
;
1872 int src
= vPC
[2].u
.operand
;
1873 callFrame
->r(dst
) = jsBoolean(jsIsObjectType(callFrame
->r(src
).jsValue()));
1875 vPC
+= OPCODE_LENGTH(op_is_object
);
1878 DEFINE_OPCODE(op_is_function
) {
1879 /* is_function dst(r) src(r)
1881 Determines whether the type string for src according to
1882 the ECMAScript rules is "function", and puts the result
1885 int dst
= vPC
[1].u
.operand
;
1886 int src
= vPC
[2].u
.operand
;
1887 callFrame
->r(dst
) = jsBoolean(jsIsFunctionType(callFrame
->r(src
).jsValue()));
1889 vPC
+= OPCODE_LENGTH(op_is_function
);
1892 DEFINE_OPCODE(op_in
) {
1893 /* in dst(r) property(r) base(r)
1895 Tests whether register base has a property named register
1896 property, and puts the boolean result in register dst.
1898 Raises an exception if register constructor is not an
1901 int dst
= vPC
[1].u
.operand
;
1902 int property
= vPC
[2].u
.operand
;
1903 int base
= vPC
[3].u
.operand
;
1905 JSValue baseVal
= callFrame
->r(base
).jsValue();
1906 if (isInvalidParamForIn(callFrame
, callFrame
->codeBlock(), vPC
, baseVal
, exceptionValue
))
1909 JSObject
* baseObj
= asObject(baseVal
);
1911 JSValue propName
= callFrame
->r(property
).jsValue();
1914 if (propName
.getUInt32(i
))
1915 callFrame
->r(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, i
));
1917 Identifier
property(callFrame
, propName
.toString(callFrame
));
1918 CHECK_FOR_EXCEPTION();
1919 callFrame
->r(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, property
));
1922 vPC
+= OPCODE_LENGTH(op_in
);
1925 DEFINE_OPCODE(op_resolve
) {
1926 /* resolve dst(r) property(id)
1928 Looks up the property named by identifier property in the
1929 scope chain, and writes the resulting value to register
1930 dst. If the property is not found, raises an exception.
1932 if (UNLIKELY(!resolve(callFrame
, vPC
, exceptionValue
)))
1935 vPC
+= OPCODE_LENGTH(op_resolve
);
1938 DEFINE_OPCODE(op_resolve_skip
) {
1939 /* resolve_skip dst(r) property(id) skip(n)
1941 Looks up the property named by identifier property in the
1942 scope chain skipping the top 'skip' levels, and writes the resulting
1943 value to register dst. If the property is not found, raises an exception.
1945 if (UNLIKELY(!resolveSkip(callFrame
, vPC
, exceptionValue
)))
1948 vPC
+= OPCODE_LENGTH(op_resolve_skip
);
1952 DEFINE_OPCODE(op_resolve_global
) {
1953 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
1955 Performs a dynamic property lookup for the given property, on the provided
1956 global object. If structure matches the Structure of the global then perform
1957 a fast lookup using the case offset, otherwise fall back to a full resolve and
1958 cache the new structure and offset
1960 if (UNLIKELY(!resolveGlobal(callFrame
, vPC
, exceptionValue
)))
1963 vPC
+= OPCODE_LENGTH(op_resolve_global
);
1967 DEFINE_OPCODE(op_get_global_var
) {
1968 /* get_global_var dst(r) globalObject(c) index(n)
1970 Gets the global var at global slot index and places it in register dst.
1972 int dst
= vPC
[1].u
.operand
;
1973 JSGlobalObject
* scope
= static_cast<JSGlobalObject
*>(vPC
[2].u
.jsCell
);
1974 ASSERT(scope
->isGlobalObject());
1975 int index
= vPC
[3].u
.operand
;
1977 callFrame
->r(dst
) = scope
->registerAt(index
);
1978 vPC
+= OPCODE_LENGTH(op_get_global_var
);
1981 DEFINE_OPCODE(op_put_global_var
) {
1982 /* put_global_var globalObject(c) index(n) value(r)
1984 Puts value into global slot index.
1986 JSGlobalObject
* scope
= static_cast<JSGlobalObject
*>(vPC
[1].u
.jsCell
);
1987 ASSERT(scope
->isGlobalObject());
1988 int index
= vPC
[2].u
.operand
;
1989 int value
= vPC
[3].u
.operand
;
1991 scope
->registerAt(index
) = JSValue(callFrame
->r(value
).jsValue());
1992 vPC
+= OPCODE_LENGTH(op_put_global_var
);
1995 DEFINE_OPCODE(op_get_scoped_var
) {
1996 /* get_scoped_var dst(r) index(n) skip(n)
1998 Loads the contents of the index-th local from the scope skip nodes from
1999 the top of the scope chain, and places it in register dst
2001 int dst
= vPC
[1].u
.operand
;
2002 int index
= vPC
[2].u
.operand
;
2003 int skip
= vPC
[3].u
.operand
+ callFrame
->codeBlock()->needsFullScopeChain();
2005 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2006 ScopeChainIterator iter
= scopeChain
->begin();
2007 ScopeChainIterator end
= scopeChain
->end();
2008 ASSERT(iter
!= end
);
2011 ASSERT(iter
!= end
);
2014 ASSERT((*iter
)->isVariableObject());
2015 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(*iter
);
2016 callFrame
->r(dst
) = scope
->registerAt(index
);
2017 vPC
+= OPCODE_LENGTH(op_get_scoped_var
);
2020 DEFINE_OPCODE(op_put_scoped_var
) {
2021 /* put_scoped_var index(n) skip(n) value(r)
2024 int index
= vPC
[1].u
.operand
;
2025 int skip
= vPC
[2].u
.operand
+ callFrame
->codeBlock()->needsFullScopeChain();
2026 int value
= vPC
[3].u
.operand
;
2028 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2029 ScopeChainIterator iter
= scopeChain
->begin();
2030 ScopeChainIterator end
= scopeChain
->end();
2031 ASSERT(iter
!= end
);
2034 ASSERT(iter
!= end
);
2037 ASSERT((*iter
)->isVariableObject());
2038 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(*iter
);
2039 scope
->registerAt(index
) = JSValue(callFrame
->r(value
).jsValue());
2040 vPC
+= OPCODE_LENGTH(op_put_scoped_var
);
2043 DEFINE_OPCODE(op_resolve_base
) {
2044 /* resolve_base dst(r) property(id)
2046 Searches the scope chain for an object containing
2047 identifier property, and if one is found, writes it to
2048 register dst. If none is found, the outermost scope (which
2049 will be the global object) is stored in register dst.
2051 resolveBase(callFrame
, vPC
);
2053 vPC
+= OPCODE_LENGTH(op_resolve_base
);
2056 DEFINE_OPCODE(op_resolve_with_base
) {
2057 /* resolve_with_base baseDst(r) propDst(r) property(id)
2059 Searches the scope chain for an object containing
2060 identifier property, and if one is found, writes it to
2061 register srcDst, and the retrieved property value to register
2062 propDst. If the property is not found, raises an exception.
2064 This is more efficient than doing resolve_base followed by
2065 resolve, or resolve_base followed by get_by_id, as it
2066 avoids duplicate hash lookups.
2068 if (UNLIKELY(!resolveBaseAndProperty(callFrame
, vPC
, exceptionValue
)))
2071 vPC
+= OPCODE_LENGTH(op_resolve_with_base
);
2074 DEFINE_OPCODE(op_get_by_id
) {
2075 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2077 Generic property access: Gets the property named by identifier
2078 property from the value base, and puts the result in register dst.
2080 int dst
= vPC
[1].u
.operand
;
2081 int base
= vPC
[2].u
.operand
;
2082 int property
= vPC
[3].u
.operand
;
2084 CodeBlock
* codeBlock
= callFrame
->codeBlock();
2085 Identifier
& ident
= codeBlock
->identifier(property
);
2086 JSValue baseValue
= callFrame
->r(base
).jsValue();
2087 PropertySlot
slot(baseValue
);
2088 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
2089 CHECK_FOR_EXCEPTION();
2091 tryCacheGetByID(callFrame
, codeBlock
, vPC
, baseValue
, ident
, slot
);
2093 callFrame
->r(dst
) = result
;
2094 vPC
+= OPCODE_LENGTH(op_get_by_id
);
2097 DEFINE_OPCODE(op_get_by_id_self
) {
2098 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2100 Cached property access: Attempts to get a cached property from the
2101 value base. If the cache misses, op_get_by_id_self reverts to
2104 int base
= vPC
[2].u
.operand
;
2105 JSValue baseValue
= callFrame
->r(base
).jsValue();
2107 if (LIKELY(baseValue
.isCell())) {
2108 JSCell
* baseCell
= asCell(baseValue
);
2109 Structure
* structure
= vPC
[4].u
.structure
;
2111 if (LIKELY(baseCell
->structure() == structure
)) {
2112 ASSERT(baseCell
->isObject());
2113 JSObject
* baseObject
= asObject(baseCell
);
2114 int dst
= vPC
[1].u
.operand
;
2115 int offset
= vPC
[5].u
.operand
;
2117 ASSERT(baseObject
->get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2118 callFrame
->r(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
2120 vPC
+= OPCODE_LENGTH(op_get_by_id_self
);
2125 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2128 DEFINE_OPCODE(op_get_by_id_proto
) {
2129 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2131 Cached property access: Attempts to get a cached property from the
2132 value base's prototype. If the cache misses, op_get_by_id_proto
2133 reverts to op_get_by_id.
2135 int base
= vPC
[2].u
.operand
;
2136 JSValue baseValue
= callFrame
->r(base
).jsValue();
2138 if (LIKELY(baseValue
.isCell())) {
2139 JSCell
* baseCell
= asCell(baseValue
);
2140 Structure
* structure
= vPC
[4].u
.structure
;
2142 if (LIKELY(baseCell
->structure() == structure
)) {
2143 ASSERT(structure
->prototypeForLookup(callFrame
).isObject());
2144 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
2145 Structure
* prototypeStructure
= vPC
[5].u
.structure
;
2147 if (LIKELY(protoObject
->structure() == prototypeStructure
)) {
2148 int dst
= vPC
[1].u
.operand
;
2149 int offset
= vPC
[6].u
.operand
;
2151 ASSERT(protoObject
->get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
2152 ASSERT(baseValue
.get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
2153 callFrame
->r(dst
) = JSValue(protoObject
->getDirectOffset(offset
));
2155 vPC
+= OPCODE_LENGTH(op_get_by_id_proto
);
2161 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2164 DEFINE_OPCODE(op_get_by_id_self_list
) {
2165 // Polymorphic self access caching currently only supported when JITting.
2166 ASSERT_NOT_REACHED();
2167 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2168 vPC
+= OPCODE_LENGTH(op_get_by_id_self_list
);
2171 DEFINE_OPCODE(op_get_by_id_proto_list
) {
2172 // Polymorphic prototype access caching currently only supported when JITting.
2173 ASSERT_NOT_REACHED();
2174 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2175 vPC
+= OPCODE_LENGTH(op_get_by_id_proto_list
);
2178 DEFINE_OPCODE(op_get_by_id_chain
) {
2179 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2181 Cached property access: Attempts to get a cached property from the
2182 value base's prototype chain. If the cache misses, op_get_by_id_chain
2183 reverts to op_get_by_id.
2185 int base
= vPC
[2].u
.operand
;
2186 JSValue baseValue
= callFrame
->r(base
).jsValue();
2188 if (LIKELY(baseValue
.isCell())) {
2189 JSCell
* baseCell
= asCell(baseValue
);
2190 Structure
* structure
= vPC
[4].u
.structure
;
2192 if (LIKELY(baseCell
->structure() == structure
)) {
2193 RefPtr
<Structure
>* it
= vPC
[5].u
.structureChain
->head();
2194 size_t count
= vPC
[6].u
.operand
;
2195 RefPtr
<Structure
>* end
= it
+ count
;
2198 JSObject
* baseObject
= asObject(baseCell
->structure()->prototypeForLookup(callFrame
));
2200 if (UNLIKELY(baseObject
->structure() != (*it
).get()))
2204 int dst
= vPC
[1].u
.operand
;
2205 int offset
= vPC
[7].u
.operand
;
2207 ASSERT(baseObject
->get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2208 ASSERT(baseValue
.get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2209 callFrame
->r(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
2211 vPC
+= OPCODE_LENGTH(op_get_by_id_chain
);
2215 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2216 baseCell
= baseObject
;
2221 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2224 DEFINE_OPCODE(op_get_by_id_generic
) {
2225 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2227 Generic property access: Gets the property named by identifier
2228 property from the value base, and puts the result in register dst.
2230 int dst
= vPC
[1].u
.operand
;
2231 int base
= vPC
[2].u
.operand
;
2232 int property
= vPC
[3].u
.operand
;
2234 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
2235 JSValue baseValue
= callFrame
->r(base
).jsValue();
2236 PropertySlot
slot(baseValue
);
2237 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
2238 CHECK_FOR_EXCEPTION();
2240 callFrame
->r(dst
) = result
;
2241 vPC
+= OPCODE_LENGTH(op_get_by_id_generic
);
2244 DEFINE_OPCODE(op_get_array_length
) {
2245 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2247 Cached property access: Gets the length of the array in register base,
2248 and puts the result in register dst. If register base does not hold
2249 an array, op_get_array_length reverts to op_get_by_id.
2252 int base
= vPC
[2].u
.operand
;
2253 JSValue baseValue
= callFrame
->r(base
).jsValue();
2254 if (LIKELY(isJSArray(globalData
, baseValue
))) {
2255 int dst
= vPC
[1].u
.operand
;
2256 callFrame
->r(dst
) = jsNumber(callFrame
, asArray(baseValue
)->length());
2257 vPC
+= OPCODE_LENGTH(op_get_array_length
);
2261 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2264 DEFINE_OPCODE(op_get_string_length
) {
2265 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2267 Cached property access: Gets the length of the string in register base,
2268 and puts the result in register dst. If register base does not hold
2269 a string, op_get_string_length reverts to op_get_by_id.
2272 int base
= vPC
[2].u
.operand
;
2273 JSValue baseValue
= callFrame
->r(base
).jsValue();
2274 if (LIKELY(isJSString(globalData
, baseValue
))) {
2275 int dst
= vPC
[1].u
.operand
;
2276 callFrame
->r(dst
) = jsNumber(callFrame
, asString(baseValue
)->length());
2277 vPC
+= OPCODE_LENGTH(op_get_string_length
);
2281 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2284 DEFINE_OPCODE(op_put_by_id
) {
2285 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2287 Generic property access: Sets the property named by identifier
2288 property, belonging to register base, to register value.
2290 Unlike many opcodes, this one does not write any output to
2294 int base
= vPC
[1].u
.operand
;
2295 int property
= vPC
[2].u
.operand
;
2296 int value
= vPC
[3].u
.operand
;
2298 CodeBlock
* codeBlock
= callFrame
->codeBlock();
2299 JSValue baseValue
= callFrame
->r(base
).jsValue();
2300 Identifier
& ident
= codeBlock
->identifier(property
);
2301 PutPropertySlot slot
;
2302 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
2303 CHECK_FOR_EXCEPTION();
2305 tryCachePutByID(callFrame
, codeBlock
, vPC
, baseValue
, slot
);
2307 vPC
+= OPCODE_LENGTH(op_put_by_id
);
2310 DEFINE_OPCODE(op_put_by_id_transition
) {
2311 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)
2313 Cached property access: Attempts to set a new property with a cached transition
2314 property named by identifier property, belonging to register base,
2315 to register value. If the cache misses, op_put_by_id_transition
2316 reverts to op_put_by_id_generic.
2318 Unlike many opcodes, this one does not write any output to
2321 int base
= vPC
[1].u
.operand
;
2322 JSValue baseValue
= callFrame
->r(base
).jsValue();
2324 if (LIKELY(baseValue
.isCell())) {
2325 JSCell
* baseCell
= asCell(baseValue
);
2326 Structure
* oldStructure
= vPC
[4].u
.structure
;
2327 Structure
* newStructure
= vPC
[5].u
.structure
;
2329 if (LIKELY(baseCell
->structure() == oldStructure
)) {
2330 ASSERT(baseCell
->isObject());
2331 JSObject
* baseObject
= asObject(baseCell
);
2333 RefPtr
<Structure
>* it
= vPC
[6].u
.structureChain
->head();
2335 JSValue proto
= baseObject
->structure()->prototypeForLookup(callFrame
);
2336 while (!proto
.isNull()) {
2337 if (UNLIKELY(asObject(proto
)->structure() != (*it
).get())) {
2338 uncachePutByID(callFrame
->codeBlock(), vPC
);
2342 proto
= asObject(proto
)->structure()->prototypeForLookup(callFrame
);
2345 baseObject
->transitionTo(newStructure
);
2347 int value
= vPC
[3].u
.operand
;
2348 unsigned offset
= vPC
[7].u
.operand
;
2349 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(callFrame
->codeBlock()->identifier(vPC
[2].u
.operand
))) == offset
);
2350 baseObject
->putDirectOffset(offset
, callFrame
->r(value
).jsValue());
2352 vPC
+= OPCODE_LENGTH(op_put_by_id_transition
);
2357 uncachePutByID(callFrame
->codeBlock(), vPC
);
2360 DEFINE_OPCODE(op_put_by_id_replace
) {
2361 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)
2363 Cached property access: Attempts to set a pre-existing, cached
2364 property named by identifier property, belonging to register base,
2365 to register value. If the cache misses, op_put_by_id_replace
2366 reverts to op_put_by_id.
2368 Unlike many opcodes, this one does not write any output to
2371 int base
= vPC
[1].u
.operand
;
2372 JSValue baseValue
= callFrame
->r(base
).jsValue();
2374 if (LIKELY(baseValue
.isCell())) {
2375 JSCell
* baseCell
= asCell(baseValue
);
2376 Structure
* structure
= vPC
[4].u
.structure
;
2378 if (LIKELY(baseCell
->structure() == structure
)) {
2379 ASSERT(baseCell
->isObject());
2380 JSObject
* baseObject
= asObject(baseCell
);
2381 int value
= vPC
[3].u
.operand
;
2382 unsigned offset
= vPC
[5].u
.operand
;
2384 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(callFrame
->codeBlock()->identifier(vPC
[2].u
.operand
))) == offset
);
2385 baseObject
->putDirectOffset(offset
, callFrame
->r(value
).jsValue());
2387 vPC
+= OPCODE_LENGTH(op_put_by_id_replace
);
2392 uncachePutByID(callFrame
->codeBlock(), vPC
);
2395 DEFINE_OPCODE(op_put_by_id_generic
) {
2396 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2398 Generic property access: Sets the property named by identifier
2399 property, belonging to register base, to register value.
2401 Unlike many opcodes, this one does not write any output to
2404 int base
= vPC
[1].u
.operand
;
2405 int property
= vPC
[2].u
.operand
;
2406 int value
= vPC
[3].u
.operand
;
2408 JSValue baseValue
= callFrame
->r(base
).jsValue();
2409 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
2410 PutPropertySlot slot
;
2411 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
2412 CHECK_FOR_EXCEPTION();
2414 vPC
+= OPCODE_LENGTH(op_put_by_id_generic
);
2417 DEFINE_OPCODE(op_del_by_id
) {
2418 /* del_by_id dst(r) base(r) property(id)
2420 Converts register base to Object, deletes the property
2421 named by identifier property from the object, and writes a
2422 boolean indicating success (if true) or failure (if false)
2425 int dst
= vPC
[1].u
.operand
;
2426 int base
= vPC
[2].u
.operand
;
2427 int property
= vPC
[3].u
.operand
;
2429 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
);
2430 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
2431 JSValue result
= jsBoolean(baseObj
->deleteProperty(callFrame
, ident
));
2432 CHECK_FOR_EXCEPTION();
2433 callFrame
->r(dst
) = result
;
2434 vPC
+= OPCODE_LENGTH(op_del_by_id
);
2437 DEFINE_OPCODE(op_get_by_pname
) {
2438 int dst
= vPC
[1].u
.operand
;
2439 int base
= vPC
[2].u
.operand
;
2440 int property
= vPC
[3].u
.operand
;
2441 int expected
= vPC
[4].u
.operand
;
2442 int iter
= vPC
[5].u
.operand
;
2443 int i
= vPC
[6].u
.operand
;
2445 JSValue baseValue
= callFrame
->r(base
).jsValue();
2446 JSPropertyNameIterator
* it
= callFrame
->r(iter
).propertyNameIterator();
2447 JSValue subscript
= callFrame
->r(property
).jsValue();
2448 JSValue expectedSubscript
= callFrame
->r(expected
).jsValue();
2449 int index
= callFrame
->r(i
).i() - 1;
2452 if (subscript
== expectedSubscript
&& baseValue
.isCell() && (baseValue
.asCell()->structure() == it
->cachedStructure()) && it
->getOffset(index
, offset
)) {
2453 callFrame
->r(dst
) = asObject(baseValue
)->getDirectOffset(offset
);
2454 vPC
+= OPCODE_LENGTH(op_get_by_pname
);
2457 Identifier
propertyName(callFrame
, subscript
.toString(callFrame
));
2458 result
= baseValue
.get(callFrame
, propertyName
);
2459 CHECK_FOR_EXCEPTION();
2460 callFrame
->r(dst
) = result
;
2461 vPC
+= OPCODE_LENGTH(op_get_by_pname
);
2464 DEFINE_OPCODE(op_get_by_val
) {
2465 /* get_by_val dst(r) base(r) property(r)
2467 Converts register base to Object, gets the property named
2468 by register property from the object, and puts the result
2469 in register dst. property is nominally converted to string
2470 but numbers are treated more efficiently.
2472 int dst
= vPC
[1].u
.operand
;
2473 int base
= vPC
[2].u
.operand
;
2474 int property
= vPC
[3].u
.operand
;
2476 JSValue baseValue
= callFrame
->r(base
).jsValue();
2477 JSValue subscript
= callFrame
->r(property
).jsValue();
2481 if (LIKELY(subscript
.isUInt32())) {
2482 uint32_t i
= subscript
.asUInt32();
2483 if (isJSArray(globalData
, baseValue
)) {
2484 JSArray
* jsArray
= asArray(baseValue
);
2485 if (jsArray
->canGetIndex(i
))
2486 result
= jsArray
->getIndex(i
);
2488 result
= jsArray
->JSArray::get(callFrame
, i
);
2489 } else if (isJSString(globalData
, baseValue
) && asString(baseValue
)->canGetIndex(i
))
2490 result
= asString(baseValue
)->getIndex(callFrame
, i
);
2491 else if (isJSByteArray(globalData
, baseValue
) && asByteArray(baseValue
)->canAccessIndex(i
))
2492 result
= asByteArray(baseValue
)->getIndex(callFrame
, i
);
2494 result
= baseValue
.get(callFrame
, i
);
2496 Identifier
property(callFrame
, subscript
.toString(callFrame
));
2497 result
= baseValue
.get(callFrame
, property
);
2500 CHECK_FOR_EXCEPTION();
2501 callFrame
->r(dst
) = result
;
2502 vPC
+= OPCODE_LENGTH(op_get_by_val
);
2505 DEFINE_OPCODE(op_put_by_val
) {
2506 /* put_by_val base(r) property(r) value(r)
2508 Sets register value on register base as the property named
2509 by register property. Base is converted to object
2510 first. register property is nominally converted to string
2511 but numbers are treated more efficiently.
2513 Unlike many opcodes, this one does not write any output to
2516 int base
= vPC
[1].u
.operand
;
2517 int property
= vPC
[2].u
.operand
;
2518 int value
= vPC
[3].u
.operand
;
2520 JSValue baseValue
= callFrame
->r(base
).jsValue();
2521 JSValue subscript
= callFrame
->r(property
).jsValue();
2523 if (LIKELY(subscript
.isUInt32())) {
2524 uint32_t i
= subscript
.asUInt32();
2525 if (isJSArray(globalData
, baseValue
)) {
2526 JSArray
* jsArray
= asArray(baseValue
);
2527 if (jsArray
->canSetIndex(i
))
2528 jsArray
->setIndex(i
, callFrame
->r(value
).jsValue());
2530 jsArray
->JSArray::put(callFrame
, i
, callFrame
->r(value
).jsValue());
2531 } else if (isJSByteArray(globalData
, baseValue
) && asByteArray(baseValue
)->canAccessIndex(i
)) {
2532 JSByteArray
* jsByteArray
= asByteArray(baseValue
);
2534 JSValue jsValue
= callFrame
->r(value
).jsValue();
2535 if (jsValue
.isInt32())
2536 jsByteArray
->setIndex(i
, jsValue
.asInt32());
2537 else if (jsValue
.getNumber(dValue
))
2538 jsByteArray
->setIndex(i
, dValue
);
2540 baseValue
.put(callFrame
, i
, jsValue
);
2542 baseValue
.put(callFrame
, i
, callFrame
->r(value
).jsValue());
2544 Identifier
property(callFrame
, subscript
.toString(callFrame
));
2545 if (!globalData
->exception
) { // Don't put to an object if toString threw an exception.
2546 PutPropertySlot slot
;
2547 baseValue
.put(callFrame
, property
, callFrame
->r(value
).jsValue(), slot
);
2551 CHECK_FOR_EXCEPTION();
2552 vPC
+= OPCODE_LENGTH(op_put_by_val
);
2555 DEFINE_OPCODE(op_del_by_val
) {
2556 /* del_by_val dst(r) base(r) property(r)
2558 Converts register base to Object, deletes the property
2559 named by register property from the object, and writes a
2560 boolean indicating success (if true) or failure (if false)
2563 int dst
= vPC
[1].u
.operand
;
2564 int base
= vPC
[2].u
.operand
;
2565 int property
= vPC
[3].u
.operand
;
2567 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
); // may throw
2569 JSValue subscript
= callFrame
->r(property
).jsValue();
2572 if (subscript
.getUInt32(i
))
2573 result
= jsBoolean(baseObj
->deleteProperty(callFrame
, i
));
2575 CHECK_FOR_EXCEPTION();
2576 Identifier
property(callFrame
, subscript
.toString(callFrame
));
2577 CHECK_FOR_EXCEPTION();
2578 result
= jsBoolean(baseObj
->deleteProperty(callFrame
, property
));
2581 CHECK_FOR_EXCEPTION();
2582 callFrame
->r(dst
) = result
;
2583 vPC
+= OPCODE_LENGTH(op_del_by_val
);
2586 DEFINE_OPCODE(op_put_by_index
) {
2587 /* put_by_index base(r) property(n) value(r)
2589 Sets register value on register base as the property named
2590 by the immediate number property. Base is converted to
2593 Unlike many opcodes, this one does not write any output to
2596 This opcode is mainly used to initialize array literals.
2598 int base
= vPC
[1].u
.operand
;
2599 unsigned property
= vPC
[2].u
.operand
;
2600 int value
= vPC
[3].u
.operand
;
2602 callFrame
->r(base
).jsValue().put(callFrame
, property
, callFrame
->r(value
).jsValue());
2604 vPC
+= OPCODE_LENGTH(op_put_by_index
);
2607 DEFINE_OPCODE(op_loop
) {
2608 /* loop target(offset)
2610 Jumps unconditionally to offset target from the current
2613 Additionally this loop instruction may terminate JS execution is
2614 the JS timeout is reached.
2616 #if ENABLE(OPCODE_STATS)
2617 OpcodeStats::resetLastInstruction();
2619 int target
= vPC
[1].u
.operand
;
2620 CHECK_FOR_TIMEOUT();
2624 DEFINE_OPCODE(op_jmp
) {
2625 /* jmp target(offset)
2627 Jumps unconditionally to offset target from the current
2630 #if ENABLE(OPCODE_STATS)
2631 OpcodeStats::resetLastInstruction();
2633 int target
= vPC
[1].u
.operand
;
2638 DEFINE_OPCODE(op_loop_if_true
) {
2639 /* loop_if_true cond(r) target(offset)
2641 Jumps to offset target from the current instruction, if and
2642 only if register cond converts to boolean as true.
2644 Additionally this loop instruction may terminate JS execution is
2645 the JS timeout is reached.
2647 int cond
= vPC
[1].u
.operand
;
2648 int target
= vPC
[2].u
.operand
;
2649 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2651 CHECK_FOR_TIMEOUT();
2655 vPC
+= OPCODE_LENGTH(op_loop_if_true
);
2658 DEFINE_OPCODE(op_loop_if_false
) {
2659 /* loop_if_true cond(r) target(offset)
2661 Jumps to offset target from the current instruction, if and
2662 only if register cond converts to boolean as false.
2664 Additionally this loop instruction may terminate JS execution is
2665 the JS timeout is reached.
2667 int cond
= vPC
[1].u
.operand
;
2668 int target
= vPC
[2].u
.operand
;
2669 if (!callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2671 CHECK_FOR_TIMEOUT();
2675 vPC
+= OPCODE_LENGTH(op_loop_if_true
);
2678 DEFINE_OPCODE(op_jtrue
) {
2679 /* jtrue cond(r) target(offset)
2681 Jumps to offset target from the current instruction, if and
2682 only if register cond converts to boolean as true.
2684 int cond
= vPC
[1].u
.operand
;
2685 int target
= vPC
[2].u
.operand
;
2686 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2691 vPC
+= OPCODE_LENGTH(op_jtrue
);
2694 DEFINE_OPCODE(op_jfalse
) {
2695 /* jfalse cond(r) target(offset)
2697 Jumps to offset target from the current instruction, if and
2698 only if register cond converts to boolean as false.
2700 int cond
= vPC
[1].u
.operand
;
2701 int target
= vPC
[2].u
.operand
;
2702 if (!callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2707 vPC
+= OPCODE_LENGTH(op_jfalse
);
2710 DEFINE_OPCODE(op_jeq_null
) {
2711 /* jeq_null src(r) target(offset)
2713 Jumps to offset target from the current instruction, if and
2714 only if register src is null.
2716 int src
= vPC
[1].u
.operand
;
2717 int target
= vPC
[2].u
.operand
;
2718 JSValue srcValue
= callFrame
->r(src
).jsValue();
2720 if (srcValue
.isUndefinedOrNull() || (srcValue
.isCell() && srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2725 vPC
+= OPCODE_LENGTH(op_jeq_null
);
2728 DEFINE_OPCODE(op_jneq_null
) {
2729 /* jneq_null src(r) target(offset)
2731 Jumps to offset target from the current instruction, if and
2732 only if register src is not null.
2734 int src
= vPC
[1].u
.operand
;
2735 int target
= vPC
[2].u
.operand
;
2736 JSValue srcValue
= callFrame
->r(src
).jsValue();
2738 if (!srcValue
.isUndefinedOrNull() && (!srcValue
.isCell() || !srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2743 vPC
+= OPCODE_LENGTH(op_jneq_null
);
2746 DEFINE_OPCODE(op_jneq_ptr
) {
2747 /* jneq_ptr src(r) ptr(jsCell) target(offset)
2749 Jumps to offset target from the current instruction, if the value r is equal
2750 to ptr, using pointer equality.
2752 int src
= vPC
[1].u
.operand
;
2753 JSValue ptr
= JSValue(vPC
[2].u
.jsCell
);
2754 int target
= vPC
[3].u
.operand
;
2755 JSValue srcValue
= callFrame
->r(src
).jsValue();
2756 if (srcValue
!= ptr
) {
2761 vPC
+= OPCODE_LENGTH(op_jneq_ptr
);
2764 DEFINE_OPCODE(op_loop_if_less
) {
2765 /* loop_if_less src1(r) src2(r) target(offset)
2767 Checks whether register src1 is less than register src2, as
2768 with the ECMAScript '<' operator, and then jumps to offset
2769 target from the current instruction, if and only if the
2770 result of the comparison is true.
2772 Additionally this loop instruction may terminate JS execution is
2773 the JS timeout is reached.
2775 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2776 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2777 int target
= vPC
[3].u
.operand
;
2779 bool result
= jsLess(callFrame
, src1
, src2
);
2780 CHECK_FOR_EXCEPTION();
2784 CHECK_FOR_TIMEOUT();
2788 vPC
+= OPCODE_LENGTH(op_loop_if_less
);
2791 DEFINE_OPCODE(op_loop_if_lesseq
) {
2792 /* loop_if_lesseq src1(r) src2(r) target(offset)
2794 Checks whether register src1 is less than or equal to register
2795 src2, as with the ECMAScript '<=' operator, and then jumps to
2796 offset target from the current instruction, if and only if the
2797 result of the comparison is true.
2799 Additionally this loop instruction may terminate JS execution is
2800 the JS timeout is reached.
2802 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2803 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2804 int target
= vPC
[3].u
.operand
;
2806 bool result
= jsLessEq(callFrame
, src1
, src2
);
2807 CHECK_FOR_EXCEPTION();
2811 CHECK_FOR_TIMEOUT();
2815 vPC
+= OPCODE_LENGTH(op_loop_if_lesseq
);
2818 DEFINE_OPCODE(op_jnless
) {
2819 /* jnless src1(r) src2(r) target(offset)
2821 Checks whether register src1 is less than register src2, as
2822 with the ECMAScript '<' operator, and then jumps to offset
2823 target from the current instruction, if and only if the
2824 result of the comparison is false.
2826 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2827 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2828 int target
= vPC
[3].u
.operand
;
2830 bool result
= jsLess(callFrame
, src1
, src2
);
2831 CHECK_FOR_EXCEPTION();
2838 vPC
+= OPCODE_LENGTH(op_jnless
);
2841 DEFINE_OPCODE(op_jless
) {
2842 /* jless src1(r) src2(r) target(offset)
2844 Checks whether register src1 is less than register src2, as
2845 with the ECMAScript '<' operator, and then jumps to offset
2846 target from the current instruction, if and only if the
2847 result of the comparison is true.
2849 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2850 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2851 int target
= vPC
[3].u
.operand
;
2853 bool result
= jsLess(callFrame
, src1
, src2
);
2854 CHECK_FOR_EXCEPTION();
2861 vPC
+= OPCODE_LENGTH(op_jless
);
2864 DEFINE_OPCODE(op_jnlesseq
) {
2865 /* jnlesseq src1(r) src2(r) target(offset)
2867 Checks whether register src1 is less than or equal to
2868 register src2, as with the ECMAScript '<=' operator,
2869 and then jumps to offset target from the current instruction,
2870 if and only if theresult of the comparison is false.
2872 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2873 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2874 int target
= vPC
[3].u
.operand
;
2876 bool result
= jsLessEq(callFrame
, src1
, src2
);
2877 CHECK_FOR_EXCEPTION();
2884 vPC
+= OPCODE_LENGTH(op_jnlesseq
);
2887 DEFINE_OPCODE(op_switch_imm
) {
2888 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2890 Performs a range checked switch on the scrutinee value, using
2891 the tableIndex-th immediate switch jump table. If the scrutinee value
2892 is an immediate number in the range covered by the referenced jump
2893 table, and the value at jumpTable[scrutinee value] is non-zero, then
2894 that value is used as the jump offset, otherwise defaultOffset is used.
2896 int tableIndex
= vPC
[1].u
.operand
;
2897 int defaultOffset
= vPC
[2].u
.operand
;
2898 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2899 if (scrutinee
.isInt32())
2900 vPC
+= callFrame
->codeBlock()->immediateSwitchJumpTable(tableIndex
).offsetForValue(scrutinee
.asInt32(), defaultOffset
);
2904 if (scrutinee
.getNumber(value
) && ((intValue
= static_cast<int32_t>(value
)) == value
))
2905 vPC
+= callFrame
->codeBlock()->immediateSwitchJumpTable(tableIndex
).offsetForValue(intValue
, defaultOffset
);
2907 vPC
+= defaultOffset
;
2911 DEFINE_OPCODE(op_switch_char
) {
2912 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2914 Performs a range checked switch on the scrutinee value, using
2915 the tableIndex-th character switch jump table. If the scrutinee value
2916 is a single character string in the range covered by the referenced jump
2917 table, and the value at jumpTable[scrutinee value] is non-zero, then
2918 that value is used as the jump offset, otherwise defaultOffset is used.
2920 int tableIndex
= vPC
[1].u
.operand
;
2921 int defaultOffset
= vPC
[2].u
.operand
;
2922 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2923 if (!scrutinee
.isString())
2924 vPC
+= defaultOffset
;
2926 UString::Rep
* value
= asString(scrutinee
)->value(callFrame
).rep();
2927 if (value
->size() != 1)
2928 vPC
+= defaultOffset
;
2930 vPC
+= callFrame
->codeBlock()->characterSwitchJumpTable(tableIndex
).offsetForValue(value
->data()[0], defaultOffset
);
2934 DEFINE_OPCODE(op_switch_string
) {
2935 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2937 Performs a sparse hashmap based switch on the value in the scrutinee
2938 register, using the tableIndex-th string switch jump table. If the
2939 scrutinee value is a string that exists as a key in the referenced
2940 jump table, then the value associated with the string is used as the
2941 jump offset, otherwise defaultOffset is used.
2943 int tableIndex
= vPC
[1].u
.operand
;
2944 int defaultOffset
= vPC
[2].u
.operand
;
2945 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2946 if (!scrutinee
.isString())
2947 vPC
+= defaultOffset
;
2949 vPC
+= callFrame
->codeBlock()->stringSwitchJumpTable(tableIndex
).offsetForValue(asString(scrutinee
)->value(callFrame
).rep(), defaultOffset
);
2952 DEFINE_OPCODE(op_new_func
) {
2953 /* new_func dst(r) func(f)
2955 Constructs a new Function instance from function func and
2956 the current scope chain using the original Function
2957 constructor, using the rules for function declarations, and
2958 puts the result in register dst.
2960 int dst
= vPC
[1].u
.operand
;
2961 int func
= vPC
[2].u
.operand
;
2963 callFrame
->r(dst
) = JSValue(callFrame
->codeBlock()->functionDecl(func
)->make(callFrame
, callFrame
->scopeChain()));
2965 vPC
+= OPCODE_LENGTH(op_new_func
);
2968 DEFINE_OPCODE(op_new_func_exp
) {
2969 /* new_func_exp dst(r) func(f)
2971 Constructs a new Function instance from function func and
2972 the current scope chain using the original Function
2973 constructor, using the rules for function expressions, and
2974 puts the result in register dst.
2976 int dst
= vPC
[1].u
.operand
;
2977 int funcIndex
= vPC
[2].u
.operand
;
2979 FunctionExecutable
* function
= callFrame
->codeBlock()->functionExpr(funcIndex
);
2980 JSFunction
* func
= function
->make(callFrame
, callFrame
->scopeChain());
2983 The Identifier in a FunctionExpression can be referenced from inside
2984 the FunctionExpression's FunctionBody to allow the function to call
2985 itself recursively. However, unlike in a FunctionDeclaration, the
2986 Identifier in a FunctionExpression cannot be referenced from and
2987 does not affect the scope enclosing the FunctionExpression.
2989 if (!function
->name().isNull()) {
2990 JSStaticScopeObject
* functionScopeObject
= new (callFrame
) JSStaticScopeObject(callFrame
, function
->name(), func
, ReadOnly
| DontDelete
);
2991 func
->scope().push(functionScopeObject
);
2994 callFrame
->r(dst
) = JSValue(func
);
2996 vPC
+= OPCODE_LENGTH(op_new_func_exp
);
2999 DEFINE_OPCODE(op_call_eval
) {
3000 /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
3002 Call a function named "eval" with no explicit "this" value
3003 (which may therefore be the eval operator). If register
3004 thisVal is the global object, and register func contains
3005 that global object's original global eval function, then
3006 perform the eval operator in local scope (interpreting
3007 the argument registers as for the "call"
3008 opcode). Otherwise, act exactly as the "call" opcode would.
3011 int dst
= vPC
[1].u
.operand
;
3012 int func
= vPC
[2].u
.operand
;
3013 int argCount
= vPC
[3].u
.operand
;
3014 int registerOffset
= vPC
[4].u
.operand
;
3016 JSValue funcVal
= callFrame
->r(func
).jsValue();
3018 Register
* newCallFrame
= callFrame
->registers() + registerOffset
;
3019 Register
* argv
= newCallFrame
- RegisterFile::CallFrameHeaderSize
- argCount
;
3020 JSValue thisValue
= argv
[0].jsValue();
3021 JSGlobalObject
* globalObject
= callFrame
->scopeChain()->globalObject
;
3023 if (thisValue
== globalObject
&& funcVal
== globalObject
->evalFunction()) {
3024 JSValue result
= callEval(callFrame
, registerFile
, argv
, argCount
, registerOffset
, exceptionValue
);
3027 callFrame
->r(dst
) = result
;
3029 vPC
+= OPCODE_LENGTH(op_call_eval
);
3033 // We didn't find the blessed version of eval, so process this
3034 // instruction as a normal function call.
3035 // fall through to op_call
3037 DEFINE_OPCODE(op_call
) {
3038 /* call dst(r) func(r) argCount(n) registerOffset(n)
3040 Perform a function call.
3042 registerOffset is the distance the callFrame pointer should move
3043 before the VM initializes the new call frame's header.
3045 dst is where op_ret should store its result.
3048 int dst
= vPC
[1].u
.operand
;
3049 int func
= vPC
[2].u
.operand
;
3050 int argCount
= vPC
[3].u
.operand
;
3051 int registerOffset
= vPC
[4].u
.operand
;
3053 JSValue v
= callFrame
->r(func
).jsValue();
3056 CallType callType
= v
.getCallData(callData
);
3058 if (callType
== CallTypeJS
) {
3059 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
3060 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->bytecode(callFrame
, callDataScopeChain
);
3062 CallFrame
* previousCallFrame
= callFrame
;
3064 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
3065 if (UNLIKELY(!callFrame
)) {
3066 callFrame
= previousCallFrame
;
3067 exceptionValue
= createStackOverflowError(callFrame
);
3071 callFrame
->init(newCodeBlock
, vPC
+ 5, callDataScopeChain
, previousCallFrame
, dst
, argCount
, asFunction(v
));
3072 vPC
= newCodeBlock
->instructions().begin();
3074 #if ENABLE(OPCODE_STATS)
3075 OpcodeStats::resetLastInstruction();
3081 if (callType
== CallTypeHost
) {
3082 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3083 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
3084 newCallFrame
->init(0, vPC
+ 5, scopeChain
, callFrame
, dst
, argCount
, 0);
3086 Register
* thisRegister
= newCallFrame
->registers() - RegisterFile::CallFrameHeaderSize
- argCount
;
3087 ArgList
args(thisRegister
+ 1, argCount
- 1);
3089 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3090 JSValue thisValue
= thisRegister
->jsValue();
3091 if (thisValue
== jsNull())
3092 thisValue
= callFrame
->globalThisValue();
3094 JSValue returnValue
;
3096 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
3097 returnValue
= callData
.native
.function(newCallFrame
, asObject(v
), thisValue
, args
);
3099 CHECK_FOR_EXCEPTION();
3101 callFrame
->r(dst
) = returnValue
;
3103 vPC
+= OPCODE_LENGTH(op_call
);
3107 ASSERT(callType
== CallTypeNone
);
3109 exceptionValue
= createNotAFunctionError(callFrame
, v
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3112 DEFINE_OPCODE(op_load_varargs
) {
3113 int argCountDst
= vPC
[1].u
.operand
;
3114 int argsOffset
= vPC
[2].u
.operand
;
3116 JSValue arguments
= callFrame
->r(argsOffset
).jsValue();
3117 uint32_t argCount
= 0;
3119 argCount
= (uint32_t)(callFrame
->argumentCount()) - 1;
3120 argCount
= min
<uint32_t>(argCount
, Arguments::MaxArguments
);
3121 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3122 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3123 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3124 exceptionValue
= createStackOverflowError(callFrame
);
3127 ASSERT(!callFrame
->callee()->isHostFunction());
3128 uint32_t expectedParams
= callFrame
->callee()->jsExecutable()->parameterCount();
3129 uint32_t inplaceArgs
= min(argCount
, expectedParams
);
3131 Register
* argStore
= callFrame
->registers() + argsOffset
;
3133 // First step is to copy the "expected" parameters from their normal location relative to the callframe
3134 for (; i
< inplaceArgs
; i
++)
3135 argStore
[i
] = callFrame
->registers()[i
- RegisterFile::CallFrameHeaderSize
- expectedParams
];
3136 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
3137 for (; i
< argCount
; i
++)
3138 argStore
[i
] = callFrame
->registers()[i
- RegisterFile::CallFrameHeaderSize
- expectedParams
- argCount
- 1];
3139 } else if (!arguments
.isUndefinedOrNull()) {
3140 if (!arguments
.isObject()) {
3141 exceptionValue
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3144 if (asObject(arguments
)->classInfo() == &Arguments::info
) {
3145 Arguments
* args
= asArguments(arguments
);
3146 argCount
= args
->numProvidedArguments(callFrame
);
3147 argCount
= min
<uint32_t>(argCount
, Arguments::MaxArguments
);
3148 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3149 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3150 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3151 exceptionValue
= createStackOverflowError(callFrame
);
3154 args
->copyToRegisters(callFrame
, callFrame
->registers() + argsOffset
, argCount
);
3155 } else if (isJSArray(&callFrame
->globalData(), arguments
)) {
3156 JSArray
* array
= asArray(arguments
);
3157 argCount
= array
->length();
3158 argCount
= min
<uint32_t>(argCount
, Arguments::MaxArguments
);
3159 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3160 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3161 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3162 exceptionValue
= createStackOverflowError(callFrame
);
3165 array
->copyToRegisters(callFrame
, callFrame
->registers() + argsOffset
, argCount
);
3166 } else if (asObject(arguments
)->inherits(&JSArray::info
)) {
3167 JSObject
* argObject
= asObject(arguments
);
3168 argCount
= argObject
->get(callFrame
, callFrame
->propertyNames().length
).toUInt32(callFrame
);
3169 argCount
= min
<uint32_t>(argCount
, Arguments::MaxArguments
);
3170 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3171 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3172 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3173 exceptionValue
= createStackOverflowError(callFrame
);
3176 Register
* argsBuffer
= callFrame
->registers() + argsOffset
;
3177 for (uint32_t i
= 0; i
< argCount
; ++i
) {
3178 argsBuffer
[i
] = asObject(arguments
)->get(callFrame
, i
);
3179 CHECK_FOR_EXCEPTION();
3182 if (!arguments
.isObject()) {
3183 exceptionValue
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3188 CHECK_FOR_EXCEPTION();
3189 callFrame
->r(argCountDst
) = Register::withInt(argCount
+ 1);
3190 vPC
+= OPCODE_LENGTH(op_load_varargs
);
3193 DEFINE_OPCODE(op_call_varargs
) {
3194 /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
3196 Perform a function call with a dynamic set of arguments.
3198 registerOffset is the distance the callFrame pointer should move
3199 before the VM initializes the new call frame's header, excluding
3200 space for arguments.
3202 dst is where op_ret should store its result.
3205 int dst
= vPC
[1].u
.operand
;
3206 int func
= vPC
[2].u
.operand
;
3207 int argCountReg
= vPC
[3].u
.operand
;
3208 int registerOffset
= vPC
[4].u
.operand
;
3210 JSValue v
= callFrame
->r(func
).jsValue();
3211 int argCount
= callFrame
->r(argCountReg
).i();
3212 registerOffset
+= argCount
;
3214 CallType callType
= v
.getCallData(callData
);
3216 if (callType
== CallTypeJS
) {
3217 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
3218 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->bytecode(callFrame
, callDataScopeChain
);
3220 CallFrame
* previousCallFrame
= callFrame
;
3222 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
3223 if (UNLIKELY(!callFrame
)) {
3224 callFrame
= previousCallFrame
;
3225 exceptionValue
= createStackOverflowError(callFrame
);
3229 callFrame
->init(newCodeBlock
, vPC
+ 5, callDataScopeChain
, previousCallFrame
, dst
, argCount
, asFunction(v
));
3230 vPC
= newCodeBlock
->instructions().begin();
3232 #if ENABLE(OPCODE_STATS)
3233 OpcodeStats::resetLastInstruction();
3239 if (callType
== CallTypeHost
) {
3240 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3241 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
3242 newCallFrame
->init(0, vPC
+ 5, scopeChain
, callFrame
, dst
, argCount
, 0);
3244 Register
* thisRegister
= newCallFrame
->registers() - RegisterFile::CallFrameHeaderSize
- argCount
;
3245 ArgList
args(thisRegister
+ 1, argCount
- 1);
3247 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3248 JSValue thisValue
= thisRegister
->jsValue();
3249 if (thisValue
== jsNull())
3250 thisValue
= callFrame
->globalThisValue();
3252 JSValue returnValue
;
3254 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
3255 returnValue
= callData
.native
.function(newCallFrame
, asObject(v
), thisValue
, args
);
3257 CHECK_FOR_EXCEPTION();
3259 callFrame
->r(dst
) = returnValue
;
3261 vPC
+= OPCODE_LENGTH(op_call_varargs
);
3265 ASSERT(callType
== CallTypeNone
);
3267 exceptionValue
= createNotAFunctionError(callFrame
, v
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3270 DEFINE_OPCODE(op_tear_off_activation
) {
3271 /* tear_off_activation activation(r)
3273 Copy all locals and parameters to new memory allocated on
3274 the heap, and make the passed activation use this memory
3275 in the future when looking up entries in the symbol table.
3276 If there is an 'arguments' object, then it will also use
3277 this memory for storing the named parameters, but not any
3280 This opcode should only be used immediately before op_ret.
3283 int src
= vPC
[1].u
.operand
;
3284 ASSERT(callFrame
->codeBlock()->needsFullScopeChain());
3286 asActivation(callFrame
->r(src
).jsValue())->copyRegisters(callFrame
->optionalCalleeArguments());
3288 vPC
+= OPCODE_LENGTH(op_tear_off_activation
);
3291 DEFINE_OPCODE(op_tear_off_arguments
) {
3292 /* tear_off_arguments
3294 Copy all arguments to new memory allocated on the heap,
3295 and make the 'arguments' object use this memory in the
3296 future when looking up named parameters, but not any
3297 extra arguments. If an activation object exists for the
3298 current function context, then the tear_off_activation
3299 opcode should be used instead.
3301 This opcode should only be used immediately before op_ret.
3304 ASSERT(callFrame
->codeBlock()->usesArguments() && !callFrame
->codeBlock()->needsFullScopeChain());
3306 if (callFrame
->optionalCalleeArguments())
3307 callFrame
->optionalCalleeArguments()->copyRegisters();
3309 vPC
+= OPCODE_LENGTH(op_tear_off_arguments
);
3312 DEFINE_OPCODE(op_ret
) {
3315 Return register result as the return value of the current
3316 function call, writing it into the caller's expected return
3317 value register. In addition, unwind one call frame and
3318 restore the scope chain, code block instruction pointer and
3319 register base to those of the calling function.
3322 int result
= vPC
[1].u
.operand
;
3324 if (callFrame
->codeBlock()->needsFullScopeChain())
3325 callFrame
->scopeChain()->deref();
3327 JSValue returnValue
= callFrame
->r(result
).jsValue();
3329 vPC
= callFrame
->returnPC();
3330 int dst
= callFrame
->returnValueRegister();
3331 callFrame
= callFrame
->callerFrame();
3333 if (callFrame
->hasHostCallFrameFlag())
3336 callFrame
->r(dst
) = returnValue
;
3340 DEFINE_OPCODE(op_enter
) {
3343 Initializes local variables to undefined and fills constant
3344 registers with their values. If the code block requires an
3345 activation, enter_with_activation should be used instead.
3347 This opcode should only be used at the beginning of a code
3352 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3354 for (size_t count
= codeBlock
->m_numVars
; i
< count
; ++i
)
3355 callFrame
->r(i
) = jsUndefined();
3357 vPC
+= OPCODE_LENGTH(op_enter
);
3360 DEFINE_OPCODE(op_enter_with_activation
) {
3361 /* enter_with_activation dst(r)
3363 Initializes local variables to undefined, fills constant
3364 registers with their values, creates an activation object,
3365 and places the new activation both in dst and at the top
3366 of the scope chain. If the code block does not require an
3367 activation, enter should be used instead.
3369 This opcode should only be used at the beginning of a code
3374 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3376 for (size_t count
= codeBlock
->m_numVars
; i
< count
; ++i
)
3377 callFrame
->r(i
) = jsUndefined();
3379 int dst
= vPC
[1].u
.operand
;
3380 JSActivation
* activation
= new (globalData
) JSActivation(callFrame
, static_cast<FunctionExecutable
*>(codeBlock
->ownerExecutable()));
3381 callFrame
->r(dst
) = JSValue(activation
);
3382 callFrame
->setScopeChain(callFrame
->scopeChain()->copy()->push(activation
));
3384 vPC
+= OPCODE_LENGTH(op_enter_with_activation
);
3387 DEFINE_OPCODE(op_convert_this
) {
3388 /* convert_this this(r)
3390 Takes the value in the 'this' register, converts it to a
3391 value that is suitable for use as the 'this' value, and
3392 stores it in the 'this' register. This opcode is emitted
3393 to avoid doing the conversion in the caller unnecessarily.
3395 This opcode should only be used at the beginning of a code
3399 int thisRegister
= vPC
[1].u
.operand
;
3400 JSValue thisVal
= callFrame
->r(thisRegister
).jsValue();
3401 if (thisVal
.needsThisConversion())
3402 callFrame
->r(thisRegister
) = JSValue(thisVal
.toThisObject(callFrame
));
3404 vPC
+= OPCODE_LENGTH(op_convert_this
);
3407 DEFINE_OPCODE(op_init_arguments
) {
3410 Initialises the arguments object reference to null to ensure
3411 we can correctly detect that we need to create it later (or
3412 avoid creating it altogether).
3414 This opcode should only be used at the beginning of a code
3417 callFrame
->r(RegisterFile::ArgumentsRegister
) = JSValue();
3418 vPC
+= OPCODE_LENGTH(op_init_arguments
);
3421 DEFINE_OPCODE(op_create_arguments
) {
3424 Creates the 'arguments' object and places it in both the
3425 'arguments' call frame slot and the local 'arguments'
3426 register, if it has not already been initialised.
3429 if (!callFrame
->r(RegisterFile::ArgumentsRegister
).jsValue()) {
3430 Arguments
* arguments
= new (globalData
) Arguments(callFrame
);
3431 callFrame
->setCalleeArguments(arguments
);
3432 callFrame
->r(RegisterFile::ArgumentsRegister
) = JSValue(arguments
);
3434 vPC
+= OPCODE_LENGTH(op_create_arguments
);
3437 DEFINE_OPCODE(op_construct
) {
3438 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
3440 Invoke register "func" as a constructor. For JS
3441 functions, the calling convention is exactly as for the
3442 "call" opcode, except that the "this" value is a newly
3443 created Object. For native constructors, no "this"
3444 value is passed. In either case, the argCount and registerOffset
3445 registers are interpreted as for the "call" opcode.
3447 Register proto must contain the prototype property of
3448 register func. This is to enable polymorphic inline
3449 caching of this lookup.
3452 int dst
= vPC
[1].u
.operand
;
3453 int func
= vPC
[2].u
.operand
;
3454 int argCount
= vPC
[3].u
.operand
;
3455 int registerOffset
= vPC
[4].u
.operand
;
3456 int proto
= vPC
[5].u
.operand
;
3457 int thisRegister
= vPC
[6].u
.operand
;
3459 JSValue v
= callFrame
->r(func
).jsValue();
3461 ConstructData constructData
;
3462 ConstructType constructType
= v
.getConstructData(constructData
);
3464 if (constructType
== ConstructTypeJS
) {
3465 ScopeChainNode
* callDataScopeChain
= constructData
.js
.scopeChain
;
3466 CodeBlock
* newCodeBlock
= &constructData
.js
.functionExecutable
->bytecode(callFrame
, callDataScopeChain
);
3468 Structure
* structure
;
3469 JSValue prototype
= callFrame
->r(proto
).jsValue();
3470 if (prototype
.isObject())
3471 structure
= asObject(prototype
)->inheritorID();
3473 structure
= callDataScopeChain
->globalObject
->emptyObjectStructure();
3474 JSObject
* newObject
= new (globalData
) JSObject(structure
);
3476 callFrame
->r(thisRegister
) = JSValue(newObject
); // "this" value
3478 CallFrame
* previousCallFrame
= callFrame
;
3480 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
3481 if (UNLIKELY(!callFrame
)) {
3482 callFrame
= previousCallFrame
;
3483 exceptionValue
= createStackOverflowError(callFrame
);
3487 callFrame
->init(newCodeBlock
, vPC
+ 7, callDataScopeChain
, previousCallFrame
, dst
, argCount
, asFunction(v
));
3488 vPC
= newCodeBlock
->instructions().begin();
3490 #if ENABLE(OPCODE_STATS)
3491 OpcodeStats::resetLastInstruction();
3497 if (constructType
== ConstructTypeHost
) {
3498 ArgList
args(callFrame
->registers() + thisRegister
+ 1, argCount
- 1);
3500 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3501 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
3502 newCallFrame
->init(0, vPC
+ 7, scopeChain
, callFrame
, dst
, argCount
, 0);
3504 JSValue returnValue
;
3506 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
3507 returnValue
= constructData
.native
.function(newCallFrame
, asObject(v
), args
);
3509 CHECK_FOR_EXCEPTION();
3510 callFrame
->r(dst
) = JSValue(returnValue
);
3512 vPC
+= OPCODE_LENGTH(op_construct
);
3516 ASSERT(constructType
== ConstructTypeNone
);
3518 exceptionValue
= createNotAConstructorError(callFrame
, v
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3521 DEFINE_OPCODE(op_construct_verify
) {
3522 /* construct_verify dst(r) override(r)
3524 Verifies that register dst holds an object. If not, moves
3525 the object in register override to register dst.
3528 int dst
= vPC
[1].u
.operand
;
3529 if (LIKELY(callFrame
->r(dst
).jsValue().isObject())) {
3530 vPC
+= OPCODE_LENGTH(op_construct_verify
);
3534 int override
= vPC
[2].u
.operand
;
3535 callFrame
->r(dst
) = callFrame
->r(override
);
3537 vPC
+= OPCODE_LENGTH(op_construct_verify
);
3540 DEFINE_OPCODE(op_strcat
) {
3541 int dst
= vPC
[1].u
.operand
;
3542 int src
= vPC
[2].u
.operand
;
3543 int count
= vPC
[3].u
.operand
;
3545 callFrame
->r(dst
) = jsString(callFrame
, &callFrame
->registers()[src
], count
);
3546 CHECK_FOR_EXCEPTION();
3547 vPC
+= OPCODE_LENGTH(op_strcat
);
3551 DEFINE_OPCODE(op_to_primitive
) {
3552 int dst
= vPC
[1].u
.operand
;
3553 int src
= vPC
[2].u
.operand
;
3555 callFrame
->r(dst
) = callFrame
->r(src
).jsValue().toPrimitive(callFrame
);
3556 vPC
+= OPCODE_LENGTH(op_to_primitive
);
3560 DEFINE_OPCODE(op_push_scope
) {
3561 /* push_scope scope(r)
3563 Converts register scope to object, and pushes it onto the top
3564 of the current scope chain. The contents of the register scope
3565 are replaced by the result of toObject conversion of the scope.
3567 int scope
= vPC
[1].u
.operand
;
3568 JSValue v
= callFrame
->r(scope
).jsValue();
3569 JSObject
* o
= v
.toObject(callFrame
);
3570 CHECK_FOR_EXCEPTION();
3572 callFrame
->r(scope
) = JSValue(o
);
3573 callFrame
->setScopeChain(callFrame
->scopeChain()->push(o
));
3575 vPC
+= OPCODE_LENGTH(op_push_scope
);
3578 DEFINE_OPCODE(op_pop_scope
) {
3581 Removes the top item from the current scope chain.
3583 callFrame
->setScopeChain(callFrame
->scopeChain()->pop());
3585 vPC
+= OPCODE_LENGTH(op_pop_scope
);
3588 DEFINE_OPCODE(op_get_pnames
) {
3589 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
3591 Creates a property name list for register base and puts it
3592 in register dst, initializing i and size for iteration. If
3593 base is undefined or null, jumps to breakTarget.
3595 int dst
= vPC
[1].u
.operand
;
3596 int base
= vPC
[2].u
.operand
;
3597 int i
= vPC
[3].u
.operand
;
3598 int size
= vPC
[4].u
.operand
;
3599 int breakTarget
= vPC
[5].u
.operand
;
3601 JSValue v
= callFrame
->r(base
).jsValue();
3602 if (v
.isUndefinedOrNull()) {
3607 JSObject
* o
= v
.toObject(callFrame
);
3608 Structure
* structure
= o
->structure();
3609 JSPropertyNameIterator
* jsPropertyNameIterator
= structure
->enumerationCache();
3610 if (!jsPropertyNameIterator
|| jsPropertyNameIterator
->cachedPrototypeChain() != structure
->prototypeChain(callFrame
))
3611 jsPropertyNameIterator
= JSPropertyNameIterator::create(callFrame
, o
);
3613 callFrame
->r(dst
) = jsPropertyNameIterator
;
3614 callFrame
->r(base
) = JSValue(o
);
3615 callFrame
->r(i
) = Register::withInt(0);
3616 callFrame
->r(size
) = Register::withInt(jsPropertyNameIterator
->size());
3617 vPC
+= OPCODE_LENGTH(op_get_pnames
);
3620 DEFINE_OPCODE(op_next_pname
) {
3621 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
3623 Copies the next name from the property name list in
3624 register iter to dst, then jumps to offset target. If there are no
3625 names left, invalidates the iterator and continues to the next
3628 int dst
= vPC
[1].u
.operand
;
3629 int base
= vPC
[2].u
.operand
;
3630 int i
= vPC
[3].u
.operand
;
3631 int size
= vPC
[4].u
.operand
;
3632 int iter
= vPC
[5].u
.operand
;
3633 int target
= vPC
[6].u
.operand
;
3635 JSPropertyNameIterator
* it
= callFrame
->r(iter
).propertyNameIterator();
3636 while (callFrame
->r(i
).i() != callFrame
->r(size
).i()) {
3637 JSValue key
= it
->get(callFrame
, asObject(callFrame
->r(base
).jsValue()), callFrame
->r(i
).i());
3638 callFrame
->r(i
) = Register::withInt(callFrame
->r(i
).i() + 1);
3640 CHECK_FOR_TIMEOUT();
3641 callFrame
->r(dst
) = key
;
3647 vPC
+= OPCODE_LENGTH(op_next_pname
);
3650 DEFINE_OPCODE(op_jmp_scopes
) {
3651 /* jmp_scopes count(n) target(offset)
3653 Removes the a number of items from the current scope chain
3654 specified by immediate number count, then jumps to offset
3657 int count
= vPC
[1].u
.operand
;
3658 int target
= vPC
[2].u
.operand
;
3660 ScopeChainNode
* tmp
= callFrame
->scopeChain();
3663 callFrame
->setScopeChain(tmp
);
3668 #if HAVE(COMPUTED_GOTO)
3670 goto *(&&skip_new_scope
);
3672 DEFINE_OPCODE(op_push_new_scope
) {
3673 /* new_scope dst(r) property(id) value(r)
3675 Constructs a new StaticScopeObject with property set to value. That scope
3676 object is then pushed onto the ScopeChain. The scope object is then stored
3679 callFrame
->setScopeChain(createExceptionScope(callFrame
, vPC
));
3681 vPC
+= OPCODE_LENGTH(op_push_new_scope
);
3684 #if HAVE(COMPUTED_GOTO)
3687 DEFINE_OPCODE(op_catch
) {
3690 Retrieves the VM's current exception and puts it in register
3691 ex. This is only valid after an exception has been raised,
3692 and usually forms the beginning of an exception handler.
3694 ASSERT(exceptionValue
);
3695 ASSERT(!globalData
->exception
);
3696 int ex
= vPC
[1].u
.operand
;
3697 callFrame
->r(ex
) = exceptionValue
;
3698 exceptionValue
= JSValue();
3700 vPC
+= OPCODE_LENGTH(op_catch
);
3703 DEFINE_OPCODE(op_throw
) {
3706 Throws register ex as an exception. This involves three
3707 steps: first, it is set as the current exception in the
3708 VM's internal state, then the stack is unwound until an
3709 exception handler or a native code boundary is found, and
3710 then control resumes at the exception handler if any or
3711 else the script returns control to the nearest native caller.
3714 int ex
= vPC
[1].u
.operand
;
3715 exceptionValue
= callFrame
->r(ex
).jsValue();
3717 handler
= throwException(callFrame
, exceptionValue
, vPC
- callFrame
->codeBlock()->instructions().begin(), true);
3719 *exception
= exceptionValue
;
3723 vPC
= callFrame
->codeBlock()->instructions().begin() + handler
->target
;
3726 DEFINE_OPCODE(op_new_error
) {
3727 /* new_error dst(r) type(n) message(k)
3729 Constructs a new Error instance using the original
3730 constructor, using immediate number n as the type and
3731 constant message as the message string. The result is
3732 written to register dst.
3734 int dst
= vPC
[1].u
.operand
;
3735 int type
= vPC
[2].u
.operand
;
3736 int message
= vPC
[3].u
.operand
;
3738 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3739 callFrame
->r(dst
) = JSValue(Error::create(callFrame
, (ErrorType
)type
, callFrame
->r(message
).jsValue().toString(callFrame
), codeBlock
->lineNumberForBytecodeOffset(callFrame
, vPC
- codeBlock
->instructions().begin()), codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->sourceURL()));
3741 vPC
+= OPCODE_LENGTH(op_new_error
);
3744 DEFINE_OPCODE(op_end
) {
3747 Return register result as the value of a global or eval
3748 program. Return control to the calling native code.
3751 if (callFrame
->codeBlock()->needsFullScopeChain()) {
3752 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3753 ASSERT(scopeChain
->refCount
> 1);
3754 scopeChain
->deref();
3756 int result
= vPC
[1].u
.operand
;
3757 return callFrame
->r(result
).jsValue();
3759 DEFINE_OPCODE(op_put_getter
) {
3760 /* put_getter base(r) property(id) function(r)
3762 Sets register function on register base as the getter named
3763 by identifier property. Base and function are assumed to be
3764 objects as this op should only be used for getters defined
3765 in object literal form.
3767 Unlike many opcodes, this one does not write any output to
3770 int base
= vPC
[1].u
.operand
;
3771 int property
= vPC
[2].u
.operand
;
3772 int function
= vPC
[3].u
.operand
;
3774 ASSERT(callFrame
->r(base
).jsValue().isObject());
3775 JSObject
* baseObj
= asObject(callFrame
->r(base
).jsValue());
3776 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
3777 ASSERT(callFrame
->r(function
).jsValue().isObject());
3778 baseObj
->defineGetter(callFrame
, ident
, asObject(callFrame
->r(function
).jsValue()));
3780 vPC
+= OPCODE_LENGTH(op_put_getter
);
3783 DEFINE_OPCODE(op_put_setter
) {
3784 /* put_setter base(r) property(id) function(r)
3786 Sets register function on register base as the setter named
3787 by identifier property. Base and function are assumed to be
3788 objects as this op should only be used for setters defined
3789 in object literal form.
3791 Unlike many opcodes, this one does not write any output to
3794 int base
= vPC
[1].u
.operand
;
3795 int property
= vPC
[2].u
.operand
;
3796 int function
= vPC
[3].u
.operand
;
3798 ASSERT(callFrame
->r(base
).jsValue().isObject());
3799 JSObject
* baseObj
= asObject(callFrame
->r(base
).jsValue());
3800 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
3801 ASSERT(callFrame
->r(function
).jsValue().isObject());
3802 baseObj
->defineSetter(callFrame
, ident
, asObject(callFrame
->r(function
).jsValue()), 0);
3804 vPC
+= OPCODE_LENGTH(op_put_setter
);
3807 DEFINE_OPCODE(op_method_check
) {
3811 DEFINE_OPCODE(op_jsr
) {
3812 /* jsr retAddrDst(r) target(offset)
3814 Places the address of the next instruction into the retAddrDst
3815 register and jumps to offset target from the current instruction.
3817 int retAddrDst
= vPC
[1].u
.operand
;
3818 int target
= vPC
[2].u
.operand
;
3819 callFrame
->r(retAddrDst
) = vPC
+ OPCODE_LENGTH(op_jsr
);
3824 DEFINE_OPCODE(op_sret
) {
3825 /* sret retAddrSrc(r)
3827 Jumps to the address stored in the retAddrSrc register. This
3828 differs from op_jmp because the target address is stored in a
3829 register, not as an immediate.
3831 int retAddrSrc
= vPC
[1].u
.operand
;
3832 vPC
= callFrame
->r(retAddrSrc
).vPC();
3835 DEFINE_OPCODE(op_debug
) {
3836 /* debug debugHookID(n) firstLine(n) lastLine(n)
3838 Notifies the debugger of the current state of execution. This opcode
3839 is only generated while the debugger is attached.
3841 int debugHookID
= vPC
[1].u
.operand
;
3842 int firstLine
= vPC
[2].u
.operand
;
3843 int lastLine
= vPC
[3].u
.operand
;
3845 debug(callFrame
, static_cast<DebugHookID
>(debugHookID
), firstLine
, lastLine
);
3847 vPC
+= OPCODE_LENGTH(op_debug
);
3850 DEFINE_OPCODE(op_profile_will_call
) {
3851 /* op_profile_will_call function(r)
3853 Notifies the profiler of the beginning of a function call. This opcode
3854 is only generated if developer tools are enabled.
3856 int function
= vPC
[1].u
.operand
;
3858 if (*enabledProfilerReference
)
3859 (*enabledProfilerReference
)->willExecute(callFrame
, callFrame
->r(function
).jsValue());
3861 vPC
+= OPCODE_LENGTH(op_profile_will_call
);
3864 DEFINE_OPCODE(op_profile_did_call
) {
3865 /* op_profile_did_call function(r)
3867 Notifies the profiler of the end of a function call. This opcode
3868 is only generated if developer tools are enabled.
3870 int function
= vPC
[1].u
.operand
;
3872 if (*enabledProfilerReference
)
3873 (*enabledProfilerReference
)->didExecute(callFrame
, callFrame
->r(function
).jsValue());
3875 vPC
+= OPCODE_LENGTH(op_profile_did_call
);
3879 globalData
->exception
= JSValue();
3881 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3882 // cannot fathom if we don't assign to the exceptionValue before branching)
3883 exceptionValue
= createInterruptedExecutionException(globalData
);
3885 handler
= throwException(callFrame
, exceptionValue
, vPC
- callFrame
->codeBlock()->instructions().begin(), false);
3887 *exception
= exceptionValue
;
3891 vPC
= callFrame
->codeBlock()->instructions().begin() + handler
->target
;
3895 #if !HAVE(COMPUTED_GOTO)
3896 } // iterator loop ends
3898 #endif // USE(INTERPRETER)
3899 #undef NEXT_INSTRUCTION
3900 #undef DEFINE_OPCODE
3901 #undef CHECK_FOR_EXCEPTION
3902 #undef CHECK_FOR_TIMEOUT
3905 JSValue
Interpreter::retrieveArguments(CallFrame
* callFrame
, JSFunction
* function
) const
3907 CallFrame
* functionCallFrame
= findFunctionCallFrame(callFrame
, function
);
3908 if (!functionCallFrame
)
3911 CodeBlock
* codeBlock
= functionCallFrame
->codeBlock();
3912 if (codeBlock
->usesArguments()) {
3913 ASSERT(codeBlock
->codeType() == FunctionCode
);
3914 SymbolTable
& symbolTable
= *codeBlock
->symbolTable();
3915 int argumentsIndex
= symbolTable
.get(functionCallFrame
->propertyNames().arguments
.ustring().rep()).getIndex();
3916 if (!functionCallFrame
->r(argumentsIndex
).jsValue()) {
3917 Arguments
* arguments
= new (callFrame
) Arguments(functionCallFrame
);
3918 functionCallFrame
->setCalleeArguments(arguments
);
3919 functionCallFrame
->r(RegisterFile::ArgumentsRegister
) = JSValue(arguments
);
3921 return functionCallFrame
->r(argumentsIndex
).jsValue();
3924 Arguments
* arguments
= functionCallFrame
->optionalCalleeArguments();
3926 arguments
= new (functionCallFrame
) Arguments(functionCallFrame
);
3927 arguments
->copyRegisters();
3928 callFrame
->setCalleeArguments(arguments
);
3934 JSValue
Interpreter::retrieveCaller(CallFrame
* callFrame
, InternalFunction
* function
) const
3936 CallFrame
* functionCallFrame
= findFunctionCallFrame(callFrame
, function
);
3937 if (!functionCallFrame
)
3940 CallFrame
* callerFrame
= functionCallFrame
->callerFrame();
3941 if (callerFrame
->hasHostCallFrameFlag())
3944 JSValue caller
= callerFrame
->callee();
3951 void Interpreter::retrieveLastCaller(CallFrame
* callFrame
, int& lineNumber
, intptr_t& sourceID
, UString
& sourceURL
, JSValue
& function
) const
3953 function
= JSValue();
3955 sourceURL
= UString();
3957 CallFrame
* callerFrame
= callFrame
->callerFrame();
3958 if (callerFrame
->hasHostCallFrameFlag())
3961 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
3962 if (!callerCodeBlock
)
3965 unsigned bytecodeOffset
= bytecodeOffsetForPC(callerFrame
, callerCodeBlock
, callFrame
->returnPC());
3966 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(callerFrame
, bytecodeOffset
- 1);
3967 sourceID
= callerCodeBlock
->ownerExecutable()->sourceID();
3968 sourceURL
= callerCodeBlock
->ownerExecutable()->sourceURL();
3969 function
= callerFrame
->callee();
3972 CallFrame
* Interpreter::findFunctionCallFrame(CallFrame
* callFrame
, InternalFunction
* function
)
3974 for (CallFrame
* candidate
= callFrame
; candidate
; candidate
= candidate
->callerFrame()->removeHostCallFrameFlag()) {
3975 if (candidate
->callee() == function
)
3981 void Interpreter::enableSampler()
3983 #if ENABLE(OPCODE_SAMPLING)
3985 m_sampler
.set(new SamplingTool(this));
3990 void Interpreter::dumpSampleData(ExecState
* exec
)
3992 #if ENABLE(OPCODE_SAMPLING)
3994 m_sampler
->dump(exec
);
3999 void Interpreter::startSampling()
4001 #if ENABLE(SAMPLING_THREAD)
4002 if (!m_sampleEntryDepth
)
4003 SamplingThread::start();
4005 m_sampleEntryDepth
++;
4008 void Interpreter::stopSampling()
4010 #if ENABLE(SAMPLING_THREAD)
4011 m_sampleEntryDepth
--;
4012 if (!m_sampleEntryDepth
)
4013 SamplingThread::stop();