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

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

2010-04-06 Adam Barth <[email protected]>

Reviewed by Eric Seidel.

REGRESSION: Worker termination via JS timeout may cause worker tests like fast/workers/worker-terminate.html fail.
https://bugs.webkit.org/show_bug.cgi?id=36646

Add a new exception type for forcibly terminating a JavaScript stack.
The new exception functions similarly to the
InterruptedExecutionException but is conceptually different because
execution is terminated instead of just interrupted.

  • GNUmakefile.am:
    • Added new Terminator.h file.
  • JavaScriptCore.gypi:
    • Added new Terminator.h file.
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
    • Added new Terminator.h file.
  • JavaScriptCore.xcodeproj/project.pbxproj:
    • Added new Terminator.h file.
  • interpreter/Interpreter.cpp: (JSC::Interpreter::throwException):
    • Fully unwind the stack for TerminatedExecutionException.

(JSC::Interpreter::privateExecute):

  • Check if we've been terminated at the same time we check if we've timed out.
  • jit/JITStubs.cpp: (JSC::DEFINE_STUB_FUNCTION):
    • Check if we've been terminated at the same time we check if we've timed out.
  • runtime/Completion.cpp:
    • Some exceptions define special completion types so that calls can see why we terminated evaluation.

(JSC::evaluate):

  • runtime/Completion.h:
    • Define a new completion type for termination.

(JSC::):

  • runtime/ExceptionHelpers.cpp:
    • Define TerminatedExecutionException and refactor pseudo-RTTI virtual function to be more semantic.

(JSC::InterruptedExecutionError::exceptionType):
(JSC::TerminatedExecutionError::TerminatedExecutionError):
(JSC::TerminatedExecutionError::exceptionType):
(JSC::TerminatedExecutionError::toString):
(JSC::createTerminatedExecutionException):

  • runtime/ExceptionHelpers.h:
    • Entry point for generating a TerminatedExecutionException.
  • runtime/JSGlobalData.cpp: (JSC::JSGlobalData::JSGlobalData):
    • Add a Terminator object that can be used to asynchronously terminate a JavaScript execution stack.
  • runtime/JSGlobalData.h:
  • runtime/JSObject.h: (JSC::JSObject::exceptionType):
    • Define that, by default, thrown objects have a normal exception type.
  • runtime/Terminator.h: Added.
    • Added a new controller object that can be used to terminate execution asynchronously. This object is more or less a glorified bool.

(JSC::Terminator::Terminator):
(JSC::Terminator::termianteSoon):
(JSC::Terminator::shouldTerminate):

2010-04-06 Adam Barth <[email protected]>

Reviewed by Eric Seidel.

REGRESSION: Worker termination via JS timeout may cause worker tests like fast/workers/worker-terminate.html fail.
https://bugs.webkit.org/show_bug.cgi?id=36646

  • fast/workers/resources/worker-run-forever.js: Added.
  • fast/workers/worker-terminate-forever-expected.txt: Added.
  • fast/workers/worker-terminate-forever.html: Added.
    • Test what happens when we terminate an infinitely running worker. The essential point is that we don't spam the console with nonsense about a timeout.
  • platform/mac/Skipped:
    • Rescue worker-terminate.html from the Skipped list now that we've fixed the underlying bug that was causing the flakiness.

2010-04-06 Adam Barth <[email protected]>

Reviewed by Eric Seidel.

REGRESSION: Worker termination via JS timeout may cause worker tests like fast/workers/worker-terminate.html fail.
https://bugs.webkit.org/show_bug.cgi?id=36646

Cause the worker code to swallow termination exceptions because these
need not be reported to the user because they are an implementation
detail of how we terminate worker execution.

Test: fast/workers/worker-terminate-forever.html

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