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