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

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

2009-04-21 Geoffrey Garen <[email protected]>

Reviewed by Cameron Zwarich and Oliver Hunt.


Re-Fixed <rdar://problem/6406045> REGRESSION: Stack overflow on PowerPC on
fast/workers/use-machine-stack.html (22531)


SunSpider reports no change.


Use a larger recursion limit on the main thread (because we can, and
there's some evidence that it may improve compatibility), and a smaller
recursion limit on secondary threads (because they tend to have smaller
stacks).

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