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

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

Merged nitro-extreme branch into trunk.

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