source: webkit/trunk/JavaScriptCore/interpreter/Interpreter.cpp@ 51735

Last change on this file since 51735 was 51735, checked in by [email protected], 15 years ago

2009-12-05 Maciej Stachowiak <[email protected]>

Reviewed by Oliver Hunt.

conway benchmark spends half it's time in op_less (jump fusion fails)
https://bugs.webkit.org/show_bug.cgi?id=32190

<1% speedup on SunSpider and V8
2x speedup on "conway" benchmark


Two optimizations:

1) Improve codegen for logical operators &&,
and ! in a condition context


When generating code for combinations of &&,
and !, in a

condition context (i.e. in an if statement or loop condition), we
used to produce a value, and then separately jump based on its
truthiness. Now we pass the false and true targets in, and let the
logical operators generate jumps directly. This helps in four
ways:

a) Individual clauses of a short-circuit logical operator can now
jump directly to the then or else clause of an if statement (or to
the top or exit of a loop) instead of jumping to a jump.


b) It used to be that jump fusion with the condition of the first
clause of a logical operator was inhibited, because the register
was ref'd to be used later, in the actual condition jump; this no
longer happens since a jump straight to the final target is
generated directly.

c) It used to be that jump fusion with the condition of the second
clause of a logical operator was inhibited, because there was a
jump target right after the second clause and before the actual
condition jump. But now it's no longer necessary for the first
clause to jump there so jump fusion is not blocked.

d) We avoid generating excess mov statements in some cases.


As a concrete example this source:


if (!((x < q && y < q)
(t < q && z < q))) {

...

}


Used to generate this bytecode:


[ 34] less r1, r-15, r-19
[ 38] jfalse r1, 7(->45)
[ 41] less r1, r-16, r-19
[ 45] jtrue r1, 14(->59)
[ 48] less r1, r-17, r-19
[ 52] jfalse r1, 7(->59)
[ 55] less r1, r-18, r-19
[ 59] jtrue r1, 17(->76)


And now generates this bytecode (also taking advantage of the second optimization below):


[ 34] jnless r-15, r-19, 8(->42)
[ 38] jless r-16, r-19, 26(->64)
[ 42] jnless r-17, r-19, 8(->50)
[ 46] jless r-18, r-19, 18(->64)


Note the jump fusion and the fact that there's less jump
indirection - three of the four jumps go straight to the target
clause instead of indirecting through another jump.


2) Implement jless opcode to take advantage of the above, since we'll now often generate
a less followed by a jtrue where fusion is not forbidden.


  • parser/Nodes.h: (JSC::ExpressionNode::hasConditionContextCodegen): Helper function to determine whether a node supports special conditional codegen. Return false as this is the default. (JSC::ExpressionNode::emitBytecodeInConditionContext): Assert not reached - only really defined for nodes that do have conditional codegen. (JSC::UnaryOpNode::expr): Add const version. (JSC::LogicalNotNode::hasConditionContextCodegen): Returne true only if subexpression supports it. (JSC::LogicalOpNode::hasConditionContextCodegen): Return true.
  • parser/Nodes.cpp: (JSC::LogicalNotNode::emitBytecodeInConditionContext): Implemented - just swap the true and false targets for the child node. (JSC::LogicalOpNode::emitBytecodeInConditionContext): Implemented - handle jumps directly, improving codegen quality. Also handles further nested conditional codegen. (JSC::ConditionalNode::emitBytecode): Use condition context codegen when available. (JSC::IfNode::emitBytecode): ditto (JSC::IfElseNode::emitBytecode): ditto (JSC::DoWhileNode::emitBytecode): ditto (JSC::WhileNode::emitBytecode): ditto (JSC::ForNode::emitBytecode): ditto
  • bytecode/Opcode.h:
  • Added loop_if_false opcode - needed now that falsey jumps can be backwards.
  • Added jless opcode to take advantage of new fusion opportunities.
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): Handle above.
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitJumpIfTrue): Add peephole for less + jtrue ==> jless. (JSC::BytecodeGenerator::emitJumpIfFalse): Add handling of backwrds falsey jumps.
  • bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::emitNodeInConditionContext): Wrapper to handle tracking of overly deep expressions etc.
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute): Implement the two new opcodes (loop_if_false, jless).
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): Implement JIT support for the two new opcodes. (JSC::JIT::privateCompileSlowCases): ditto
  • jit/JIT.h:
  • jit/JITArithmetic.cpp: (JSC::JIT::emit_op_jless): (JSC::JIT::emitSlow_op_jless): ditto (JSC::JIT::emitBinaryDoubleOp): ditto
  • jit/JITOpcodes.cpp: (JSC::JIT::emitSlow_op_loop_if_less): ditto (JSC::JIT::emit_op_loop_if_false): ditto (JSC::JIT::emitSlow_op_loop_if_false): ditto
  • jit/JITStubs.cpp:
  • jit/JITStubs.h: (JSC::):

2009-12-05 Maciej Stachowiak <[email protected]>

Reviewed by Oliver Hunt.

conway benchmark spends half it's time in op_less (jump fusion fails)
https://bugs.webkit.org/show_bug.cgi?id=32190

  • fast/js/codegen-loops-logical-nodes-expected.txt:
  • fast/js/script-tests/codegen-loops-logical-nodes.js: Update to test some newly sensitive cases of codegen that were not already covered.
File size: 151.7 KB
Line 
1/*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
17 *
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.
28 */
29
30#include "config.h"
31#include "Interpreter.h"
32
33#include "Arguments.h"
34#include "BatchedTransitionOptimizer.h"
35#include "CallFrame.h"
36#include "CallFrameClosure.h"
37#include "CodeBlock.h"
38#include "Collector.h"
39#include "Debugger.h"
40#include "DebuggerCallFrame.h"
41#include "EvalCodeCache.h"
42#include "ExceptionHelpers.h"
43#include "GlobalEvalFunction.h"
44#include "JSActivation.h"
45#include "JSArray.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"
52#include "JSString.h"
53#include "ObjectPrototype.h"
54#include "Operations.h"
55#include "Parser.h"
56#include "Profiler.h"
57#include "RegExpObject.h"
58#include "RegExpPrototype.h"
59#include "Register.h"
60#include "SamplingTool.h"
61#include <limits.h>
62#include <stdio.h>
63#include <wtf/Threading.h>
64
65#if ENABLE(JIT)
66#include "JIT.h"
67#endif
68
69using namespace std;
70
71namespace JSC {
72
73static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, void* pc)
74{
75#if ENABLE(JIT)
76 return codeBlock->getBytecodeIndex(callFrame, ReturnAddressPtr(pc));
77#else
78 UNUSED_PARAM(callFrame);
79 return static_cast<Instruction*>(pc) - codeBlock->instructions().begin();
80#endif
81}
82
83// Returns the depth of the scope chain within a given call frame.
84static int depth(CodeBlock* codeBlock, ScopeChain& sc)
85{
86 if (!codeBlock->needsFullScopeChain())
87 return 0;
88 return sc.localDepth();
89}
90
91#if USE(INTERPRETER)
92NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
93{
94 int dst = vPC[1].u.operand;
95 int property = vPC[2].u.operand;
96
97 ScopeChainNode* scopeChain = callFrame->scopeChain();
98 ScopeChainIterator iter = scopeChain->begin();
99 ScopeChainIterator end = scopeChain->end();
100 ASSERT(iter != end);
101
102 CodeBlock* codeBlock = callFrame->codeBlock();
103 Identifier& ident = codeBlock->identifier(property);
104 do {
105 JSObject* o = *iter;
106 PropertySlot slot(o);
107 if (o->getPropertySlot(callFrame, ident, slot)) {
108 JSValue result = slot.getValue(callFrame, ident);
109 exceptionValue = callFrame->globalData().exception;
110 if (exceptionValue)
111 return false;
112 callFrame->r(dst) = JSValue(result);
113 return true;
114 }
115 } while (++iter != end);
116 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
117 return false;
118}
119
120NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
121{
122 CodeBlock* codeBlock = callFrame->codeBlock();
123
124 int dst = vPC[1].u.operand;
125 int property = vPC[2].u.operand;
126 int skip = vPC[3].u.operand + codeBlock->needsFullScopeChain();
127
128 ScopeChainNode* scopeChain = callFrame->scopeChain();
129 ScopeChainIterator iter = scopeChain->begin();
130 ScopeChainIterator end = scopeChain->end();
131 ASSERT(iter != end);
132 while (skip--) {
133 ++iter;
134 ASSERT(iter != end);
135 }
136 Identifier& ident = codeBlock->identifier(property);
137 do {
138 JSObject* o = *iter;
139 PropertySlot slot(o);
140 if (o->getPropertySlot(callFrame, ident, slot)) {
141 JSValue result = slot.getValue(callFrame, ident);
142 exceptionValue = callFrame->globalData().exception;
143 if (exceptionValue)
144 return false;
145 callFrame->r(dst) = JSValue(result);
146 return true;
147 }
148 } while (++iter != end);
149 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
150 return false;
151}
152
153NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
154{
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;
161
162 if (structure == globalObject->structure()) {
163 callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset));
164 return true;
165 }
166
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);
179 return true;
180 }
181
182 exceptionValue = callFrame->globalData().exception;
183 if (exceptionValue)
184 return false;
185 callFrame->r(dst) = JSValue(result);
186 return true;
187 }
188
189 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
190 return false;
191}
192
193NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
194{
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()));
198}
199
200NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
201{
202 int baseDst = vPC[1].u.operand;
203 int propDst = vPC[2].u.operand;
204 int property = vPC[3].u.operand;
205
206 ScopeChainNode* scopeChain = callFrame->scopeChain();
207 ScopeChainIterator iter = scopeChain->begin();
208 ScopeChainIterator end = scopeChain->end();
209
210 // FIXME: add scopeDepthIsZero optimization
211
212 ASSERT(iter != end);
213
214 CodeBlock* codeBlock = callFrame->codeBlock();
215 Identifier& ident = codeBlock->identifier(property);
216 JSObject* base;
217 do {
218 base = *iter;
219 PropertySlot slot(base);
220 if (base->getPropertySlot(callFrame, ident, slot)) {
221 JSValue result = slot.getValue(callFrame, ident);
222 exceptionValue = callFrame->globalData().exception;
223 if (exceptionValue)
224 return false;
225 callFrame->r(propDst) = JSValue(result);
226 callFrame->r(baseDst) = JSValue(base);
227 return true;
228 }
229 ++iter;
230 } while (iter != end);
231
232 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
233 return false;
234}
235
236#endif // USE(INTERPRETER)
237
238ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
239{
240 Register* r = callFrame->registers();
241 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters;
242
243 if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments
244 if (UNLIKELY(!registerFile->grow(newEnd)))
245 return 0;
246 r += registerOffset;
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))
252 return 0;
253 r += registerOffset;
254
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;
262
263 if (!registerFile->grow(newEnd))
264 return 0;
265 r += registerOffset;
266
267 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
268 for (size_t i = 0; i < numParameters; ++i)
269 argv[i + argc] = argv[i];
270 }
271
272 return CallFrame::create(r);
273}
274
275#if USE(INTERPRETER)
276static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
277{
278 if (value.isObject())
279 return false;
280 exceptionData = createInvalidParamError(callFrame, "in" , value, vPC - codeBlock->instructions().begin(), codeBlock);
281 return true;
282}
283
284static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
285{
286 if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
287 return false;
288 exceptionData = createInvalidParamError(callFrame, "instanceof" , value, vPC - codeBlock->instructions().begin(), codeBlock);
289 return true;
290}
291#endif
292
293NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue& exceptionValue)
294{
295 if (argc < 2)
296 return jsUndefined();
297
298 JSValue program = argv[1].jsValue();
299
300 if (!program.isString())
301 return program;
302
303 UString programSource = asString(program)->value();
304
305 LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
306 if (JSValue parsedObject = preparser.tryLiteralParse())
307 return parsedObject;
308
309 ScopeChainNode* scopeChain = callFrame->scopeChain();
310 CodeBlock* codeBlock = callFrame->codeBlock();
311 RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue);
312
313 JSValue result = jsUndefined();
314 if (eval)
315 result = callFrame->globalData().interpreter->execute(eval.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue);
316
317 return result;
318}
319
320Interpreter::Interpreter()
321 : m_sampleEntryDepth(0)
322 , m_reentryDepth(0)
323{
324 privateExecute(InitializeAndReturn, 0, 0, 0);
325#if ENABLE(OPCODE_SAMPLING)
326 enableSampler();
327#endif
328}
329
330#ifndef NDEBUG
331
332void Interpreter::dumpCallFrame(CallFrame* callFrame)
333{
334 callFrame->codeBlock()->dump(callFrame);
335 dumpRegisters(callFrame);
336}
337
338void Interpreter::dumpRegisters(CallFrame* callFrame)
339{
340 printf("Register frame: \n\n");
341 printf("-----------------------------------------------------------------------------\n");
342 printf(" use | address | value \n");
343 printf("-----------------------------------------------------------------------------\n");
344
345 CodeBlock* codeBlock = callFrame->codeBlock();
346 RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData()->interpreter->registerFile();
347 const Register* it;
348 const Register* end;
349 JSValue v;
350
351 if (codeBlock->codeType() == GlobalCode) {
352 it = registerFile->lastGlobal();
353 end = it + registerFile->numGlobals();
354 while (it != end) {
355 v = (*it).jsValue();
356#if USE(JSVALUE32_64)
357 printf("[global var] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
358#else
359 printf("[global var] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
360#endif
361 ++it;
362 }
363 printf("-----------------------------------------------------------------------------\n");
364 }
365
366 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters;
367 v = (*it).jsValue();
368#if USE(JSVALUE32_64)
369 printf("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it;
370#else
371 printf("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it;
372#endif
373 end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this"
374 if (it != end) {
375 do {
376 v = (*it).jsValue();
377#if USE(JSVALUE32_64)
378 printf("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
379#else
380 printf("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
381#endif
382 ++it;
383 } while (it != end);
384 }
385 printf("-----------------------------------------------------------------------------\n");
386 printf("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it;
387 printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
388 printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
389 printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
390 printf("[ReturnValueRegister] | %10p | %d \n", it, (*it).i()); ++it;
391 printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
392 printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it;
393 printf("[OptionalCalleeArguments] | %10p | %p \n", it, (*it).arguments()); ++it;
394 printf("-----------------------------------------------------------------------------\n");
395
396 int registerCount = 0;
397
398 end = it + codeBlock->m_numVars;
399 if (it != end) {
400 do {
401 v = (*it).jsValue();
402#if USE(JSVALUE32_64)
403 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
404#else
405 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
406#endif
407 ++it;
408 ++registerCount;
409 } while (it != end);
410 }
411 printf("-----------------------------------------------------------------------------\n");
412
413 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
414 if (it != end) {
415 do {
416 v = (*it).jsValue();
417#if USE(JSVALUE32_64)
418 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
419#else
420 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
421#endif
422 ++it;
423 ++registerCount;
424 } while (it != end);
425 }
426 printf("-----------------------------------------------------------------------------\n");
427}
428
429#endif
430
431bool Interpreter::isOpcode(Opcode opcode)
432{
433#if HAVE(COMPUTED_GOTO)
434 return opcode != HashTraits<Opcode>::emptyValue()
435 && !HashTraits<Opcode>::isDeletedValue(opcode)
436 && m_opcodeIDTable.contains(opcode);
437#else
438 return opcode >= 0 && opcode <= op_end;
439#endif
440}
441
442NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
443{
444 CodeBlock* oldCodeBlock = codeBlock;
445 ScopeChainNode* scopeChain = callFrame->scopeChain();
446
447 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
448 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
449 if (callFrame->callee())
450 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
451 else
452 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
453 }
454
455 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
456 if (callFrame->callee())
457 profiler->didExecute(callFrame, callFrame->callee());
458 else
459 profiler->didExecute(callFrame, codeBlock->ownerExecutable()->sourceURL(), codeBlock->ownerExecutable()->lineNo());
460 }
461
462 // If this call frame created an activation or an 'arguments' object, tear it off.
463 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
464 while (!scopeChain->object->inherits(&JSActivation::info))
465 scopeChain = scopeChain->pop();
466 static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments());
467 } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) {
468 if (!arguments->isTornOff())
469 arguments->copyRegisters();
470 }
471
472 if (oldCodeBlock->needsFullScopeChain())
473 scopeChain->deref();
474
475 void* returnPC = callFrame->returnPC();
476 callFrame = callFrame->callerFrame();
477 if (callFrame->hasHostCallFrameFlag())
478 return false;
479
480 codeBlock = callFrame->codeBlock();
481 bytecodeOffset = bytecodeOffsetForPC(callFrame, codeBlock, returnPC);
482 return true;
483}
484
485NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset, bool explicitThrow)
486{
487 // Set up the exception object
488
489 CodeBlock* codeBlock = callFrame->codeBlock();
490 if (exceptionValue.isObject()) {
491 JSObject* exception = asObject(exceptionValue);
492 if (exception->isNotAnObjectErrorStub()) {
493 exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock);
494 exceptionValue = exception;
495 } else {
496 if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) &&
497 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) &&
498 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) &&
499 !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) &&
500 !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) &&
501 !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) {
502 if (explicitThrow) {
503 int startOffset = 0;
504 int endOffset = 0;
505 int divotPoint = 0;
506 int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset);
507 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete);
508
509 // We only hit this path for error messages and throw statements, which don't have a specific failure position
510 // So we just give the full range of the error/throw statement.
511 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete);
512 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete);
513 } else
514 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete);
515 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerExecutable()->sourceID()), ReadOnly | DontDelete);
516 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerExecutable()->sourceURL()), ReadOnly | DontDelete);
517 }
518
519 if (exception->isWatchdogException()) {
520 while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
521 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
522 }
523 return 0;
524 }
525 }
526 }
527
528 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
529 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
530 debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset));
531 }
532
533 // If we throw in the middle of a call instruction, we need to notify
534 // the profiler manually that the call instruction has returned, since
535 // we'll never reach the relevant op_profile_did_call.
536 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
537#if !ENABLE(JIT)
538 if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode))
539 profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 2].u.operand).jsValue());
540 else if (codeBlock->instructions().size() > (bytecodeOffset + 8) && codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct))
541 profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 10].u.operand).jsValue());
542#else
543 int functionRegisterIndex;
544 if (codeBlock->functionRegisterForBytecodeOffset(bytecodeOffset, functionRegisterIndex))
545 profiler->didExecute(callFrame, callFrame->r(functionRegisterIndex).jsValue());
546#endif
547 }
548
549 // Calculate an exception handler vPC, unwinding call frames as necessary.
550
551 HandlerInfo* handler = 0;
552 while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
553 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock))
554 return 0;
555 }
556
557 // Now unwind the scope chain within the exception handler's call frame.
558
559 ScopeChainNode* scopeChain = callFrame->scopeChain();
560 ScopeChain sc(scopeChain);
561 int scopeDelta = depth(codeBlock, sc) - handler->scopeDepth;
562 ASSERT(scopeDelta >= 0);
563 while (scopeDelta--)
564 scopeChain = scopeChain->pop();
565 callFrame->setScopeChain(scopeChain);
566
567 return handler;
568}
569
570JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception)
571{
572 ASSERT(!scopeChain->globalData->exception);
573
574 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
575 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
576 *exception = createStackOverflowError(callFrame);
577 return jsNull();
578 }
579 }
580
581 CodeBlock* codeBlock = &program->bytecode(callFrame, scopeChain);
582
583 Register* oldEnd = m_registerFile.end();
584 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
585 if (!m_registerFile.grow(newEnd)) {
586 *exception = createStackOverflowError(callFrame);
587 return jsNull();
588 }
589
590 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
591
592 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
593 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
594 globalObject->copyGlobalsTo(m_registerFile);
595
596 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
597 newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
598 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0);
599
600 if (codeBlock->needsFullScopeChain())
601 scopeChain->ref();
602
603 Profiler** profiler = Profiler::enabledProfilerReference();
604 if (*profiler)
605 (*profiler)->willExecute(newCallFrame, program->sourceURL(), program->lineNo());
606
607 JSValue result;
608 {
609 SamplingTool::CallRecord callRecord(m_sampler.get());
610
611 m_reentryDepth++;
612#if ENABLE(JIT)
613 result = program->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
614#else
615 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
616#endif
617 m_reentryDepth--;
618 }
619
620 if (*profiler)
621 (*profiler)->didExecute(callFrame, program->sourceURL(), program->lineNo());
622
623 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
624 lastGlobalObject->copyGlobalsTo(m_registerFile);
625
626 m_registerFile.shrink(oldEnd);
627
628 return result;
629}
630
631JSValue Interpreter::execute(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception)
632{
633 ASSERT(!scopeChain->globalData->exception);
634
635 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
636 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
637 *exception = createStackOverflowError(callFrame);
638 return jsNull();
639 }
640 }
641
642 Register* oldEnd = m_registerFile.end();
643 int argc = 1 + args.size(); // implicit "this" parameter
644
645 if (!m_registerFile.grow(oldEnd + argc)) {
646 *exception = createStackOverflowError(callFrame);
647 return jsNull();
648 }
649
650 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
651
652 CallFrame* newCallFrame = CallFrame::create(oldEnd);
653 size_t dst = 0;
654 newCallFrame->r(0) = JSValue(thisObj);
655 ArgList::const_iterator end = args.end();
656 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
657 newCallFrame->r(++dst) = *it;
658
659 CodeBlock* codeBlock = &functionExecutable->bytecode(callFrame, scopeChain);
660 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
661 if (UNLIKELY(!newCallFrame)) {
662 *exception = createStackOverflowError(callFrame);
663 m_registerFile.shrink(oldEnd);
664 return jsNull();
665 }
666 // a 0 codeBlock indicates a built-in caller
667 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
668
669 Profiler** profiler = Profiler::enabledProfilerReference();
670 if (*profiler)
671 (*profiler)->willExecute(callFrame, function);
672
673 JSValue result;
674 {
675 SamplingTool::CallRecord callRecord(m_sampler.get());
676
677 m_reentryDepth++;
678#if ENABLE(JIT)
679 result = functionExecutable->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
680#else
681 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
682#endif
683 m_reentryDepth--;
684 }
685
686 if (*profiler)
687 (*profiler)->didExecute(callFrame, function);
688
689 m_registerFile.shrink(oldEnd);
690 return result;
691}
692
693CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain, JSValue* exception)
694{
695 ASSERT(!scopeChain->globalData->exception);
696
697 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
698 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
699 *exception = createStackOverflowError(callFrame);
700 return CallFrameClosure();
701 }
702 }
703
704 Register* oldEnd = m_registerFile.end();
705 int argc = 1 + argCount; // implicit "this" parameter
706
707 if (!m_registerFile.grow(oldEnd + argc)) {
708 *exception = createStackOverflowError(callFrame);
709 return CallFrameClosure();
710 }
711
712 CallFrame* newCallFrame = CallFrame::create(oldEnd);
713 size_t dst = 0;
714 for (int i = 0; i < argc; ++i)
715 newCallFrame->r(++dst) = jsUndefined();
716
717 CodeBlock* codeBlock = &FunctionExecutable->bytecode(callFrame, scopeChain);
718 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
719 if (UNLIKELY(!newCallFrame)) {
720 *exception = createStackOverflowError(callFrame);
721 m_registerFile.shrink(oldEnd);
722 return CallFrameClosure();
723 }
724 // a 0 codeBlock indicates a built-in caller
725 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
726#if ENABLE(JIT)
727 FunctionExecutable->jitCode(newCallFrame, scopeChain);
728#endif
729
730 CallFrameClosure result = { callFrame, newCallFrame, function, FunctionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc };
731 return result;
732}
733
734JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception)
735{
736 closure.resetCallFrame();
737 Profiler** profiler = Profiler::enabledProfilerReference();
738 if (*profiler)
739 (*profiler)->willExecute(closure.oldCallFrame, closure.function);
740
741 JSValue result;
742 {
743 SamplingTool::CallRecord callRecord(m_sampler.get());
744
745 m_reentryDepth++;
746#if ENABLE(JIT)
747 result = closure.functionExecutable->generatedJITCode().execute(&m_registerFile, closure.newCallFrame, closure.globalData, exception);
748#else
749 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame, exception);
750#endif
751 m_reentryDepth--;
752 }
753
754 if (*profiler)
755 (*profiler)->didExecute(closure.oldCallFrame, closure.function);
756 return result;
757}
758
759void Interpreter::endRepeatCall(CallFrameClosure& closure)
760{
761 m_registerFile.shrink(closure.oldEnd);
762}
763
764JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception)
765{
766 return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->bytecode(callFrame, scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
767}
768
769JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue* exception)
770{
771 ASSERT(!scopeChain->globalData->exception);
772
773 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
774 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
775 *exception = createStackOverflowError(callFrame);
776 return jsNull();
777 }
778 }
779
780 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
781
782 EvalCodeBlock* codeBlock = &eval->bytecode(callFrame, scopeChain);
783
784 JSVariableObject* variableObject;
785 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
786 ASSERT(node);
787 if (node->object->isVariableObject()) {
788 variableObject = static_cast<JSVariableObject*>(node->object);
789 break;
790 }
791 }
792
793 { // Scope for BatchedTransitionOptimizer
794
795 BatchedTransitionOptimizer optimizer(variableObject);
796
797 unsigned numVariables = codeBlock->numVariables();
798 for (unsigned i = 0; i < numVariables; ++i) {
799 const Identifier& ident = codeBlock->variable(i);
800 if (!variableObject->hasProperty(callFrame, ident)) {
801 PutPropertySlot slot;
802 variableObject->put(callFrame, ident, jsUndefined(), slot);
803 }
804 }
805
806 int numFunctions = codeBlock->numberOfFunctionDecls();
807 for (int i = 0; i < numFunctions; ++i) {
808 FunctionExecutable* function = codeBlock->functionDecl(i);
809 PutPropertySlot slot;
810 variableObject->put(callFrame, function->name(), function->make(callFrame, scopeChain), slot);
811 }
812
813 }
814
815 Register* oldEnd = m_registerFile.end();
816 Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
817 if (!m_registerFile.grow(newEnd)) {
818 *exception = createStackOverflowError(callFrame);
819 return jsNull();
820 }
821
822 CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
823
824 // a 0 codeBlock indicates a built-in caller
825 newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
826 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0);
827
828 if (codeBlock->needsFullScopeChain())
829 scopeChain->ref();
830
831 Profiler** profiler = Profiler::enabledProfilerReference();
832 if (*profiler)
833 (*profiler)->willExecute(newCallFrame, eval->sourceURL(), eval->lineNo());
834
835 JSValue result;
836 {
837 SamplingTool::CallRecord callRecord(m_sampler.get());
838
839 m_reentryDepth++;
840#if ENABLE(JIT)
841 result = eval->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
842#else
843 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
844#endif
845 m_reentryDepth--;
846 }
847
848 if (*profiler)
849 (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
850
851 m_registerFile.shrink(oldEnd);
852 return result;
853}
854
855NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
856{
857 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
858 if (!debugger)
859 return;
860
861 switch (debugHookID) {
862 case DidEnterCallFrame:
863 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
864 return;
865 case WillLeaveCallFrame:
866 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
867 return;
868 case WillExecuteStatement:
869 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
870 return;
871 case WillExecuteProgram:
872 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
873 return;
874 case DidExecuteProgram:
875 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
876 return;
877 case DidReachBreakpoint:
878 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
879 return;
880 }
881}
882
883#if USE(INTERPRETER)
884NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
885{
886 int dst = vPC[1].u.operand;
887 CodeBlock* codeBlock = callFrame->codeBlock();
888 Identifier& property = codeBlock->identifier(vPC[2].u.operand);
889 JSValue value = callFrame->r(vPC[3].u.operand).jsValue();
890 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
891 callFrame->r(dst) = JSValue(scope);
892
893 return callFrame->scopeChain()->push(scope);
894}
895
896NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot)
897{
898 // Recursive invocation may already have specialized this instruction.
899 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
900 return;
901
902 if (!baseValue.isCell())
903 return;
904
905 // Uncacheable: give up.
906 if (!slot.isCacheable()) {
907 vPC[0] = getOpcode(op_put_by_id_generic);
908 return;
909 }
910
911 JSCell* baseCell = asCell(baseValue);
912 Structure* structure = baseCell->structure();
913
914 if (structure->isUncacheableDictionary()) {
915 vPC[0] = getOpcode(op_put_by_id_generic);
916 return;
917 }
918
919 // Cache miss: record Structure to compare against next time.
920 Structure* lastStructure = vPC[4].u.structure;
921 if (structure != lastStructure) {
922 // First miss: record Structure to compare against next time.
923 if (!lastStructure) {
924 vPC[4] = structure;
925 return;
926 }
927
928 // Second miss: give up.
929 vPC[0] = getOpcode(op_put_by_id_generic);
930 return;
931 }
932
933 // Cache hit: Specialize instruction and ref Structures.
934
935 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
936 if (baseCell != slot.base()) {
937 vPC[0] = getOpcode(op_put_by_id_generic);
938 return;
939 }
940
941 // Structure transition, cache transition info
942 if (slot.type() == PutPropertySlot::NewProperty) {
943 if (structure->isDictionary()) {
944 vPC[0] = getOpcode(op_put_by_id_generic);
945 return;
946 }
947
948 // put_by_id_transition checks the prototype chain for setters.
949 normalizePrototypeChain(callFrame, baseCell);
950
951 vPC[0] = getOpcode(op_put_by_id_transition);
952 vPC[4] = structure->previousID();
953 vPC[5] = structure;
954 vPC[6] = structure->prototypeChain(callFrame);
955 vPC[7] = slot.cachedOffset();
956 codeBlock->refStructures(vPC);
957 return;
958 }
959
960 vPC[0] = getOpcode(op_put_by_id_replace);
961 vPC[5] = slot.cachedOffset();
962 codeBlock->refStructures(vPC);
963}
964
965NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
966{
967 codeBlock->derefStructures(vPC);
968 vPC[0] = getOpcode(op_put_by_id);
969 vPC[4] = 0;
970}
971
972NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)
973{
974 // Recursive invocation may already have specialized this instruction.
975 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
976 return;
977
978 // FIXME: Cache property access for immediates.
979 if (!baseValue.isCell()) {
980 vPC[0] = getOpcode(op_get_by_id_generic);
981 return;
982 }
983
984 JSGlobalData* globalData = &callFrame->globalData();
985 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
986 vPC[0] = getOpcode(op_get_array_length);
987 return;
988 }
989
990 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
991 vPC[0] = getOpcode(op_get_string_length);
992 return;
993 }
994
995 // Uncacheable: give up.
996 if (!slot.isCacheable()) {
997 vPC[0] = getOpcode(op_get_by_id_generic);
998 return;
999 }
1000
1001 Structure* structure = asCell(baseValue)->structure();
1002
1003 if (structure->isUncacheableDictionary()) {
1004 vPC[0] = getOpcode(op_get_by_id_generic);
1005 return;
1006 }
1007
1008 // Cache miss
1009 Structure* lastStructure = vPC[4].u.structure;
1010 if (structure != lastStructure) {
1011 // First miss: record Structure to compare against next time.
1012 if (!lastStructure) {
1013 vPC[4] = structure;
1014 return;
1015 }
1016
1017 // Second miss: give up.
1018 vPC[0] = getOpcode(op_get_by_id_generic);
1019 return;
1020 }
1021
1022 // Cache hit: Specialize instruction and ref Structures.
1023
1024 if (slot.slotBase() == baseValue) {
1025 vPC[0] = getOpcode(op_get_by_id_self);
1026 vPC[5] = slot.cachedOffset();
1027
1028 codeBlock->refStructures(vPC);
1029 return;
1030 }
1031
1032 if (structure->isDictionary()) {
1033 vPC[0] = getOpcode(op_get_by_id_generic);
1034 return;
1035 }
1036
1037 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
1038 ASSERT(slot.slotBase().isObject());
1039
1040 JSObject* baseObject = asObject(slot.slotBase());
1041
1042 // Since we're accessing a prototype in a loop, it's a good bet that it
1043 // should not be treated as a dictionary.
1044 if (baseObject->structure()->isDictionary())
1045 baseObject->flattenDictionaryObject();
1046
1047 ASSERT(!baseObject->structure()->isUncacheableDictionary());
1048
1049 vPC[0] = getOpcode(op_get_by_id_proto);
1050 vPC[5] = baseObject->structure();
1051 vPC[6] = slot.cachedOffset();
1052
1053 codeBlock->refStructures(vPC);
1054 return;
1055 }
1056
1057 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase());
1058 if (!count) {
1059 vPC[0] = getOpcode(op_get_by_id_generic);
1060 return;
1061 }
1062
1063 vPC[0] = getOpcode(op_get_by_id_chain);
1064 vPC[4] = structure;
1065 vPC[5] = structure->prototypeChain(callFrame);
1066 vPC[6] = count;
1067 vPC[7] = slot.cachedOffset();
1068 codeBlock->refStructures(vPC);
1069}
1070
1071NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1072{
1073 codeBlock->derefStructures(vPC);
1074 vPC[0] = getOpcode(op_get_by_id);
1075 vPC[4] = 0;
1076}
1077
1078#endif // USE(INTERPRETER)
1079
1080JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValue* exception)
1081{
1082 // One-time initialization of our address tables. We have to put this code
1083 // here because our labels are only in scope inside this function.
1084 if (flag == InitializeAndReturn) {
1085 #if HAVE(COMPUTED_GOTO)
1086 #define ADD_BYTECODE(id, length) m_opcodeTable[id] = &&id;
1087 FOR_EACH_OPCODE_ID(ADD_BYTECODE);
1088 #undef ADD_BYTECODE
1089
1090 #define ADD_OPCODE_ID(id, length) m_opcodeIDTable.add(&&id, id);
1091 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1092 #undef ADD_OPCODE_ID
1093 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1094 #endif // HAVE(COMPUTED_GOTO)
1095 return JSValue();
1096 }
1097
1098#if ENABLE(JIT)
1099 // Mixing Interpreter + JIT is not supported.
1100 ASSERT_NOT_REACHED();
1101#endif
1102#if !USE(INTERPRETER)
1103 UNUSED_PARAM(registerFile);
1104 UNUSED_PARAM(callFrame);
1105 UNUSED_PARAM(exception);
1106 return JSValue();
1107#else
1108
1109 JSGlobalData* globalData = &callFrame->globalData();
1110 JSValue exceptionValue;
1111 HandlerInfo* handler = 0;
1112
1113 Instruction* vPC = callFrame->codeBlock()->instructions().begin();
1114 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1115 unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();
1116
1117#define CHECK_FOR_EXCEPTION() \
1118 do { \
1119 if (UNLIKELY(globalData->exception != JSValue())) { \
1120 exceptionValue = globalData->exception; \
1121 goto vm_throw; \
1122 } \
1123 } while (0)
1124
1125#if ENABLE(OPCODE_STATS)
1126 OpcodeStats::resetLastInstruction();
1127#endif
1128
1129#define CHECK_FOR_TIMEOUT() \
1130 if (!--tickCount) { \
1131 if (globalData->timeoutChecker.didTimeOut(callFrame)) { \
1132 exceptionValue = jsNull(); \
1133 goto vm_throw; \
1134 } \
1135 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1136 }
1137
1138#if ENABLE(OPCODE_SAMPLING)
1139 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1140#else
1141 #define SAMPLE(codeBlock, vPC)
1142#endif
1143
1144#if HAVE(COMPUTED_GOTO)
1145 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
1146#if ENABLE(OPCODE_STATS)
1147 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1148#else
1149 #define DEFINE_OPCODE(opcode) opcode:
1150#endif
1151 NEXT_INSTRUCTION();
1152#else
1153 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
1154#if ENABLE(OPCODE_STATS)
1155 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1156#else
1157 #define DEFINE_OPCODE(opcode) case opcode:
1158#endif
1159 while (1) { // iterator loop begins
1160 interpreterLoopStart:;
1161 switch (vPC->u.opcode)
1162#endif
1163 {
1164 DEFINE_OPCODE(op_new_object) {
1165 /* new_object dst(r)
1166
1167 Constructs a new empty Object instance using the original
1168 constructor, and puts the result in register dst.
1169 */
1170 int dst = vPC[1].u.operand;
1171 callFrame->r(dst) = JSValue(constructEmptyObject(callFrame));
1172
1173 vPC += OPCODE_LENGTH(op_new_object);
1174 NEXT_INSTRUCTION();
1175 }
1176 DEFINE_OPCODE(op_new_array) {
1177 /* new_array dst(r) firstArg(r) argCount(n)
1178
1179 Constructs a new Array instance using the original
1180 constructor, and puts the result in register dst.
1181 The array will contain argCount elements with values
1182 taken from registers starting at register firstArg.
1183 */
1184 int dst = vPC[1].u.operand;
1185 int firstArg = vPC[2].u.operand;
1186 int argCount = vPC[3].u.operand;
1187 ArgList args(callFrame->registers() + firstArg, argCount);
1188 callFrame->r(dst) = JSValue(constructArray(callFrame, args));
1189
1190 vPC += OPCODE_LENGTH(op_new_array);
1191 NEXT_INSTRUCTION();
1192 }
1193 DEFINE_OPCODE(op_new_regexp) {
1194 /* new_regexp dst(r) regExp(re)
1195
1196 Constructs a new RegExp instance using the original
1197 constructor from regexp regExp, and puts the result in
1198 register dst.
1199 */
1200 int dst = vPC[1].u.operand;
1201 int regExp = vPC[2].u.operand;
1202 callFrame->r(dst) = JSValue(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject->regExpStructure(), callFrame->codeBlock()->regexp(regExp)));
1203
1204 vPC += OPCODE_LENGTH(op_new_regexp);
1205 NEXT_INSTRUCTION();
1206 }
1207 DEFINE_OPCODE(op_mov) {
1208 /* mov dst(r) src(r)
1209
1210 Copies register src to register dst.
1211 */
1212 int dst = vPC[1].u.operand;
1213 int src = vPC[2].u.operand;
1214 callFrame->r(dst) = callFrame->r(src);
1215
1216 vPC += OPCODE_LENGTH(op_mov);
1217 NEXT_INSTRUCTION();
1218 }
1219 DEFINE_OPCODE(op_eq) {
1220 /* eq dst(r) src1(r) src2(r)
1221
1222 Checks whether register src1 and register src2 are equal,
1223 as with the ECMAScript '==' operator, and puts the result
1224 as a boolean in register dst.
1225 */
1226 int dst = vPC[1].u.operand;
1227 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1228 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1229 if (src1.isInt32() && src2.isInt32())
1230 callFrame->r(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
1231 else {
1232 JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));
1233 CHECK_FOR_EXCEPTION();
1234 callFrame->r(dst) = result;
1235 }
1236
1237 vPC += OPCODE_LENGTH(op_eq);
1238 NEXT_INSTRUCTION();
1239 }
1240 DEFINE_OPCODE(op_eq_null) {
1241 /* eq_null dst(r) src(r)
1242
1243 Checks whether register src is null, as with the ECMAScript '!='
1244 operator, and puts the result as a boolean in register dst.
1245 */
1246 int dst = vPC[1].u.operand;
1247 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1248
1249 if (src.isUndefinedOrNull()) {
1250 callFrame->r(dst) = jsBoolean(true);
1251 vPC += OPCODE_LENGTH(op_eq_null);
1252 NEXT_INSTRUCTION();
1253 }
1254
1255 callFrame->r(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1256 vPC += OPCODE_LENGTH(op_eq_null);
1257 NEXT_INSTRUCTION();
1258 }
1259 DEFINE_OPCODE(op_neq) {
1260 /* neq dst(r) src1(r) src2(r)
1261
1262 Checks whether register src1 and register src2 are not
1263 equal, as with the ECMAScript '!=' operator, and puts the
1264 result as a boolean in register dst.
1265 */
1266 int dst = vPC[1].u.operand;
1267 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1268 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1269 if (src1.isInt32() && src2.isInt32())
1270 callFrame->r(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
1271 else {
1272 JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));
1273 CHECK_FOR_EXCEPTION();
1274 callFrame->r(dst) = result;
1275 }
1276
1277 vPC += OPCODE_LENGTH(op_neq);
1278 NEXT_INSTRUCTION();
1279 }
1280 DEFINE_OPCODE(op_neq_null) {
1281 /* neq_null dst(r) src(r)
1282
1283 Checks whether register src is not null, as with the ECMAScript '!='
1284 operator, and puts the result as a boolean in register dst.
1285 */
1286 int dst = vPC[1].u.operand;
1287 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1288
1289 if (src.isUndefinedOrNull()) {
1290 callFrame->r(dst) = jsBoolean(false);
1291 vPC += OPCODE_LENGTH(op_neq_null);
1292 NEXT_INSTRUCTION();
1293 }
1294
1295 callFrame->r(dst) = jsBoolean(!src.isCell() || !asCell(src)->structure()->typeInfo().masqueradesAsUndefined());
1296 vPC += OPCODE_LENGTH(op_neq_null);
1297 NEXT_INSTRUCTION();
1298 }
1299 DEFINE_OPCODE(op_stricteq) {
1300 /* stricteq dst(r) src1(r) src2(r)
1301
1302 Checks whether register src1 and register src2 are strictly
1303 equal, as with the ECMAScript '===' operator, and puts the
1304 result as a boolean in register dst.
1305 */
1306 int dst = vPC[1].u.operand;
1307 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1308 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1309 callFrame->r(dst) = jsBoolean(JSValue::strictEqual(src1, src2));
1310
1311 vPC += OPCODE_LENGTH(op_stricteq);
1312 NEXT_INSTRUCTION();
1313 }
1314 DEFINE_OPCODE(op_nstricteq) {
1315 /* nstricteq dst(r) src1(r) src2(r)
1316
1317 Checks whether register src1 and register src2 are not
1318 strictly equal, as with the ECMAScript '!==' operator, and
1319 puts the result as a boolean in register dst.
1320 */
1321 int dst = vPC[1].u.operand;
1322 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1323 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1324 callFrame->r(dst) = jsBoolean(!JSValue::strictEqual(src1, src2));
1325
1326 vPC += OPCODE_LENGTH(op_nstricteq);
1327 NEXT_INSTRUCTION();
1328 }
1329 DEFINE_OPCODE(op_less) {
1330 /* less dst(r) src1(r) src2(r)
1331
1332 Checks whether register src1 is less than register src2, as
1333 with the ECMAScript '<' operator, and puts the result as
1334 a boolean in register dst.
1335 */
1336 int dst = vPC[1].u.operand;
1337 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1338 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1339 JSValue result = jsBoolean(jsLess(callFrame, src1, src2));
1340 CHECK_FOR_EXCEPTION();
1341 callFrame->r(dst) = result;
1342
1343 vPC += OPCODE_LENGTH(op_less);
1344 NEXT_INSTRUCTION();
1345 }
1346 DEFINE_OPCODE(op_lesseq) {
1347 /* lesseq dst(r) src1(r) src2(r)
1348
1349 Checks whether register src1 is less than or equal to
1350 register src2, as with the ECMAScript '<=' operator, and
1351 puts the result as a boolean in register dst.
1352 */
1353 int dst = vPC[1].u.operand;
1354 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1355 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1356 JSValue result = jsBoolean(jsLessEq(callFrame, src1, src2));
1357 CHECK_FOR_EXCEPTION();
1358 callFrame->r(dst) = result;
1359
1360 vPC += OPCODE_LENGTH(op_lesseq);
1361 NEXT_INSTRUCTION();
1362 }
1363 DEFINE_OPCODE(op_pre_inc) {
1364 /* pre_inc srcDst(r)
1365
1366 Converts register srcDst to number, adds one, and puts the result
1367 back in register srcDst.
1368 */
1369 int srcDst = vPC[1].u.operand;
1370 JSValue v = callFrame->r(srcDst).jsValue();
1371 if (v.isInt32() && v.asInt32() < INT_MAX)
1372 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
1373 else {
1374 JSValue result = jsNumber(callFrame, v.toNumber(callFrame) + 1);
1375 CHECK_FOR_EXCEPTION();
1376 callFrame->r(srcDst) = result;
1377 }
1378
1379 vPC += OPCODE_LENGTH(op_pre_inc);
1380 NEXT_INSTRUCTION();
1381 }
1382 DEFINE_OPCODE(op_pre_dec) {
1383 /* pre_dec srcDst(r)
1384
1385 Converts register srcDst to number, subtracts one, and puts the result
1386 back in register srcDst.
1387 */
1388 int srcDst = vPC[1].u.operand;
1389 JSValue v = callFrame->r(srcDst).jsValue();
1390 if (v.isInt32() && v.asInt32() > INT_MIN)
1391 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
1392 else {
1393 JSValue result = jsNumber(callFrame, v.toNumber(callFrame) - 1);
1394 CHECK_FOR_EXCEPTION();
1395 callFrame->r(srcDst) = result;
1396 }
1397
1398 vPC += OPCODE_LENGTH(op_pre_dec);
1399 NEXT_INSTRUCTION();
1400 }
1401 DEFINE_OPCODE(op_post_inc) {
1402 /* post_inc dst(r) srcDst(r)
1403
1404 Converts register srcDst to number. The number itself is
1405 written to register dst, and the number plus one is written
1406 back to register srcDst.
1407 */
1408 int dst = vPC[1].u.operand;
1409 int srcDst = vPC[2].u.operand;
1410 JSValue v = callFrame->r(srcDst).jsValue();
1411 if (v.isInt32() && v.asInt32() < INT_MAX) {
1412 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
1413 callFrame->r(dst) = v;
1414 } else {
1415 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
1416 CHECK_FOR_EXCEPTION();
1417 callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() + 1);
1418 callFrame->r(dst) = number;
1419 }
1420
1421 vPC += OPCODE_LENGTH(op_post_inc);
1422 NEXT_INSTRUCTION();
1423 }
1424 DEFINE_OPCODE(op_post_dec) {
1425 /* post_dec dst(r) srcDst(r)
1426
1427 Converts register srcDst to number. The number itself is
1428 written to register dst, and the number minus one is written
1429 back to register srcDst.
1430 */
1431 int dst = vPC[1].u.operand;
1432 int srcDst = vPC[2].u.operand;
1433 JSValue v = callFrame->r(srcDst).jsValue();
1434 if (v.isInt32() && v.asInt32() > INT_MIN) {
1435 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
1436 callFrame->r(dst) = v;
1437 } else {
1438 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
1439 CHECK_FOR_EXCEPTION();
1440 callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() - 1);
1441 callFrame->r(dst) = number;
1442 }
1443
1444 vPC += OPCODE_LENGTH(op_post_dec);
1445 NEXT_INSTRUCTION();
1446 }
1447 DEFINE_OPCODE(op_to_jsnumber) {
1448 /* to_jsnumber dst(r) src(r)
1449
1450 Converts register src to number, and puts the result
1451 in register dst.
1452 */
1453 int dst = vPC[1].u.operand;
1454 int src = vPC[2].u.operand;
1455
1456 JSValue srcVal = callFrame->r(src).jsValue();
1457
1458 if (LIKELY(srcVal.isNumber()))
1459 callFrame->r(dst) = callFrame->r(src);
1460 else {
1461 JSValue result = srcVal.toJSNumber(callFrame);
1462 CHECK_FOR_EXCEPTION();
1463 callFrame->r(dst) = result;
1464 }
1465
1466 vPC += OPCODE_LENGTH(op_to_jsnumber);
1467 NEXT_INSTRUCTION();
1468 }
1469 DEFINE_OPCODE(op_negate) {
1470 /* negate dst(r) src(r)
1471
1472 Converts register src to number, negates it, and puts the
1473 result in register dst.
1474 */
1475 int dst = vPC[1].u.operand;
1476 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1477 if (src.isInt32() && src.asInt32())
1478 callFrame->r(dst) = jsNumber(callFrame, -src.asInt32());
1479 else {
1480 JSValue result = jsNumber(callFrame, -src.toNumber(callFrame));
1481 CHECK_FOR_EXCEPTION();
1482 callFrame->r(dst) = result;
1483 }
1484
1485 vPC += OPCODE_LENGTH(op_negate);
1486 NEXT_INSTRUCTION();
1487 }
1488 DEFINE_OPCODE(op_add) {
1489 /* add dst(r) src1(r) src2(r)
1490
1491 Adds register src1 and register src2, and puts the result
1492 in register dst. (JS add may be string concatenation or
1493 numeric add, depending on the types of the operands.)
1494 */
1495 int dst = vPC[1].u.operand;
1496 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1497 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1498 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
1499 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() + src2.asInt32());
1500 else {
1501 JSValue result = jsAdd(callFrame, src1, src2);
1502 CHECK_FOR_EXCEPTION();
1503 callFrame->r(dst) = result;
1504 }
1505 vPC += OPCODE_LENGTH(op_add);
1506 NEXT_INSTRUCTION();
1507 }
1508 DEFINE_OPCODE(op_mul) {
1509 /* mul dst(r) src1(r) src2(r)
1510
1511 Multiplies register src1 and register src2 (converted to
1512 numbers), and puts the product in register dst.
1513 */
1514 int dst = vPC[1].u.operand;
1515 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1516 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1517 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
1518 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() * src2.asInt32());
1519 else {
1520 JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) * src2.toNumber(callFrame));
1521 CHECK_FOR_EXCEPTION();
1522 callFrame->r(dst) = result;
1523 }
1524
1525 vPC += OPCODE_LENGTH(op_mul);
1526 NEXT_INSTRUCTION();
1527 }
1528 DEFINE_OPCODE(op_div) {
1529 /* div dst(r) dividend(r) divisor(r)
1530
1531 Divides register dividend (converted to number) by the
1532 register divisor (converted to number), and puts the
1533 quotient in register dst.
1534 */
1535 int dst = vPC[1].u.operand;
1536 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
1537 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
1538
1539 JSValue result = jsNumber(callFrame, dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
1540 CHECK_FOR_EXCEPTION();
1541 callFrame->r(dst) = result;
1542
1543 vPC += OPCODE_LENGTH(op_div);
1544 NEXT_INSTRUCTION();
1545 }
1546 DEFINE_OPCODE(op_mod) {
1547 /* mod dst(r) dividend(r) divisor(r)
1548
1549 Divides register dividend (converted to number) by
1550 register divisor (converted to number), and puts the
1551 remainder in register dst.
1552 */
1553 int dst = vPC[1].u.operand;
1554 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
1555 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
1556
1557 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
1558 JSValue result = jsNumber(callFrame, dividend.asInt32() % divisor.asInt32());
1559 ASSERT(result);
1560 callFrame->r(dst) = result;
1561 vPC += OPCODE_LENGTH(op_mod);
1562 NEXT_INSTRUCTION();
1563 }
1564
1565 // Conversion to double must happen outside the call to fmod since the
1566 // order of argument evaluation is not guaranteed.
1567 double d1 = dividend.toNumber(callFrame);
1568 double d2 = divisor.toNumber(callFrame);
1569 JSValue result = jsNumber(callFrame, fmod(d1, d2));
1570 CHECK_FOR_EXCEPTION();
1571 callFrame->r(dst) = result;
1572 vPC += OPCODE_LENGTH(op_mod);
1573 NEXT_INSTRUCTION();
1574 }
1575 DEFINE_OPCODE(op_sub) {
1576 /* sub dst(r) src1(r) src2(r)
1577
1578 Subtracts register src2 (converted to number) from register
1579 src1 (converted to number), and puts the difference in
1580 register dst.
1581 */
1582 int dst = vPC[1].u.operand;
1583 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1584 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1585 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
1586 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() - src2.asInt32());
1587 else {
1588 JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) - src2.toNumber(callFrame));
1589 CHECK_FOR_EXCEPTION();
1590 callFrame->r(dst) = result;
1591 }
1592 vPC += OPCODE_LENGTH(op_sub);
1593 NEXT_INSTRUCTION();
1594 }
1595 DEFINE_OPCODE(op_lshift) {
1596 /* lshift dst(r) val(r) shift(r)
1597
1598 Performs left shift of register val (converted to int32) by
1599 register shift (converted to uint32), and puts the result
1600 in register dst.
1601 */
1602 int dst = vPC[1].u.operand;
1603 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
1604 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
1605
1606 if (val.isInt32() && shift.isInt32())
1607 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() << (shift.asInt32() & 0x1f));
1608 else {
1609 JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
1610 CHECK_FOR_EXCEPTION();
1611 callFrame->r(dst) = result;
1612 }
1613
1614 vPC += OPCODE_LENGTH(op_lshift);
1615 NEXT_INSTRUCTION();
1616 }
1617 DEFINE_OPCODE(op_rshift) {
1618 /* rshift dst(r) val(r) shift(r)
1619
1620 Performs arithmetic right shift of register val (converted
1621 to int32) by register shift (converted to
1622 uint32), and puts the result in register dst.
1623 */
1624 int dst = vPC[1].u.operand;
1625 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
1626 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
1627
1628 if (val.isInt32() && shift.isInt32())
1629 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
1630 else {
1631 JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
1632 CHECK_FOR_EXCEPTION();
1633 callFrame->r(dst) = result;
1634 }
1635
1636 vPC += OPCODE_LENGTH(op_rshift);
1637 NEXT_INSTRUCTION();
1638 }
1639 DEFINE_OPCODE(op_urshift) {
1640 /* rshift dst(r) val(r) shift(r)
1641
1642 Performs logical right shift of register val (converted
1643 to uint32) by register shift (converted to
1644 uint32), and puts the result in register dst.
1645 */
1646 int dst = vPC[1].u.operand;
1647 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
1648 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
1649 if (val.isUInt32() && shift.isInt32())
1650 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
1651 else {
1652 JSValue result = jsNumber(callFrame, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
1653 CHECK_FOR_EXCEPTION();
1654 callFrame->r(dst) = result;
1655 }
1656
1657 vPC += OPCODE_LENGTH(op_urshift);
1658 NEXT_INSTRUCTION();
1659 }
1660 DEFINE_OPCODE(op_bitand) {
1661 /* bitand dst(r) src1(r) src2(r)
1662
1663 Computes bitwise AND of register src1 (converted to int32)
1664 and register src2 (converted to int32), and puts the result
1665 in register dst.
1666 */
1667 int dst = vPC[1].u.operand;
1668 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1669 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1670 if (src1.isInt32() && src2.isInt32())
1671 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() & src2.asInt32());
1672 else {
1673 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) & src2.toInt32(callFrame));
1674 CHECK_FOR_EXCEPTION();
1675 callFrame->r(dst) = result;
1676 }
1677
1678 vPC += OPCODE_LENGTH(op_bitand);
1679 NEXT_INSTRUCTION();
1680 }
1681 DEFINE_OPCODE(op_bitxor) {
1682 /* bitxor dst(r) src1(r) src2(r)
1683
1684 Computes bitwise XOR of register src1 (converted to int32)
1685 and register src2 (converted to int32), and puts the result
1686 in register dst.
1687 */
1688 int dst = vPC[1].u.operand;
1689 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1690 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1691 if (src1.isInt32() && src2.isInt32())
1692 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() ^ src2.asInt32());
1693 else {
1694 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
1695 CHECK_FOR_EXCEPTION();
1696 callFrame->r(dst) = result;
1697 }
1698
1699 vPC += OPCODE_LENGTH(op_bitxor);
1700 NEXT_INSTRUCTION();
1701 }
1702 DEFINE_OPCODE(op_bitor) {
1703 /* bitor dst(r) src1(r) src2(r)
1704
1705 Computes bitwise OR of register src1 (converted to int32)
1706 and register src2 (converted to int32), and puts the
1707 result in register dst.
1708 */
1709 int dst = vPC[1].u.operand;
1710 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1711 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1712 if (src1.isInt32() && src2.isInt32())
1713 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() | src2.asInt32());
1714 else {
1715 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) | src2.toInt32(callFrame));
1716 CHECK_FOR_EXCEPTION();
1717 callFrame->r(dst) = result;
1718 }
1719
1720 vPC += OPCODE_LENGTH(op_bitor);
1721 NEXT_INSTRUCTION();
1722 }
1723 DEFINE_OPCODE(op_bitnot) {
1724 /* bitnot dst(r) src(r)
1725
1726 Computes bitwise NOT of register src1 (converted to int32),
1727 and puts the result in register dst.
1728 */
1729 int dst = vPC[1].u.operand;
1730 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1731 if (src.isInt32())
1732 callFrame->r(dst) = jsNumber(callFrame, ~src.asInt32());
1733 else {
1734 JSValue result = jsNumber(callFrame, ~src.toInt32(callFrame));
1735 CHECK_FOR_EXCEPTION();
1736 callFrame->r(dst) = result;
1737 }
1738 vPC += OPCODE_LENGTH(op_bitnot);
1739 NEXT_INSTRUCTION();
1740 }
1741 DEFINE_OPCODE(op_not) {
1742 /* not dst(r) src(r)
1743
1744 Computes logical NOT of register src (converted to
1745 boolean), and puts the result in register dst.
1746 */
1747 int dst = vPC[1].u.operand;
1748 int src = vPC[2].u.operand;
1749 JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));
1750 CHECK_FOR_EXCEPTION();
1751 callFrame->r(dst) = result;
1752
1753 vPC += OPCODE_LENGTH(op_not);
1754 NEXT_INSTRUCTION();
1755 }
1756 DEFINE_OPCODE(op_instanceof) {
1757 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
1758
1759 Tests whether register value is an instance of register
1760 constructor, and puts the boolean result in register
1761 dst. Register constructorProto must contain the "prototype"
1762 property (not the actual prototype) of the object in
1763 register constructor. This lookup is separated so that
1764 polymorphic inline caching can apply.
1765
1766 Raises an exception if register constructor is not an
1767 object.
1768 */
1769 int dst = vPC[1].u.operand;
1770 int value = vPC[2].u.operand;
1771 int base = vPC[3].u.operand;
1772 int baseProto = vPC[4].u.operand;
1773
1774 JSValue baseVal = callFrame->r(base).jsValue();
1775
1776 if (isInvalidParamForInstanceOf(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
1777 goto vm_throw;
1778
1779 bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
1780 CHECK_FOR_EXCEPTION();
1781 callFrame->r(dst) = jsBoolean(result);
1782
1783 vPC += OPCODE_LENGTH(op_instanceof);
1784 NEXT_INSTRUCTION();
1785 }
1786 DEFINE_OPCODE(op_typeof) {
1787 /* typeof dst(r) src(r)
1788
1789 Determines the type string for src according to ECMAScript
1790 rules, and puts the result in register dst.
1791 */
1792 int dst = vPC[1].u.operand;
1793 int src = vPC[2].u.operand;
1794 callFrame->r(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
1795
1796 vPC += OPCODE_LENGTH(op_typeof);
1797 NEXT_INSTRUCTION();
1798 }
1799 DEFINE_OPCODE(op_is_undefined) {
1800 /* is_undefined dst(r) src(r)
1801
1802 Determines whether the type string for src according to
1803 the ECMAScript rules is "undefined", and puts the result
1804 in register dst.
1805 */
1806 int dst = vPC[1].u.operand;
1807 int src = vPC[2].u.operand;
1808 JSValue v = callFrame->r(src).jsValue();
1809 callFrame->r(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
1810
1811 vPC += OPCODE_LENGTH(op_is_undefined);
1812 NEXT_INSTRUCTION();
1813 }
1814 DEFINE_OPCODE(op_is_boolean) {
1815 /* is_boolean dst(r) src(r)
1816
1817 Determines whether the type string for src according to
1818 the ECMAScript rules is "boolean", and puts the result
1819 in register dst.
1820 */
1821 int dst = vPC[1].u.operand;
1822 int src = vPC[2].u.operand;
1823 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
1824
1825 vPC += OPCODE_LENGTH(op_is_boolean);
1826 NEXT_INSTRUCTION();
1827 }
1828 DEFINE_OPCODE(op_is_number) {
1829 /* is_number dst(r) src(r)
1830
1831 Determines whether the type string for src according to
1832 the ECMAScript rules is "number", and puts the result
1833 in register dst.
1834 */
1835 int dst = vPC[1].u.operand;
1836 int src = vPC[2].u.operand;
1837 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
1838
1839 vPC += OPCODE_LENGTH(op_is_number);
1840 NEXT_INSTRUCTION();
1841 }
1842 DEFINE_OPCODE(op_is_string) {
1843 /* is_string dst(r) src(r)
1844
1845 Determines whether the type string for src according to
1846 the ECMAScript rules is "string", and puts the result
1847 in register dst.
1848 */
1849 int dst = vPC[1].u.operand;
1850 int src = vPC[2].u.operand;
1851 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
1852
1853 vPC += OPCODE_LENGTH(op_is_string);
1854 NEXT_INSTRUCTION();
1855 }
1856 DEFINE_OPCODE(op_is_object) {
1857 /* is_object dst(r) src(r)
1858
1859 Determines whether the type string for src according to
1860 the ECMAScript rules is "object", and puts the result
1861 in register dst.
1862 */
1863 int dst = vPC[1].u.operand;
1864 int src = vPC[2].u.operand;
1865 callFrame->r(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
1866
1867 vPC += OPCODE_LENGTH(op_is_object);
1868 NEXT_INSTRUCTION();
1869 }
1870 DEFINE_OPCODE(op_is_function) {
1871 /* is_function dst(r) src(r)
1872
1873 Determines whether the type string for src according to
1874 the ECMAScript rules is "function", and puts the result
1875 in register dst.
1876 */
1877 int dst = vPC[1].u.operand;
1878 int src = vPC[2].u.operand;
1879 callFrame->r(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
1880
1881 vPC += OPCODE_LENGTH(op_is_function);
1882 NEXT_INSTRUCTION();
1883 }
1884 DEFINE_OPCODE(op_in) {
1885 /* in dst(r) property(r) base(r)
1886
1887 Tests whether register base has a property named register
1888 property, and puts the boolean result in register dst.
1889
1890 Raises an exception if register constructor is not an
1891 object.
1892 */
1893 int dst = vPC[1].u.operand;
1894 int property = vPC[2].u.operand;
1895 int base = vPC[3].u.operand;
1896
1897 JSValue baseVal = callFrame->r(base).jsValue();
1898 if (isInvalidParamForIn(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
1899 goto vm_throw;
1900
1901 JSObject* baseObj = asObject(baseVal);
1902
1903 JSValue propName = callFrame->r(property).jsValue();
1904
1905 uint32_t i;
1906 if (propName.getUInt32(i))
1907 callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
1908 else {
1909 Identifier property(callFrame, propName.toString(callFrame));
1910 CHECK_FOR_EXCEPTION();
1911 callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
1912 }
1913
1914 vPC += OPCODE_LENGTH(op_in);
1915 NEXT_INSTRUCTION();
1916 }
1917 DEFINE_OPCODE(op_resolve) {
1918 /* resolve dst(r) property(id)
1919
1920 Looks up the property named by identifier property in the
1921 scope chain, and writes the resulting value to register
1922 dst. If the property is not found, raises an exception.
1923 */
1924 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
1925 goto vm_throw;
1926
1927 vPC += OPCODE_LENGTH(op_resolve);
1928 NEXT_INSTRUCTION();
1929 }
1930 DEFINE_OPCODE(op_resolve_skip) {
1931 /* resolve_skip dst(r) property(id) skip(n)
1932
1933 Looks up the property named by identifier property in the
1934 scope chain skipping the top 'skip' levels, and writes the resulting
1935 value to register dst. If the property is not found, raises an exception.
1936 */
1937 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
1938 goto vm_throw;
1939
1940 vPC += OPCODE_LENGTH(op_resolve_skip);
1941
1942 NEXT_INSTRUCTION();
1943 }
1944 DEFINE_OPCODE(op_resolve_global) {
1945 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
1946
1947 Performs a dynamic property lookup for the given property, on the provided
1948 global object. If structure matches the Structure of the global then perform
1949 a fast lookup using the case offset, otherwise fall back to a full resolve and
1950 cache the new structure and offset
1951 */
1952 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
1953 goto vm_throw;
1954
1955 vPC += OPCODE_LENGTH(op_resolve_global);
1956
1957 NEXT_INSTRUCTION();
1958 }
1959 DEFINE_OPCODE(op_get_global_var) {
1960 /* get_global_var dst(r) globalObject(c) index(n)
1961
1962 Gets the global var at global slot index and places it in register dst.
1963 */
1964 int dst = vPC[1].u.operand;
1965 JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
1966 ASSERT(scope->isGlobalObject());
1967 int index = vPC[3].u.operand;
1968
1969 callFrame->r(dst) = scope->registerAt(index);
1970 vPC += OPCODE_LENGTH(op_get_global_var);
1971 NEXT_INSTRUCTION();
1972 }
1973 DEFINE_OPCODE(op_put_global_var) {
1974 /* put_global_var globalObject(c) index(n) value(r)
1975
1976 Puts value into global slot index.
1977 */
1978 JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[1].u.jsCell);
1979 ASSERT(scope->isGlobalObject());
1980 int index = vPC[2].u.operand;
1981 int value = vPC[3].u.operand;
1982
1983 scope->registerAt(index) = JSValue(callFrame->r(value).jsValue());
1984 vPC += OPCODE_LENGTH(op_put_global_var);
1985 NEXT_INSTRUCTION();
1986 }
1987 DEFINE_OPCODE(op_get_scoped_var) {
1988 /* get_scoped_var dst(r) index(n) skip(n)
1989
1990 Loads the contents of the index-th local from the scope skip nodes from
1991 the top of the scope chain, and places it in register dst
1992 */
1993 int dst = vPC[1].u.operand;
1994 int index = vPC[2].u.operand;
1995 int skip = vPC[3].u.operand + callFrame->codeBlock()->needsFullScopeChain();
1996
1997 ScopeChainNode* scopeChain = callFrame->scopeChain();
1998 ScopeChainIterator iter = scopeChain->begin();
1999 ScopeChainIterator end = scopeChain->end();
2000 ASSERT(iter != end);
2001 while (skip--) {
2002 ++iter;
2003 ASSERT(iter != end);
2004 }
2005
2006 ASSERT((*iter)->isVariableObject());
2007 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2008 callFrame->r(dst) = scope->registerAt(index);
2009 vPC += OPCODE_LENGTH(op_get_scoped_var);
2010 NEXT_INSTRUCTION();
2011 }
2012 DEFINE_OPCODE(op_put_scoped_var) {
2013 /* put_scoped_var index(n) skip(n) value(r)
2014
2015 */
2016 int index = vPC[1].u.operand;
2017 int skip = vPC[2].u.operand + callFrame->codeBlock()->needsFullScopeChain();
2018 int value = vPC[3].u.operand;
2019
2020 ScopeChainNode* scopeChain = callFrame->scopeChain();
2021 ScopeChainIterator iter = scopeChain->begin();
2022 ScopeChainIterator end = scopeChain->end();
2023 ASSERT(iter != end);
2024 while (skip--) {
2025 ++iter;
2026 ASSERT(iter != end);
2027 }
2028
2029 ASSERT((*iter)->isVariableObject());
2030 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2031 scope->registerAt(index) = JSValue(callFrame->r(value).jsValue());
2032 vPC += OPCODE_LENGTH(op_put_scoped_var);
2033 NEXT_INSTRUCTION();
2034 }
2035 DEFINE_OPCODE(op_resolve_base) {
2036 /* resolve_base dst(r) property(id)
2037
2038 Searches the scope chain for an object containing
2039 identifier property, and if one is found, writes it to
2040 register dst. If none is found, the outermost scope (which
2041 will be the global object) is stored in register dst.
2042 */
2043 resolveBase(callFrame, vPC);
2044
2045 vPC += OPCODE_LENGTH(op_resolve_base);
2046 NEXT_INSTRUCTION();
2047 }
2048 DEFINE_OPCODE(op_resolve_with_base) {
2049 /* resolve_with_base baseDst(r) propDst(r) property(id)
2050
2051 Searches the scope chain for an object containing
2052 identifier property, and if one is found, writes it to
2053 register srcDst, and the retrieved property value to register
2054 propDst. If the property is not found, raises an exception.
2055
2056 This is more efficient than doing resolve_base followed by
2057 resolve, or resolve_base followed by get_by_id, as it
2058 avoids duplicate hash lookups.
2059 */
2060 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
2061 goto vm_throw;
2062
2063 vPC += OPCODE_LENGTH(op_resolve_with_base);
2064 NEXT_INSTRUCTION();
2065 }
2066 DEFINE_OPCODE(op_get_by_id) {
2067 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2068
2069 Generic property access: Gets the property named by identifier
2070 property from the value base, and puts the result in register dst.
2071 */
2072 int dst = vPC[1].u.operand;
2073 int base = vPC[2].u.operand;
2074 int property = vPC[3].u.operand;
2075
2076 CodeBlock* codeBlock = callFrame->codeBlock();
2077 Identifier& ident = codeBlock->identifier(property);
2078 JSValue baseValue = callFrame->r(base).jsValue();
2079 PropertySlot slot(baseValue);
2080 JSValue result = baseValue.get(callFrame, ident, slot);
2081 CHECK_FOR_EXCEPTION();
2082
2083 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
2084
2085 callFrame->r(dst) = result;
2086 vPC += OPCODE_LENGTH(op_get_by_id);
2087 NEXT_INSTRUCTION();
2088 }
2089 DEFINE_OPCODE(op_get_by_id_self) {
2090 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2091
2092 Cached property access: Attempts to get a cached property from the
2093 value base. If the cache misses, op_get_by_id_self reverts to
2094 op_get_by_id.
2095 */
2096 int base = vPC[2].u.operand;
2097 JSValue baseValue = callFrame->r(base).jsValue();
2098
2099 if (LIKELY(baseValue.isCell())) {
2100 JSCell* baseCell = asCell(baseValue);
2101 Structure* structure = vPC[4].u.structure;
2102
2103 if (LIKELY(baseCell->structure() == structure)) {
2104 ASSERT(baseCell->isObject());
2105 JSObject* baseObject = asObject(baseCell);
2106 int dst = vPC[1].u.operand;
2107 int offset = vPC[5].u.operand;
2108
2109 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2110 callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
2111
2112 vPC += OPCODE_LENGTH(op_get_by_id_self);
2113 NEXT_INSTRUCTION();
2114 }
2115 }
2116
2117 uncacheGetByID(callFrame->codeBlock(), vPC);
2118 NEXT_INSTRUCTION();
2119 }
2120 DEFINE_OPCODE(op_get_by_id_proto) {
2121 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2122
2123 Cached property access: Attempts to get a cached property from the
2124 value base's prototype. If the cache misses, op_get_by_id_proto
2125 reverts to op_get_by_id.
2126 */
2127 int base = vPC[2].u.operand;
2128 JSValue baseValue = callFrame->r(base).jsValue();
2129
2130 if (LIKELY(baseValue.isCell())) {
2131 JSCell* baseCell = asCell(baseValue);
2132 Structure* structure = vPC[4].u.structure;
2133
2134 if (LIKELY(baseCell->structure() == structure)) {
2135 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2136 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2137 Structure* prototypeStructure = vPC[5].u.structure;
2138
2139 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2140 int dst = vPC[1].u.operand;
2141 int offset = vPC[6].u.operand;
2142
2143 ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2144 ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2145 callFrame->r(dst) = JSValue(protoObject->getDirectOffset(offset));
2146
2147 vPC += OPCODE_LENGTH(op_get_by_id_proto);
2148 NEXT_INSTRUCTION();
2149 }
2150 }
2151 }
2152
2153 uncacheGetByID(callFrame->codeBlock(), vPC);
2154 NEXT_INSTRUCTION();
2155 }
2156 DEFINE_OPCODE(op_get_by_id_self_list) {
2157 // Polymorphic self access caching currently only supported when JITting.
2158 ASSERT_NOT_REACHED();
2159 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2160 vPC += OPCODE_LENGTH(op_get_by_id_self_list);
2161 NEXT_INSTRUCTION();
2162 }
2163 DEFINE_OPCODE(op_get_by_id_proto_list) {
2164 // Polymorphic prototype access caching currently only supported when JITting.
2165 ASSERT_NOT_REACHED();
2166 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2167 vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
2168 NEXT_INSTRUCTION();
2169 }
2170 DEFINE_OPCODE(op_get_by_id_chain) {
2171 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2172
2173 Cached property access: Attempts to get a cached property from the
2174 value base's prototype chain. If the cache misses, op_get_by_id_chain
2175 reverts to op_get_by_id.
2176 */
2177 int base = vPC[2].u.operand;
2178 JSValue baseValue = callFrame->r(base).jsValue();
2179
2180 if (LIKELY(baseValue.isCell())) {
2181 JSCell* baseCell = asCell(baseValue);
2182 Structure* structure = vPC[4].u.structure;
2183
2184 if (LIKELY(baseCell->structure() == structure)) {
2185 RefPtr<Structure>* it = vPC[5].u.structureChain->head();
2186 size_t count = vPC[6].u.operand;
2187 RefPtr<Structure>* end = it + count;
2188
2189 while (true) {
2190 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
2191
2192 if (UNLIKELY(baseObject->structure() != (*it).get()))
2193 break;
2194
2195 if (++it == end) {
2196 int dst = vPC[1].u.operand;
2197 int offset = vPC[7].u.operand;
2198
2199 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2200 ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2201 callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
2202
2203 vPC += OPCODE_LENGTH(op_get_by_id_chain);
2204 NEXT_INSTRUCTION();
2205 }
2206
2207 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2208 baseCell = baseObject;
2209 }
2210 }
2211 }
2212
2213 uncacheGetByID(callFrame->codeBlock(), vPC);
2214 NEXT_INSTRUCTION();
2215 }
2216 DEFINE_OPCODE(op_get_by_id_generic) {
2217 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2218
2219 Generic property access: Gets the property named by identifier
2220 property from the value base, and puts the result in register dst.
2221 */
2222 int dst = vPC[1].u.operand;
2223 int base = vPC[2].u.operand;
2224 int property = vPC[3].u.operand;
2225
2226 Identifier& ident = callFrame->codeBlock()->identifier(property);
2227 JSValue baseValue = callFrame->r(base).jsValue();
2228 PropertySlot slot(baseValue);
2229 JSValue result = baseValue.get(callFrame, ident, slot);
2230 CHECK_FOR_EXCEPTION();
2231
2232 callFrame->r(dst) = result;
2233 vPC += OPCODE_LENGTH(op_get_by_id_generic);
2234 NEXT_INSTRUCTION();
2235 }
2236 DEFINE_OPCODE(op_get_array_length) {
2237 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2238
2239 Cached property access: Gets the length of the array in register base,
2240 and puts the result in register dst. If register base does not hold
2241 an array, op_get_array_length reverts to op_get_by_id.
2242 */
2243
2244 int base = vPC[2].u.operand;
2245 JSValue baseValue = callFrame->r(base).jsValue();
2246 if (LIKELY(isJSArray(globalData, baseValue))) {
2247 int dst = vPC[1].u.operand;
2248 callFrame->r(dst) = jsNumber(callFrame, asArray(baseValue)->length());
2249 vPC += OPCODE_LENGTH(op_get_array_length);
2250 NEXT_INSTRUCTION();
2251 }
2252
2253 uncacheGetByID(callFrame->codeBlock(), vPC);
2254 NEXT_INSTRUCTION();
2255 }
2256 DEFINE_OPCODE(op_get_string_length) {
2257 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2258
2259 Cached property access: Gets the length of the string in register base,
2260 and puts the result in register dst. If register base does not hold
2261 a string, op_get_string_length reverts to op_get_by_id.
2262 */
2263
2264 int base = vPC[2].u.operand;
2265 JSValue baseValue = callFrame->r(base).jsValue();
2266 if (LIKELY(isJSString(globalData, baseValue))) {
2267 int dst = vPC[1].u.operand;
2268 callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->length());
2269 vPC += OPCODE_LENGTH(op_get_string_length);
2270 NEXT_INSTRUCTION();
2271 }
2272
2273 uncacheGetByID(callFrame->codeBlock(), vPC);
2274 NEXT_INSTRUCTION();
2275 }
2276 DEFINE_OPCODE(op_put_by_id) {
2277 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2278
2279 Generic property access: Sets the property named by identifier
2280 property, belonging to register base, to register value.
2281
2282 Unlike many opcodes, this one does not write any output to
2283 the register file.
2284 */
2285
2286 int base = vPC[1].u.operand;
2287 int property = vPC[2].u.operand;
2288 int value = vPC[3].u.operand;
2289
2290 CodeBlock* codeBlock = callFrame->codeBlock();
2291 JSValue baseValue = callFrame->r(base).jsValue();
2292 Identifier& ident = codeBlock->identifier(property);
2293 PutPropertySlot slot;
2294 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
2295 CHECK_FOR_EXCEPTION();
2296
2297 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
2298
2299 vPC += OPCODE_LENGTH(op_put_by_id);
2300 NEXT_INSTRUCTION();
2301 }
2302 DEFINE_OPCODE(op_put_by_id_transition) {
2303 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)
2304
2305 Cached property access: Attempts to set a new property with a cached transition
2306 property named by identifier property, belonging to register base,
2307 to register value. If the cache misses, op_put_by_id_transition
2308 reverts to op_put_by_id_generic.
2309
2310 Unlike many opcodes, this one does not write any output to
2311 the register file.
2312 */
2313 int base = vPC[1].u.operand;
2314 JSValue baseValue = callFrame->r(base).jsValue();
2315
2316 if (LIKELY(baseValue.isCell())) {
2317 JSCell* baseCell = asCell(baseValue);
2318 Structure* oldStructure = vPC[4].u.structure;
2319 Structure* newStructure = vPC[5].u.structure;
2320
2321 if (LIKELY(baseCell->structure() == oldStructure)) {
2322 ASSERT(baseCell->isObject());
2323 JSObject* baseObject = asObject(baseCell);
2324
2325 RefPtr<Structure>* it = vPC[6].u.structureChain->head();
2326
2327 JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);
2328 while (!proto.isNull()) {
2329 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
2330 uncachePutByID(callFrame->codeBlock(), vPC);
2331 NEXT_INSTRUCTION();
2332 }
2333 ++it;
2334 proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
2335 }
2336
2337 baseObject->transitionTo(newStructure);
2338
2339 int value = vPC[3].u.operand;
2340 unsigned offset = vPC[7].u.operand;
2341 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2342 baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
2343
2344 vPC += OPCODE_LENGTH(op_put_by_id_transition);
2345 NEXT_INSTRUCTION();
2346 }
2347 }
2348
2349 uncachePutByID(callFrame->codeBlock(), vPC);
2350 NEXT_INSTRUCTION();
2351 }
2352 DEFINE_OPCODE(op_put_by_id_replace) {
2353 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)
2354
2355 Cached property access: Attempts to set a pre-existing, cached
2356 property named by identifier property, belonging to register base,
2357 to register value. If the cache misses, op_put_by_id_replace
2358 reverts to op_put_by_id.
2359
2360 Unlike many opcodes, this one does not write any output to
2361 the register file.
2362 */
2363 int base = vPC[1].u.operand;
2364 JSValue baseValue = callFrame->r(base).jsValue();
2365
2366 if (LIKELY(baseValue.isCell())) {
2367 JSCell* baseCell = asCell(baseValue);
2368 Structure* structure = vPC[4].u.structure;
2369
2370 if (LIKELY(baseCell->structure() == structure)) {
2371 ASSERT(baseCell->isObject());
2372 JSObject* baseObject = asObject(baseCell);
2373 int value = vPC[3].u.operand;
2374 unsigned offset = vPC[5].u.operand;
2375
2376 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2377 baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
2378
2379 vPC += OPCODE_LENGTH(op_put_by_id_replace);
2380 NEXT_INSTRUCTION();
2381 }
2382 }
2383
2384 uncachePutByID(callFrame->codeBlock(), vPC);
2385 NEXT_INSTRUCTION();
2386 }
2387 DEFINE_OPCODE(op_put_by_id_generic) {
2388 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2389
2390 Generic property access: Sets the property named by identifier
2391 property, belonging to register base, to register value.
2392
2393 Unlike many opcodes, this one does not write any output to
2394 the register file.
2395 */
2396 int base = vPC[1].u.operand;
2397 int property = vPC[2].u.operand;
2398 int value = vPC[3].u.operand;
2399
2400 JSValue baseValue = callFrame->r(base).jsValue();
2401 Identifier& ident = callFrame->codeBlock()->identifier(property);
2402 PutPropertySlot slot;
2403 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
2404 CHECK_FOR_EXCEPTION();
2405
2406 vPC += OPCODE_LENGTH(op_put_by_id_generic);
2407 NEXT_INSTRUCTION();
2408 }
2409 DEFINE_OPCODE(op_del_by_id) {
2410 /* del_by_id dst(r) base(r) property(id)
2411
2412 Converts register base to Object, deletes the property
2413 named by identifier property from the object, and writes a
2414 boolean indicating success (if true) or failure (if false)
2415 to register dst.
2416 */
2417 int dst = vPC[1].u.operand;
2418 int base = vPC[2].u.operand;
2419 int property = vPC[3].u.operand;
2420
2421 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);
2422 Identifier& ident = callFrame->codeBlock()->identifier(property);
2423 JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, ident));
2424 CHECK_FOR_EXCEPTION();
2425 callFrame->r(dst) = result;
2426 vPC += OPCODE_LENGTH(op_del_by_id);
2427 NEXT_INSTRUCTION();
2428 }
2429 DEFINE_OPCODE(op_get_by_pname) {
2430 int dst = vPC[1].u.operand;
2431 int base = vPC[2].u.operand;
2432 int property = vPC[3].u.operand;
2433 int expected = vPC[4].u.operand;
2434 int iter = vPC[5].u.operand;
2435 int i = vPC[6].u.operand;
2436
2437 JSValue baseValue = callFrame->r(base).jsValue();
2438 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
2439 JSValue subscript = callFrame->r(property).jsValue();
2440 JSValue expectedSubscript = callFrame->r(expected).jsValue();
2441 int index = callFrame->r(i).i() - 1;
2442 JSValue result;
2443 int offset = 0;
2444 if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {
2445 callFrame->r(dst) = asObject(baseValue)->getDirectOffset(offset);
2446 vPC += OPCODE_LENGTH(op_get_by_pname);
2447 NEXT_INSTRUCTION();
2448 }
2449 Identifier propertyName(callFrame, subscript.toString(callFrame));
2450 result = baseValue.get(callFrame, propertyName);
2451 CHECK_FOR_EXCEPTION();
2452 callFrame->r(dst) = result;
2453 vPC += OPCODE_LENGTH(op_get_by_pname);
2454 NEXT_INSTRUCTION();
2455 }
2456 DEFINE_OPCODE(op_get_by_val) {
2457 /* get_by_val dst(r) base(r) property(r)
2458
2459 Converts register base to Object, gets the property named
2460 by register property from the object, and puts the result
2461 in register dst. property is nominally converted to string
2462 but numbers are treated more efficiently.
2463 */
2464 int dst = vPC[1].u.operand;
2465 int base = vPC[2].u.operand;
2466 int property = vPC[3].u.operand;
2467
2468 JSValue baseValue = callFrame->r(base).jsValue();
2469 JSValue subscript = callFrame->r(property).jsValue();
2470
2471 JSValue result;
2472
2473 if (LIKELY(subscript.isUInt32())) {
2474 uint32_t i = subscript.asUInt32();
2475 if (isJSArray(globalData, baseValue)) {
2476 JSArray* jsArray = asArray(baseValue);
2477 if (jsArray->canGetIndex(i))
2478 result = jsArray->getIndex(i);
2479 else
2480 result = jsArray->JSArray::get(callFrame, i);
2481 } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
2482 result = asString(baseValue)->getIndex(&callFrame->globalData(), i);
2483 else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i))
2484 result = asByteArray(baseValue)->getIndex(callFrame, i);
2485 else
2486 result = baseValue.get(callFrame, i);
2487 } else {
2488 Identifier property(callFrame, subscript.toString(callFrame));
2489 result = baseValue.get(callFrame, property);
2490 }
2491
2492 CHECK_FOR_EXCEPTION();
2493 callFrame->r(dst) = result;
2494 vPC += OPCODE_LENGTH(op_get_by_val);
2495 NEXT_INSTRUCTION();
2496 }
2497 DEFINE_OPCODE(op_put_by_val) {
2498 /* put_by_val base(r) property(r) value(r)
2499
2500 Sets register value on register base as the property named
2501 by register property. Base is converted to object
2502 first. register property is nominally converted to string
2503 but numbers are treated more efficiently.
2504
2505 Unlike many opcodes, this one does not write any output to
2506 the register file.
2507 */
2508 int base = vPC[1].u.operand;
2509 int property = vPC[2].u.operand;
2510 int value = vPC[3].u.operand;
2511
2512 JSValue baseValue = callFrame->r(base).jsValue();
2513 JSValue subscript = callFrame->r(property).jsValue();
2514
2515 if (LIKELY(subscript.isUInt32())) {
2516 uint32_t i = subscript.asUInt32();
2517 if (isJSArray(globalData, baseValue)) {
2518 JSArray* jsArray = asArray(baseValue);
2519 if (jsArray->canSetIndex(i))
2520 jsArray->setIndex(i, callFrame->r(value).jsValue());
2521 else
2522 jsArray->JSArray::put(callFrame, i, callFrame->r(value).jsValue());
2523 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2524 JSByteArray* jsByteArray = asByteArray(baseValue);
2525 double dValue = 0;
2526 JSValue jsValue = callFrame->r(value).jsValue();
2527 if (jsValue.isInt32())
2528 jsByteArray->setIndex(i, jsValue.asInt32());
2529 else if (jsValue.getNumber(dValue))
2530 jsByteArray->setIndex(i, dValue);
2531 else
2532 baseValue.put(callFrame, i, jsValue);
2533 } else
2534 baseValue.put(callFrame, i, callFrame->r(value).jsValue());
2535 } else {
2536 Identifier property(callFrame, subscript.toString(callFrame));
2537 if (!globalData->exception) { // Don't put to an object if toString threw an exception.
2538 PutPropertySlot slot;
2539 baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot);
2540 }
2541 }
2542
2543 CHECK_FOR_EXCEPTION();
2544 vPC += OPCODE_LENGTH(op_put_by_val);
2545 NEXT_INSTRUCTION();
2546 }
2547 DEFINE_OPCODE(op_del_by_val) {
2548 /* del_by_val dst(r) base(r) property(r)
2549
2550 Converts register base to Object, deletes the property
2551 named by register property from the object, and writes a
2552 boolean indicating success (if true) or failure (if false)
2553 to register dst.
2554 */
2555 int dst = vPC[1].u.operand;
2556 int base = vPC[2].u.operand;
2557 int property = vPC[3].u.operand;
2558
2559 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw
2560
2561 JSValue subscript = callFrame->r(property).jsValue();
2562 JSValue result;
2563 uint32_t i;
2564 if (subscript.getUInt32(i))
2565 result = jsBoolean(baseObj->deleteProperty(callFrame, i));
2566 else {
2567 CHECK_FOR_EXCEPTION();
2568 Identifier property(callFrame, subscript.toString(callFrame));
2569 CHECK_FOR_EXCEPTION();
2570 result = jsBoolean(baseObj->deleteProperty(callFrame, property));
2571 }
2572
2573 CHECK_FOR_EXCEPTION();
2574 callFrame->r(dst) = result;
2575 vPC += OPCODE_LENGTH(op_del_by_val);
2576 NEXT_INSTRUCTION();
2577 }
2578 DEFINE_OPCODE(op_put_by_index) {
2579 /* put_by_index base(r) property(n) value(r)
2580
2581 Sets register value on register base as the property named
2582 by the immediate number property. Base is converted to
2583 object first.
2584
2585 Unlike many opcodes, this one does not write any output to
2586 the register file.
2587
2588 This opcode is mainly used to initialize array literals.
2589 */
2590 int base = vPC[1].u.operand;
2591 unsigned property = vPC[2].u.operand;
2592 int value = vPC[3].u.operand;
2593
2594 callFrame->r(base).jsValue().put(callFrame, property, callFrame->r(value).jsValue());
2595
2596 vPC += OPCODE_LENGTH(op_put_by_index);
2597 NEXT_INSTRUCTION();
2598 }
2599 DEFINE_OPCODE(op_loop) {
2600 /* loop target(offset)
2601
2602 Jumps unconditionally to offset target from the current
2603 instruction.
2604
2605 Additionally this loop instruction may terminate JS execution is
2606 the JS timeout is reached.
2607 */
2608#if ENABLE(OPCODE_STATS)
2609 OpcodeStats::resetLastInstruction();
2610#endif
2611 int target = vPC[1].u.operand;
2612 CHECK_FOR_TIMEOUT();
2613 vPC += target;
2614 NEXT_INSTRUCTION();
2615 }
2616 DEFINE_OPCODE(op_jmp) {
2617 /* jmp target(offset)
2618
2619 Jumps unconditionally to offset target from the current
2620 instruction.
2621 */
2622#if ENABLE(OPCODE_STATS)
2623 OpcodeStats::resetLastInstruction();
2624#endif
2625 int target = vPC[1].u.operand;
2626
2627 vPC += target;
2628 NEXT_INSTRUCTION();
2629 }
2630 DEFINE_OPCODE(op_loop_if_true) {
2631 /* loop_if_true cond(r) target(offset)
2632
2633 Jumps to offset target from the current instruction, if and
2634 only if register cond converts to boolean as true.
2635
2636 Additionally this loop instruction may terminate JS execution is
2637 the JS timeout is reached.
2638 */
2639 int cond = vPC[1].u.operand;
2640 int target = vPC[2].u.operand;
2641 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2642 vPC += target;
2643 CHECK_FOR_TIMEOUT();
2644 NEXT_INSTRUCTION();
2645 }
2646
2647 vPC += OPCODE_LENGTH(op_loop_if_true);
2648 NEXT_INSTRUCTION();
2649 }
2650 DEFINE_OPCODE(op_loop_if_false) {
2651 /* loop_if_true cond(r) target(offset)
2652
2653 Jumps to offset target from the current instruction, if and
2654 only if register cond converts to boolean as false.
2655
2656 Additionally this loop instruction may terminate JS execution is
2657 the JS timeout is reached.
2658 */
2659 int cond = vPC[1].u.operand;
2660 int target = vPC[2].u.operand;
2661 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2662 vPC += target;
2663 CHECK_FOR_TIMEOUT();
2664 NEXT_INSTRUCTION();
2665 }
2666
2667 vPC += OPCODE_LENGTH(op_loop_if_true);
2668 NEXT_INSTRUCTION();
2669 }
2670 DEFINE_OPCODE(op_jtrue) {
2671 /* jtrue cond(r) target(offset)
2672
2673 Jumps to offset target from the current instruction, if and
2674 only if register cond converts to boolean as true.
2675 */
2676 int cond = vPC[1].u.operand;
2677 int target = vPC[2].u.operand;
2678 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2679 vPC += target;
2680 NEXT_INSTRUCTION();
2681 }
2682
2683 vPC += OPCODE_LENGTH(op_jtrue);
2684 NEXT_INSTRUCTION();
2685 }
2686 DEFINE_OPCODE(op_jfalse) {
2687 /* jfalse cond(r) target(offset)
2688
2689 Jumps to offset target from the current instruction, if and
2690 only if register cond converts to boolean as false.
2691 */
2692 int cond = vPC[1].u.operand;
2693 int target = vPC[2].u.operand;
2694 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2695 vPC += target;
2696 NEXT_INSTRUCTION();
2697 }
2698
2699 vPC += OPCODE_LENGTH(op_jfalse);
2700 NEXT_INSTRUCTION();
2701 }
2702 DEFINE_OPCODE(op_jeq_null) {
2703 /* jeq_null src(r) target(offset)
2704
2705 Jumps to offset target from the current instruction, if and
2706 only if register src is null.
2707 */
2708 int src = vPC[1].u.operand;
2709 int target = vPC[2].u.operand;
2710 JSValue srcValue = callFrame->r(src).jsValue();
2711
2712 if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2713 vPC += target;
2714 NEXT_INSTRUCTION();
2715 }
2716
2717 vPC += OPCODE_LENGTH(op_jeq_null);
2718 NEXT_INSTRUCTION();
2719 }
2720 DEFINE_OPCODE(op_jneq_null) {
2721 /* jneq_null src(r) target(offset)
2722
2723 Jumps to offset target from the current instruction, if and
2724 only if register src is not null.
2725 */
2726 int src = vPC[1].u.operand;
2727 int target = vPC[2].u.operand;
2728 JSValue srcValue = callFrame->r(src).jsValue();
2729
2730 if (!srcValue.isUndefinedOrNull() && (!srcValue.isCell() || !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2731 vPC += target;
2732 NEXT_INSTRUCTION();
2733 }
2734
2735 vPC += OPCODE_LENGTH(op_jneq_null);
2736 NEXT_INSTRUCTION();
2737 }
2738 DEFINE_OPCODE(op_jneq_ptr) {
2739 /* jneq_ptr src(r) ptr(jsCell) target(offset)
2740
2741 Jumps to offset target from the current instruction, if the value r is equal
2742 to ptr, using pointer equality.
2743 */
2744 int src = vPC[1].u.operand;
2745 JSValue ptr = JSValue(vPC[2].u.jsCell);
2746 int target = vPC[3].u.operand;
2747 JSValue srcValue = callFrame->r(src).jsValue();
2748 if (srcValue != ptr) {
2749 vPC += target;
2750 NEXT_INSTRUCTION();
2751 }
2752
2753 vPC += OPCODE_LENGTH(op_jneq_ptr);
2754 NEXT_INSTRUCTION();
2755 }
2756 DEFINE_OPCODE(op_loop_if_less) {
2757 /* loop_if_less src1(r) src2(r) target(offset)
2758
2759 Checks whether register src1 is less than register src2, as
2760 with the ECMAScript '<' operator, and then jumps to offset
2761 target from the current instruction, if and only if the
2762 result of the comparison is true.
2763
2764 Additionally this loop instruction may terminate JS execution is
2765 the JS timeout is reached.
2766 */
2767 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2768 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2769 int target = vPC[3].u.operand;
2770
2771 bool result = jsLess(callFrame, src1, src2);
2772 CHECK_FOR_EXCEPTION();
2773
2774 if (result) {
2775 vPC += target;
2776 CHECK_FOR_TIMEOUT();
2777 NEXT_INSTRUCTION();
2778 }
2779
2780 vPC += OPCODE_LENGTH(op_loop_if_less);
2781 NEXT_INSTRUCTION();
2782 }
2783 DEFINE_OPCODE(op_loop_if_lesseq) {
2784 /* loop_if_lesseq src1(r) src2(r) target(offset)
2785
2786 Checks whether register src1 is less than or equal to register
2787 src2, as with the ECMAScript '<=' operator, and then jumps to
2788 offset target from the current instruction, if and only if the
2789 result of the comparison is true.
2790
2791 Additionally this loop instruction may terminate JS execution is
2792 the JS timeout is reached.
2793 */
2794 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2795 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2796 int target = vPC[3].u.operand;
2797
2798 bool result = jsLessEq(callFrame, src1, src2);
2799 CHECK_FOR_EXCEPTION();
2800
2801 if (result) {
2802 vPC += target;
2803 CHECK_FOR_TIMEOUT();
2804 NEXT_INSTRUCTION();
2805 }
2806
2807 vPC += OPCODE_LENGTH(op_loop_if_lesseq);
2808 NEXT_INSTRUCTION();
2809 }
2810 DEFINE_OPCODE(op_jnless) {
2811 /* jnless src1(r) src2(r) target(offset)
2812
2813 Checks whether register src1 is less than register src2, as
2814 with the ECMAScript '<' operator, and then jumps to offset
2815 target from the current instruction, if and only if the
2816 result of the comparison is false.
2817 */
2818 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2819 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2820 int target = vPC[3].u.operand;
2821
2822 bool result = jsLess(callFrame, src1, src2);
2823 CHECK_FOR_EXCEPTION();
2824
2825 if (!result) {
2826 vPC += target;
2827 NEXT_INSTRUCTION();
2828 }
2829
2830 vPC += OPCODE_LENGTH(op_jnless);
2831 NEXT_INSTRUCTION();
2832 }
2833 DEFINE_OPCODE(op_jless) {
2834 /* jless src1(r) src2(r) target(offset)
2835
2836 Checks whether register src1 is less than register src2, as
2837 with the ECMAScript '<' operator, and then jumps to offset
2838 target from the current instruction, if and only if the
2839 result of the comparison is true.
2840 */
2841 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2842 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2843 int target = vPC[3].u.operand;
2844
2845 bool result = jsLess(callFrame, src1, src2);
2846 CHECK_FOR_EXCEPTION();
2847
2848 if (result) {
2849 vPC += target;
2850 NEXT_INSTRUCTION();
2851 }
2852
2853 vPC += OPCODE_LENGTH(op_jless);
2854 NEXT_INSTRUCTION();
2855 }
2856 DEFINE_OPCODE(op_jnlesseq) {
2857 /* jnlesseq src1(r) src2(r) target(offset)
2858
2859 Checks whether register src1 is less than or equal to
2860 register src2, as with the ECMAScript '<=' operator,
2861 and then jumps to offset target from the current instruction,
2862 if and only if theresult of the comparison is false.
2863 */
2864 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2865 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2866 int target = vPC[3].u.operand;
2867
2868 bool result = jsLessEq(callFrame, src1, src2);
2869 CHECK_FOR_EXCEPTION();
2870
2871 if (!result) {
2872 vPC += target;
2873 NEXT_INSTRUCTION();
2874 }
2875
2876 vPC += OPCODE_LENGTH(op_jnlesseq);
2877 NEXT_INSTRUCTION();
2878 }
2879 DEFINE_OPCODE(op_switch_imm) {
2880 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2881
2882 Performs a range checked switch on the scrutinee value, using
2883 the tableIndex-th immediate switch jump table. If the scrutinee value
2884 is an immediate number in the range covered by the referenced jump
2885 table, and the value at jumpTable[scrutinee value] is non-zero, then
2886 that value is used as the jump offset, otherwise defaultOffset is used.
2887 */
2888 int tableIndex = vPC[1].u.operand;
2889 int defaultOffset = vPC[2].u.operand;
2890 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
2891 if (scrutinee.isInt32())
2892 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
2893 else {
2894 double value;
2895 int32_t intValue;
2896 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
2897 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
2898 else
2899 vPC += defaultOffset;
2900 }
2901 NEXT_INSTRUCTION();
2902 }
2903 DEFINE_OPCODE(op_switch_char) {
2904 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2905
2906 Performs a range checked switch on the scrutinee value, using
2907 the tableIndex-th character switch jump table. If the scrutinee value
2908 is a single character string in the range covered by the referenced jump
2909 table, and the value at jumpTable[scrutinee value] is non-zero, then
2910 that value is used as the jump offset, otherwise defaultOffset is used.
2911 */
2912 int tableIndex = vPC[1].u.operand;
2913 int defaultOffset = vPC[2].u.operand;
2914 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
2915 if (!scrutinee.isString())
2916 vPC += defaultOffset;
2917 else {
2918 UString::Rep* value = asString(scrutinee)->value().rep();
2919 if (value->size() != 1)
2920 vPC += defaultOffset;
2921 else
2922 vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->data()[0], defaultOffset);
2923 }
2924 NEXT_INSTRUCTION();
2925 }
2926 DEFINE_OPCODE(op_switch_string) {
2927 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2928
2929 Performs a sparse hashmap based switch on the value in the scrutinee
2930 register, using the tableIndex-th string switch jump table. If the
2931 scrutinee value is a string that exists as a key in the referenced
2932 jump table, then the value associated with the string is used as the
2933 jump offset, otherwise defaultOffset is used.
2934 */
2935 int tableIndex = vPC[1].u.operand;
2936 int defaultOffset = vPC[2].u.operand;
2937 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
2938 if (!scrutinee.isString())
2939 vPC += defaultOffset;
2940 else
2941 vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value().rep(), defaultOffset);
2942 NEXT_INSTRUCTION();
2943 }
2944 DEFINE_OPCODE(op_new_func) {
2945 /* new_func dst(r) func(f)
2946
2947 Constructs a new Function instance from function func and
2948 the current scope chain using the original Function
2949 constructor, using the rules for function declarations, and
2950 puts the result in register dst.
2951 */
2952 int dst = vPC[1].u.operand;
2953 int func = vPC[2].u.operand;
2954
2955 callFrame->r(dst) = JSValue(callFrame->codeBlock()->functionDecl(func)->make(callFrame, callFrame->scopeChain()));
2956
2957 vPC += OPCODE_LENGTH(op_new_func);
2958 NEXT_INSTRUCTION();
2959 }
2960 DEFINE_OPCODE(op_new_func_exp) {
2961 /* new_func_exp dst(r) func(f)
2962
2963 Constructs a new Function instance from function func and
2964 the current scope chain using the original Function
2965 constructor, using the rules for function expressions, and
2966 puts the result in register dst.
2967 */
2968 int dst = vPC[1].u.operand;
2969 int funcIndex = vPC[2].u.operand;
2970
2971 FunctionExecutable* function = callFrame->codeBlock()->functionExpr(funcIndex);
2972 JSFunction* func = function->make(callFrame, callFrame->scopeChain());
2973
2974 /*
2975 The Identifier in a FunctionExpression can be referenced from inside
2976 the FunctionExpression's FunctionBody to allow the function to call
2977 itself recursively. However, unlike in a FunctionDeclaration, the
2978 Identifier in a FunctionExpression cannot be referenced from and
2979 does not affect the scope enclosing the FunctionExpression.
2980 */
2981 if (!function->name().isNull()) {
2982 JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete);
2983 func->scope().push(functionScopeObject);
2984 }
2985
2986 callFrame->r(dst) = JSValue(func);
2987
2988 vPC += OPCODE_LENGTH(op_new_func_exp);
2989 NEXT_INSTRUCTION();
2990 }
2991 DEFINE_OPCODE(op_call_eval) {
2992 /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
2993
2994 Call a function named "eval" with no explicit "this" value
2995 (which may therefore be the eval operator). If register
2996 thisVal is the global object, and register func contains
2997 that global object's original global eval function, then
2998 perform the eval operator in local scope (interpreting
2999 the argument registers as for the "call"
3000 opcode). Otherwise, act exactly as the "call" opcode would.
3001 */
3002
3003 int dst = vPC[1].u.operand;
3004 int func = vPC[2].u.operand;
3005 int argCount = vPC[3].u.operand;
3006 int registerOffset = vPC[4].u.operand;
3007
3008 JSValue funcVal = callFrame->r(func).jsValue();
3009
3010 Register* newCallFrame = callFrame->registers() + registerOffset;
3011 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
3012 JSValue thisValue = argv[0].jsValue();
3013 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject;
3014
3015 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
3016 JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
3017 if (exceptionValue)
3018 goto vm_throw;
3019 callFrame->r(dst) = result;
3020
3021 vPC += OPCODE_LENGTH(op_call_eval);
3022 NEXT_INSTRUCTION();
3023 }
3024
3025 // We didn't find the blessed version of eval, so process this
3026 // instruction as a normal function call.
3027 // fall through to op_call
3028 }
3029 DEFINE_OPCODE(op_call) {
3030 /* call dst(r) func(r) argCount(n) registerOffset(n)
3031
3032 Perform a function call.
3033
3034 registerOffset is the distance the callFrame pointer should move
3035 before the VM initializes the new call frame's header.
3036
3037 dst is where op_ret should store its result.
3038 */
3039
3040 int dst = vPC[1].u.operand;
3041 int func = vPC[2].u.operand;
3042 int argCount = vPC[3].u.operand;
3043 int registerOffset = vPC[4].u.operand;
3044
3045 JSValue v = callFrame->r(func).jsValue();
3046
3047 CallData callData;
3048 CallType callType = v.getCallData(callData);
3049
3050 if (callType == CallTypeJS) {
3051 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3052 CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
3053
3054 CallFrame* previousCallFrame = callFrame;
3055
3056 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3057 if (UNLIKELY(!callFrame)) {
3058 callFrame = previousCallFrame;
3059 exceptionValue = createStackOverflowError(callFrame);
3060 goto vm_throw;
3061 }
3062
3063 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3064 vPC = newCodeBlock->instructions().begin();
3065
3066#if ENABLE(OPCODE_STATS)
3067 OpcodeStats::resetLastInstruction();
3068#endif
3069
3070 NEXT_INSTRUCTION();
3071 }
3072
3073 if (callType == CallTypeHost) {
3074 ScopeChainNode* scopeChain = callFrame->scopeChain();
3075 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3076 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
3077
3078 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
3079 ArgList args(thisRegister + 1, argCount - 1);
3080
3081 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3082 JSValue thisValue = thisRegister->jsValue();
3083 if (thisValue == jsNull())
3084 thisValue = callFrame->globalThisValue();
3085
3086 JSValue returnValue;
3087 {
3088 SamplingTool::HostCallRecord callRecord(m_sampler.get());
3089 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
3090 }
3091 CHECK_FOR_EXCEPTION();
3092
3093 callFrame->r(dst) = returnValue;
3094
3095 vPC += OPCODE_LENGTH(op_call);
3096 NEXT_INSTRUCTION();
3097 }
3098
3099 ASSERT(callType == CallTypeNone);
3100
3101 exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3102 goto vm_throw;
3103 }
3104 DEFINE_OPCODE(op_load_varargs) {
3105 int argCountDst = vPC[1].u.operand;
3106 int argsOffset = vPC[2].u.operand;
3107
3108 JSValue arguments = callFrame->r(argsOffset).jsValue();
3109 int32_t argCount = 0;
3110 if (!arguments) {
3111 argCount = (uint32_t)(callFrame->argumentCount()) - 1;
3112 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3113 Register* newEnd = callFrame->registers() + sizeDelta;
3114 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3115 exceptionValue = createStackOverflowError(callFrame);
3116 goto vm_throw;
3117 }
3118 ASSERT(!callFrame->callee()->isHostFunction());
3119 int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount();
3120 int32_t inplaceArgs = min(argCount, expectedParams);
3121 int32_t i = 0;
3122 Register* argStore = callFrame->registers() + argsOffset;
3123
3124 // First step is to copy the "expected" parameters from their normal location relative to the callframe
3125 for (; i < inplaceArgs; i++)
3126 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
3127 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
3128 for (; i < argCount; i++)
3129 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - argCount - 1];
3130 } else if (!arguments.isUndefinedOrNull()) {
3131 if (!arguments.isObject()) {
3132 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3133 goto vm_throw;
3134 }
3135 if (asObject(arguments)->classInfo() == &Arguments::info) {
3136 Arguments* args = asArguments(arguments);
3137 argCount = args->numProvidedArguments(callFrame);
3138 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3139 Register* newEnd = callFrame->registers() + sizeDelta;
3140 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3141 exceptionValue = createStackOverflowError(callFrame);
3142 goto vm_throw;
3143 }
3144 args->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
3145 } else if (isJSArray(&callFrame->globalData(), arguments)) {
3146 JSArray* array = asArray(arguments);
3147 argCount = array->length();
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);
3152 goto vm_throw;
3153 }
3154 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
3155 } else if (asObject(arguments)->inherits(&JSArray::info)) {
3156 JSObject* argObject = asObject(arguments);
3157 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
3158 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3159 Register* newEnd = callFrame->registers() + sizeDelta;
3160 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3161 exceptionValue = createStackOverflowError(callFrame);
3162 goto vm_throw;
3163 }
3164 Register* argsBuffer = callFrame->registers() + argsOffset;
3165 for (int32_t i = 0; i < argCount; ++i) {
3166 argsBuffer[i] = asObject(arguments)->get(callFrame, i);
3167 CHECK_FOR_EXCEPTION();
3168 }
3169 } else {
3170 if (!arguments.isObject()) {
3171 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3172 goto vm_throw;
3173 }
3174 }
3175 }
3176 CHECK_FOR_EXCEPTION();
3177 callFrame->r(argCountDst) = Register::withInt(argCount + 1);
3178 vPC += OPCODE_LENGTH(op_load_varargs);
3179 NEXT_INSTRUCTION();
3180 }
3181 DEFINE_OPCODE(op_call_varargs) {
3182 /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
3183
3184 Perform a function call with a dynamic set of arguments.
3185
3186 registerOffset is the distance the callFrame pointer should move
3187 before the VM initializes the new call frame's header, excluding
3188 space for arguments.
3189
3190 dst is where op_ret should store its result.
3191 */
3192
3193 int dst = vPC[1].u.operand;
3194 int func = vPC[2].u.operand;
3195 int argCountReg = vPC[3].u.operand;
3196 int registerOffset = vPC[4].u.operand;
3197
3198 JSValue v = callFrame->r(func).jsValue();
3199 int argCount = callFrame->r(argCountReg).i();
3200 registerOffset += argCount;
3201 CallData callData;
3202 CallType callType = v.getCallData(callData);
3203
3204 if (callType == CallTypeJS) {
3205 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3206 CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
3207
3208 CallFrame* previousCallFrame = callFrame;
3209
3210 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3211 if (UNLIKELY(!callFrame)) {
3212 callFrame = previousCallFrame;
3213 exceptionValue = createStackOverflowError(callFrame);
3214 goto vm_throw;
3215 }
3216
3217 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3218 vPC = newCodeBlock->instructions().begin();
3219
3220#if ENABLE(OPCODE_STATS)
3221 OpcodeStats::resetLastInstruction();
3222#endif
3223
3224 NEXT_INSTRUCTION();
3225 }
3226
3227 if (callType == CallTypeHost) {
3228 ScopeChainNode* scopeChain = callFrame->scopeChain();
3229 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3230 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
3231
3232 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
3233 ArgList args(thisRegister + 1, argCount - 1);
3234
3235 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3236 JSValue thisValue = thisRegister->jsValue();
3237 if (thisValue == jsNull())
3238 thisValue = callFrame->globalThisValue();
3239
3240 JSValue returnValue;
3241 {
3242 SamplingTool::HostCallRecord callRecord(m_sampler.get());
3243 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
3244 }
3245 CHECK_FOR_EXCEPTION();
3246
3247 callFrame->r(dst) = returnValue;
3248
3249 vPC += OPCODE_LENGTH(op_call_varargs);
3250 NEXT_INSTRUCTION();
3251 }
3252
3253 ASSERT(callType == CallTypeNone);
3254
3255 exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3256 goto vm_throw;
3257 }
3258 DEFINE_OPCODE(op_tear_off_activation) {
3259 /* tear_off_activation activation(r)
3260
3261 Copy all locals and parameters to new memory allocated on
3262 the heap, and make the passed activation use this memory
3263 in the future when looking up entries in the symbol table.
3264 If there is an 'arguments' object, then it will also use
3265 this memory for storing the named parameters, but not any
3266 extra arguments.
3267
3268 This opcode should only be used immediately before op_ret.
3269 */
3270
3271 int src = vPC[1].u.operand;
3272 ASSERT(callFrame->codeBlock()->needsFullScopeChain());
3273
3274 asActivation(callFrame->r(src).jsValue())->copyRegisters(callFrame->optionalCalleeArguments());
3275
3276 vPC += OPCODE_LENGTH(op_tear_off_activation);
3277 NEXT_INSTRUCTION();
3278 }
3279 DEFINE_OPCODE(op_tear_off_arguments) {
3280 /* tear_off_arguments
3281
3282 Copy all arguments to new memory allocated on the heap,
3283 and make the 'arguments' object use this memory in the
3284 future when looking up named parameters, but not any
3285 extra arguments. If an activation object exists for the
3286 current function context, then the tear_off_activation
3287 opcode should be used instead.
3288
3289 This opcode should only be used immediately before op_ret.
3290 */
3291
3292 ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());
3293
3294 if (callFrame->optionalCalleeArguments())
3295 callFrame->optionalCalleeArguments()->copyRegisters();
3296
3297 vPC += OPCODE_LENGTH(op_tear_off_arguments);
3298 NEXT_INSTRUCTION();
3299 }
3300 DEFINE_OPCODE(op_ret) {
3301 /* ret result(r)
3302
3303 Return register result as the return value of the current
3304 function call, writing it into the caller's expected return
3305 value register. In addition, unwind one call frame and
3306 restore the scope chain, code block instruction pointer and
3307 register base to those of the calling function.
3308 */
3309
3310 int result = vPC[1].u.operand;
3311
3312 if (callFrame->codeBlock()->needsFullScopeChain())
3313 callFrame->scopeChain()->deref();
3314
3315 JSValue returnValue = callFrame->r(result).jsValue();
3316
3317 vPC = callFrame->returnPC();
3318 int dst = callFrame->returnValueRegister();
3319 callFrame = callFrame->callerFrame();
3320
3321 if (callFrame->hasHostCallFrameFlag())
3322 return returnValue;
3323
3324 callFrame->r(dst) = returnValue;
3325
3326 NEXT_INSTRUCTION();
3327 }
3328 DEFINE_OPCODE(op_enter) {
3329 /* enter
3330
3331 Initializes local variables to undefined and fills constant
3332 registers with their values. If the code block requires an
3333 activation, enter_with_activation should be used instead.
3334
3335 This opcode should only be used at the beginning of a code
3336 block.
3337 */
3338
3339 size_t i = 0;
3340 CodeBlock* codeBlock = callFrame->codeBlock();
3341
3342 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3343 callFrame->r(i) = jsUndefined();
3344
3345 vPC += OPCODE_LENGTH(op_enter);
3346 NEXT_INSTRUCTION();
3347 }
3348 DEFINE_OPCODE(op_enter_with_activation) {
3349 /* enter_with_activation dst(r)
3350
3351 Initializes local variables to undefined, fills constant
3352 registers with their values, creates an activation object,
3353 and places the new activation both in dst and at the top
3354 of the scope chain. If the code block does not require an
3355 activation, enter should be used instead.
3356
3357 This opcode should only be used at the beginning of a code
3358 block.
3359 */
3360
3361 size_t i = 0;
3362 CodeBlock* codeBlock = callFrame->codeBlock();
3363
3364 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3365 callFrame->r(i) = jsUndefined();
3366
3367 int dst = vPC[1].u.operand;
3368 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable()));
3369 callFrame->r(dst) = JSValue(activation);
3370 callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation));
3371
3372 vPC += OPCODE_LENGTH(op_enter_with_activation);
3373 NEXT_INSTRUCTION();
3374 }
3375 DEFINE_OPCODE(op_convert_this) {
3376 /* convert_this this(r)
3377
3378 Takes the value in the 'this' register, converts it to a
3379 value that is suitable for use as the 'this' value, and
3380 stores it in the 'this' register. This opcode is emitted
3381 to avoid doing the conversion in the caller unnecessarily.
3382
3383 This opcode should only be used at the beginning of a code
3384 block.
3385 */
3386
3387 int thisRegister = vPC[1].u.operand;
3388 JSValue thisVal = callFrame->r(thisRegister).jsValue();
3389 if (thisVal.needsThisConversion())
3390 callFrame->r(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
3391
3392 vPC += OPCODE_LENGTH(op_convert_this);
3393 NEXT_INSTRUCTION();
3394 }
3395 DEFINE_OPCODE(op_init_arguments) {
3396 /* create_arguments
3397
3398 Initialises the arguments object reference to null to ensure
3399 we can correctly detect that we need to create it later (or
3400 avoid creating it altogether).
3401
3402 This opcode should only be used at the beginning of a code
3403 block.
3404 */
3405 callFrame->r(RegisterFile::ArgumentsRegister) = JSValue();
3406 vPC += OPCODE_LENGTH(op_init_arguments);
3407 NEXT_INSTRUCTION();
3408 }
3409 DEFINE_OPCODE(op_create_arguments) {
3410 /* create_arguments
3411
3412 Creates the 'arguments' object and places it in both the
3413 'arguments' call frame slot and the local 'arguments'
3414 register, if it has not already been initialised.
3415 */
3416
3417 if (!callFrame->r(RegisterFile::ArgumentsRegister).jsValue()) {
3418 Arguments* arguments = new (globalData) Arguments(callFrame);
3419 callFrame->setCalleeArguments(arguments);
3420 callFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
3421 }
3422 vPC += OPCODE_LENGTH(op_create_arguments);
3423 NEXT_INSTRUCTION();
3424 }
3425 DEFINE_OPCODE(op_construct) {
3426 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
3427
3428 Invoke register "func" as a constructor. For JS
3429 functions, the calling convention is exactly as for the
3430 "call" opcode, except that the "this" value is a newly
3431 created Object. For native constructors, no "this"
3432 value is passed. In either case, the argCount and registerOffset
3433 registers are interpreted as for the "call" opcode.
3434
3435 Register proto must contain the prototype property of
3436 register func. This is to enable polymorphic inline
3437 caching of this lookup.
3438 */
3439
3440 int dst = vPC[1].u.operand;
3441 int func = vPC[2].u.operand;
3442 int argCount = vPC[3].u.operand;
3443 int registerOffset = vPC[4].u.operand;
3444 int proto = vPC[5].u.operand;
3445 int thisRegister = vPC[6].u.operand;
3446
3447 JSValue v = callFrame->r(func).jsValue();
3448
3449 ConstructData constructData;
3450 ConstructType constructType = v.getConstructData(constructData);
3451
3452 if (constructType == ConstructTypeJS) {
3453 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3454 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
3455
3456 Structure* structure;
3457 JSValue prototype = callFrame->r(proto).jsValue();
3458 if (prototype.isObject())
3459 structure = asObject(prototype)->inheritorID();
3460 else
3461 structure = callDataScopeChain->globalObject->emptyObjectStructure();
3462 JSObject* newObject = new (globalData) JSObject(structure);
3463
3464 callFrame->r(thisRegister) = JSValue(newObject); // "this" value
3465
3466 CallFrame* previousCallFrame = callFrame;
3467
3468 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3469 if (UNLIKELY(!callFrame)) {
3470 callFrame = previousCallFrame;
3471 exceptionValue = createStackOverflowError(callFrame);
3472 goto vm_throw;
3473 }
3474
3475 callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3476 vPC = newCodeBlock->instructions().begin();
3477
3478#if ENABLE(OPCODE_STATS)
3479 OpcodeStats::resetLastInstruction();
3480#endif
3481
3482 NEXT_INSTRUCTION();
3483 }
3484
3485 if (constructType == ConstructTypeHost) {
3486 ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1);
3487
3488 ScopeChainNode* scopeChain = callFrame->scopeChain();
3489 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3490 newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
3491
3492 JSValue returnValue;
3493 {
3494 SamplingTool::HostCallRecord callRecord(m_sampler.get());
3495 returnValue = constructData.native.function(newCallFrame, asObject(v), args);
3496 }
3497 CHECK_FOR_EXCEPTION();
3498 callFrame->r(dst) = JSValue(returnValue);
3499
3500 vPC += OPCODE_LENGTH(op_construct);
3501 NEXT_INSTRUCTION();
3502 }
3503
3504 ASSERT(constructType == ConstructTypeNone);
3505
3506 exceptionValue = createNotAConstructorError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3507 goto vm_throw;
3508 }
3509 DEFINE_OPCODE(op_construct_verify) {
3510 /* construct_verify dst(r) override(r)
3511
3512 Verifies that register dst holds an object. If not, moves
3513 the object in register override to register dst.
3514 */
3515
3516 int dst = vPC[1].u.operand;
3517 if (LIKELY(callFrame->r(dst).jsValue().isObject())) {
3518 vPC += OPCODE_LENGTH(op_construct_verify);
3519 NEXT_INSTRUCTION();
3520 }
3521
3522 int override = vPC[2].u.operand;
3523 callFrame->r(dst) = callFrame->r(override);
3524
3525 vPC += OPCODE_LENGTH(op_construct_verify);
3526 NEXT_INSTRUCTION();
3527 }
3528 DEFINE_OPCODE(op_strcat) {
3529 int dst = vPC[1].u.operand;
3530 int src = vPC[2].u.operand;
3531 int count = vPC[3].u.operand;
3532
3533 callFrame->r(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
3534 vPC += OPCODE_LENGTH(op_strcat);
3535
3536 NEXT_INSTRUCTION();
3537 }
3538 DEFINE_OPCODE(op_to_primitive) {
3539 int dst = vPC[1].u.operand;
3540 int src = vPC[2].u.operand;
3541
3542 callFrame->r(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);
3543 vPC += OPCODE_LENGTH(op_to_primitive);
3544
3545 NEXT_INSTRUCTION();
3546 }
3547 DEFINE_OPCODE(op_push_scope) {
3548 /* push_scope scope(r)
3549
3550 Converts register scope to object, and pushes it onto the top
3551 of the current scope chain. The contents of the register scope
3552 are replaced by the result of toObject conversion of the scope.
3553 */
3554 int scope = vPC[1].u.operand;
3555 JSValue v = callFrame->r(scope).jsValue();
3556 JSObject* o = v.toObject(callFrame);
3557 CHECK_FOR_EXCEPTION();
3558
3559 callFrame->r(scope) = JSValue(o);
3560 callFrame->setScopeChain(callFrame->scopeChain()->push(o));
3561
3562 vPC += OPCODE_LENGTH(op_push_scope);
3563 NEXT_INSTRUCTION();
3564 }
3565 DEFINE_OPCODE(op_pop_scope) {
3566 /* pop_scope
3567
3568 Removes the top item from the current scope chain.
3569 */
3570 callFrame->setScopeChain(callFrame->scopeChain()->pop());
3571
3572 vPC += OPCODE_LENGTH(op_pop_scope);
3573 NEXT_INSTRUCTION();
3574 }
3575 DEFINE_OPCODE(op_get_pnames) {
3576 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
3577
3578 Creates a property name list for register base and puts it
3579 in register dst, initializing i and size for iteration. If
3580 base is undefined or null, jumps to breakTarget.
3581 */
3582 int dst = vPC[1].u.operand;
3583 int base = vPC[2].u.operand;
3584 int i = vPC[3].u.operand;
3585 int size = vPC[4].u.operand;
3586 int breakTarget = vPC[5].u.operand;
3587
3588 JSValue v = callFrame->r(base).jsValue();
3589 if (v.isUndefinedOrNull()) {
3590 vPC += breakTarget;
3591 NEXT_INSTRUCTION();
3592 }
3593
3594 JSObject* o = v.toObject(callFrame);
3595 Structure* structure = o->structure();
3596 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
3597 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
3598 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
3599
3600 callFrame->r(dst) = jsPropertyNameIterator;
3601 callFrame->r(base) = JSValue(o);
3602 callFrame->r(i) = Register::withInt(0);
3603 callFrame->r(size) = Register::withInt(jsPropertyNameIterator->size());
3604 vPC += OPCODE_LENGTH(op_get_pnames);
3605 NEXT_INSTRUCTION();
3606 }
3607 DEFINE_OPCODE(op_next_pname) {
3608 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
3609
3610 Copies the next name from the property name list in
3611 register iter to dst, then jumps to offset target. If there are no
3612 names left, invalidates the iterator and continues to the next
3613 instruction.
3614 */
3615 int dst = vPC[1].u.operand;
3616 int base = vPC[2].u.operand;
3617 int i = vPC[3].u.operand;
3618 int size = vPC[4].u.operand;
3619 int iter = vPC[5].u.operand;
3620 int target = vPC[6].u.operand;
3621
3622 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
3623 while (callFrame->r(i).i() != callFrame->r(size).i()) {
3624 JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());
3625 callFrame->r(i) = Register::withInt(callFrame->r(i).i() + 1);
3626 if (key) {
3627 CHECK_FOR_TIMEOUT();
3628 callFrame->r(dst) = key;
3629 vPC += target;
3630 NEXT_INSTRUCTION();
3631 }
3632 }
3633
3634 vPC += OPCODE_LENGTH(op_next_pname);
3635 NEXT_INSTRUCTION();
3636 }
3637 DEFINE_OPCODE(op_jmp_scopes) {
3638 /* jmp_scopes count(n) target(offset)
3639
3640 Removes the a number of items from the current scope chain
3641 specified by immediate number count, then jumps to offset
3642 target.
3643 */
3644 int count = vPC[1].u.operand;
3645 int target = vPC[2].u.operand;
3646
3647 ScopeChainNode* tmp = callFrame->scopeChain();
3648 while (count--)
3649 tmp = tmp->pop();
3650 callFrame->setScopeChain(tmp);
3651
3652 vPC += target;
3653 NEXT_INSTRUCTION();
3654 }
3655#if HAVE(COMPUTED_GOTO)
3656 // Appease GCC
3657 goto *(&&skip_new_scope);
3658#endif
3659 DEFINE_OPCODE(op_push_new_scope) {
3660 /* new_scope dst(r) property(id) value(r)
3661
3662 Constructs a new StaticScopeObject with property set to value. That scope
3663 object is then pushed onto the ScopeChain. The scope object is then stored
3664 in dst for GC.
3665 */
3666 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));
3667
3668 vPC += OPCODE_LENGTH(op_push_new_scope);
3669 NEXT_INSTRUCTION();
3670 }
3671#if HAVE(COMPUTED_GOTO)
3672 skip_new_scope:
3673#endif
3674 DEFINE_OPCODE(op_catch) {
3675 /* catch ex(r)
3676
3677 Retrieves the VM's current exception and puts it in register
3678 ex. This is only valid after an exception has been raised,
3679 and usually forms the beginning of an exception handler.
3680 */
3681 ASSERT(exceptionValue);
3682 ASSERT(!globalData->exception);
3683 int ex = vPC[1].u.operand;
3684 callFrame->r(ex) = exceptionValue;
3685 exceptionValue = JSValue();
3686
3687 vPC += OPCODE_LENGTH(op_catch);
3688 NEXT_INSTRUCTION();
3689 }
3690 DEFINE_OPCODE(op_throw) {
3691 /* throw ex(r)
3692
3693 Throws register ex as an exception. This involves three
3694 steps: first, it is set as the current exception in the
3695 VM's internal state, then the stack is unwound until an
3696 exception handler or a native code boundary is found, and
3697 then control resumes at the exception handler if any or
3698 else the script returns control to the nearest native caller.
3699 */
3700
3701 int ex = vPC[1].u.operand;
3702 exceptionValue = callFrame->r(ex).jsValue();
3703
3704 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), true);
3705 if (!handler) {
3706 *exception = exceptionValue;
3707 return jsNull();
3708 }
3709
3710 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
3711 NEXT_INSTRUCTION();
3712 }
3713 DEFINE_OPCODE(op_new_error) {
3714 /* new_error dst(r) type(n) message(k)
3715
3716 Constructs a new Error instance using the original
3717 constructor, using immediate number n as the type and
3718 constant message as the message string. The result is
3719 written to register dst.
3720 */
3721 int dst = vPC[1].u.operand;
3722 int type = vPC[2].u.operand;
3723 int message = vPC[3].u.operand;
3724
3725 CodeBlock* codeBlock = callFrame->codeBlock();
3726 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()));
3727
3728 vPC += OPCODE_LENGTH(op_new_error);
3729 NEXT_INSTRUCTION();
3730 }
3731 DEFINE_OPCODE(op_end) {
3732 /* end result(r)
3733
3734 Return register result as the value of a global or eval
3735 program. Return control to the calling native code.
3736 */
3737
3738 if (callFrame->codeBlock()->needsFullScopeChain()) {
3739 ScopeChainNode* scopeChain = callFrame->scopeChain();
3740 ASSERT(scopeChain->refCount > 1);
3741 scopeChain->deref();
3742 }
3743 int result = vPC[1].u.operand;
3744 return callFrame->r(result).jsValue();
3745 }
3746 DEFINE_OPCODE(op_put_getter) {
3747 /* put_getter base(r) property(id) function(r)
3748
3749 Sets register function on register base as the getter named
3750 by identifier property. Base and function are assumed to be
3751 objects as this op should only be used for getters defined
3752 in object literal form.
3753
3754 Unlike many opcodes, this one does not write any output to
3755 the register file.
3756 */
3757 int base = vPC[1].u.operand;
3758 int property = vPC[2].u.operand;
3759 int function = vPC[3].u.operand;
3760
3761 ASSERT(callFrame->r(base).jsValue().isObject());
3762 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
3763 Identifier& ident = callFrame->codeBlock()->identifier(property);
3764 ASSERT(callFrame->r(function).jsValue().isObject());
3765 baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue()));
3766
3767 vPC += OPCODE_LENGTH(op_put_getter);
3768 NEXT_INSTRUCTION();
3769 }
3770 DEFINE_OPCODE(op_put_setter) {
3771 /* put_setter base(r) property(id) function(r)
3772
3773 Sets register function on register base as the setter named
3774 by identifier property. Base and function are assumed to be
3775 objects as this op should only be used for setters defined
3776 in object literal form.
3777
3778 Unlike many opcodes, this one does not write any output to
3779 the register file.
3780 */
3781 int base = vPC[1].u.operand;
3782 int property = vPC[2].u.operand;
3783 int function = vPC[3].u.operand;
3784
3785 ASSERT(callFrame->r(base).jsValue().isObject());
3786 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
3787 Identifier& ident = callFrame->codeBlock()->identifier(property);
3788 ASSERT(callFrame->r(function).jsValue().isObject());
3789 baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
3790
3791 vPC += OPCODE_LENGTH(op_put_setter);
3792 NEXT_INSTRUCTION();
3793 }
3794 DEFINE_OPCODE(op_method_check) {
3795 vPC++;
3796 NEXT_INSTRUCTION();
3797 }
3798 DEFINE_OPCODE(op_jsr) {
3799 /* jsr retAddrDst(r) target(offset)
3800
3801 Places the address of the next instruction into the retAddrDst
3802 register and jumps to offset target from the current instruction.
3803 */
3804 int retAddrDst = vPC[1].u.operand;
3805 int target = vPC[2].u.operand;
3806 callFrame->r(retAddrDst) = vPC + OPCODE_LENGTH(op_jsr);
3807
3808 vPC += target;
3809 NEXT_INSTRUCTION();
3810 }
3811 DEFINE_OPCODE(op_sret) {
3812 /* sret retAddrSrc(r)
3813
3814 Jumps to the address stored in the retAddrSrc register. This
3815 differs from op_jmp because the target address is stored in a
3816 register, not as an immediate.
3817 */
3818 int retAddrSrc = vPC[1].u.operand;
3819 vPC = callFrame->r(retAddrSrc).vPC();
3820 NEXT_INSTRUCTION();
3821 }
3822 DEFINE_OPCODE(op_debug) {
3823 /* debug debugHookID(n) firstLine(n) lastLine(n)
3824
3825 Notifies the debugger of the current state of execution. This opcode
3826 is only generated while the debugger is attached.
3827 */
3828 int debugHookID = vPC[1].u.operand;
3829 int firstLine = vPC[2].u.operand;
3830 int lastLine = vPC[3].u.operand;
3831
3832 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3833
3834 vPC += OPCODE_LENGTH(op_debug);
3835 NEXT_INSTRUCTION();
3836 }
3837 DEFINE_OPCODE(op_profile_will_call) {
3838 /* op_profile_will_call function(r)
3839
3840 Notifies the profiler of the beginning of a function call. This opcode
3841 is only generated if developer tools are enabled.
3842 */
3843 int function = vPC[1].u.operand;
3844
3845 if (*enabledProfilerReference)
3846 (*enabledProfilerReference)->willExecute(callFrame, callFrame->r(function).jsValue());
3847
3848 vPC += OPCODE_LENGTH(op_profile_will_call);
3849 NEXT_INSTRUCTION();
3850 }
3851 DEFINE_OPCODE(op_profile_did_call) {
3852 /* op_profile_did_call function(r)
3853
3854 Notifies the profiler of the end of a function call. This opcode
3855 is only generated if developer tools are enabled.
3856 */
3857 int function = vPC[1].u.operand;
3858
3859 if (*enabledProfilerReference)
3860 (*enabledProfilerReference)->didExecute(callFrame, callFrame->r(function).jsValue());
3861
3862 vPC += OPCODE_LENGTH(op_profile_did_call);
3863 NEXT_INSTRUCTION();
3864 }
3865 vm_throw: {
3866 globalData->exception = JSValue();
3867 if (!tickCount) {
3868 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3869 // cannot fathom if we don't assign to the exceptionValue before branching)
3870 exceptionValue = createInterruptedExecutionException(globalData);
3871 }
3872 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), false);
3873 if (!handler) {
3874 *exception = exceptionValue;
3875 return jsNull();
3876 }
3877
3878 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
3879 NEXT_INSTRUCTION();
3880 }
3881 }
3882#if !HAVE(COMPUTED_GOTO)
3883 } // iterator loop ends
3884#endif
3885#endif // USE(INTERPRETER)
3886 #undef NEXT_INSTRUCTION
3887 #undef DEFINE_OPCODE
3888 #undef CHECK_FOR_EXCEPTION
3889 #undef CHECK_FOR_TIMEOUT
3890}
3891
3892JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
3893{
3894 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
3895 if (!functionCallFrame)
3896 return jsNull();
3897
3898 CodeBlock* codeBlock = functionCallFrame->codeBlock();
3899 if (codeBlock->usesArguments()) {
3900 ASSERT(codeBlock->codeType() == FunctionCode);
3901 SymbolTable& symbolTable = *codeBlock->symbolTable();
3902 int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();
3903 if (!functionCallFrame->r(argumentsIndex).jsValue()) {
3904 Arguments* arguments = new (callFrame) Arguments(functionCallFrame);
3905 functionCallFrame->setCalleeArguments(arguments);
3906 functionCallFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
3907 }
3908 return functionCallFrame->r(argumentsIndex).jsValue();
3909 }
3910
3911 Arguments* arguments = functionCallFrame->optionalCalleeArguments();
3912 if (!arguments) {
3913 arguments = new (functionCallFrame) Arguments(functionCallFrame);
3914 arguments->copyRegisters();
3915 callFrame->setCalleeArguments(arguments);
3916 }
3917
3918 return arguments;
3919}
3920
3921JSValue Interpreter::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const
3922{
3923 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
3924 if (!functionCallFrame)
3925 return jsNull();
3926
3927 CallFrame* callerFrame = functionCallFrame->callerFrame();
3928 if (callerFrame->hasHostCallFrameFlag())
3929 return jsNull();
3930
3931 JSValue caller = callerFrame->callee();
3932 if (!caller)
3933 return jsNull();
3934
3935 return caller;
3936}
3937
3938void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const
3939{
3940 function = JSValue();
3941 lineNumber = -1;
3942 sourceURL = UString();
3943
3944 CallFrame* callerFrame = callFrame->callerFrame();
3945 if (callerFrame->hasHostCallFrameFlag())
3946 return;
3947
3948 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
3949 if (!callerCodeBlock)
3950 return;
3951
3952 unsigned bytecodeOffset = bytecodeOffsetForPC(callerFrame, callerCodeBlock, callFrame->returnPC());
3953 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(callerFrame, bytecodeOffset - 1);
3954 sourceID = callerCodeBlock->ownerExecutable()->sourceID();
3955 sourceURL = callerCodeBlock->ownerExecutable()->sourceURL();
3956 function = callerFrame->callee();
3957}
3958
3959CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunction* function)
3960{
3961 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
3962 if (candidate->callee() == function)
3963 return candidate;
3964 }
3965 return 0;
3966}
3967
3968void Interpreter::enableSampler()
3969{
3970#if ENABLE(OPCODE_SAMPLING)
3971 if (!m_sampler) {
3972 m_sampler.set(new SamplingTool(this));
3973 m_sampler->setup();
3974 }
3975#endif
3976}
3977void Interpreter::dumpSampleData(ExecState* exec)
3978{
3979#if ENABLE(OPCODE_SAMPLING)
3980 if (m_sampler)
3981 m_sampler->dump(exec);
3982#else
3983 UNUSED_PARAM(exec);
3984#endif
3985}
3986void Interpreter::startSampling()
3987{
3988#if ENABLE(SAMPLING_THREAD)
3989 if (!m_sampleEntryDepth)
3990 SamplingThread::start();
3991
3992 m_sampleEntryDepth++;
3993#endif
3994}
3995void Interpreter::stopSampling()
3996{
3997#if ENABLE(SAMPLING_THREAD)
3998 m_sampleEntryDepth--;
3999 if (!m_sampleEntryDepth)
4000 SamplingThread::stop();
4001#endif
4002}
4003
4004} // namespace JSC
Note: See TracBrowser for help on using the repository browser.