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

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

Bug 42207 - Clean up interface to compile executables, always check for exceptions

Reviewed by Oliver Hunt.

Presently interface to compile executable is inconsistent between eval/program and
function code, and is error prone in allowing a caller to byte compile without JIT
compiling an executable (we rely on all executables with codeblocks having JIT code).
Unify on an interface where all compilation is performed by a single compile (with
ForCall|ForConstruct variants) method, and make all clients check for errors.

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::unwindCallFrame):
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall):
(JSC::Interpreter::privateExecute):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • parser/Parser.h:

(JSC::Parser::isFunctionBodyNode):
(JSC::Parser::parse):

  • runtime/ArrayPrototype.cpp:

(JSC::isNumericCompareFunction):

  • runtime/ExceptionHelpers.cpp:

(JSC::createStackOverflowError):

  • runtime/ExceptionHelpers.h:
  • runtime/Executable.cpp:

(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::checkSyntax):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::compileForCallInternal):
(JSC::FunctionExecutable::compileForConstructInternal):
(JSC::FunctionExecutable::reparseExceptionInfo):
(JSC::EvalExecutable::reparseExceptionInfo):
(JSC::FunctionExecutable::fromGlobalCode):

  • runtime/Executable.h:

(JSC::EvalExecutable::compile):
(JSC::EvalExecutable::generatedBytecode):
(JSC::EvalExecutable::generatedJITCode):
(JSC::ProgramExecutable::compile):
(JSC::ProgramExecutable::generatedBytecode):
(JSC::ProgramExecutable::generatedJITCode):
(JSC::FunctionExecutable::generatedBytecode):
(JSC::FunctionExecutable::compileForCall):
(JSC::FunctionExecutable::compileForConstruct):
(JSC::FunctionExecutable::generatedJITCodeForConstructWithArityCheck):

  • runtime/FunctionConstructor.cpp:

(JSC::constructFunction):

  • runtime/JSActivation.cpp:

(JSC::JSActivation::argumentsGetter):

  • runtime/JSGlobalData.h:

(JSC::JSGlobalData::canUseJIT):

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