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

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

2008-12-05 Sam Weinig <[email protected]>

Reviewed by Cameron Zwarich.

Fix for https://bugs.webkit.org/show_bug.cgi?id=22715
Encapsulate more CodeBlock members in preparation
of moving some of them to a rare data structure.

  • bytecode/CodeBlock.cpp: (JSC::locationForOffset): (JSC::printConditionalJump): (JSC::printGetByIdOp): (JSC::printPutByIdOp): (JSC::CodeBlock::printStructure): (JSC::CodeBlock::printStructures): (JSC::CodeBlock::dump): (JSC::CodeBlock::~CodeBlock): (JSC::CodeBlock::unlinkCallers): (JSC::CodeBlock::derefStructures): (JSC::CodeBlock::refStructures): (JSC::CodeBlock::mark): (JSC::CodeBlock::getHandlerForVPC): (JSC::CodeBlock::nativeExceptionCodeForHandlerVPC): (JSC::CodeBlock::lineNumberForVPC): (JSC::CodeBlock::expressionRangeForVPC): (JSC::CodeBlock::shrinkToFit):
  • bytecode/CodeBlock.h: (JSC::CodeBlock::CodeBlock): (JSC::CodeBlock::addCaller): (JSC::CodeBlock::removeCaller): (JSC::CodeBlock::isKnownNotImmediate): (JSC::CodeBlock::isConstantRegisterIndex): (JSC::CodeBlock::getConstant): (JSC::CodeBlock::isTemporaryRegisterIndex): (JSC::CodeBlock::getStubInfo): (JSC::CodeBlock::getCallLinkInfo): (JSC::CodeBlock::instructions): (JSC::CodeBlock::setJITCode): (JSC::CodeBlock::jitCode): (JSC::CodeBlock::ownerNode): (JSC::CodeBlock::setGlobalData): (JSC::CodeBlock::setThisRegister): (JSC::CodeBlock::thisRegister): (JSC::CodeBlock::setNeedsFullScopeChain): (JSC::CodeBlock::needsFullScopeChain): (JSC::CodeBlock::setUsesEval): (JSC::CodeBlock::usesEval): (JSC::CodeBlock::setUsesArguments): (JSC::CodeBlock::usesArguments): (JSC::CodeBlock::codeType): (JSC::CodeBlock::source): (JSC::CodeBlock::sourceOffset): (JSC::CodeBlock::addGlobalResolveInstruction): (JSC::CodeBlock::numberOfPropertyAccessInstructions): (JSC::CodeBlock::addPropertyAccessInstruction): (JSC::CodeBlock::propertyAccessInstruction): (JSC::CodeBlock::numberOfCallLinkInfos): (JSC::CodeBlock::addCallLinkInfo): (JSC::CodeBlock::callLinkInfo): (JSC::CodeBlock::numberOfJumpTargets): (JSC::CodeBlock::addJumpTarget): (JSC::CodeBlock::jumpTarget): (JSC::CodeBlock::lastJumpTarget): (JSC::CodeBlock::numberOfExceptionHandlers): (JSC::CodeBlock::addExceptionHandler): (JSC::CodeBlock::exceptionHandler): (JSC::CodeBlock::addExpressionInfo): (JSC::CodeBlock::numberOfLineInfos): (JSC::CodeBlock::addLineInfo): (JSC::CodeBlock::lastLineInfo): (JSC::CodeBlock::jitReturnAddressVPCMap): (JSC::CodeBlock::numberOfIdentifiers): (JSC::CodeBlock::addIdentifier): (JSC::CodeBlock::identifier): (JSC::CodeBlock::numberOfConstantRegisters): (JSC::CodeBlock::addConstantRegister): (JSC::CodeBlock::constantRegister): (JSC::CodeBlock::addFunction): (JSC::CodeBlock::function): (JSC::CodeBlock::addFunctionExpression): (JSC::CodeBlock::functionExpression): (JSC::CodeBlock::addUnexpectedConstant): (JSC::CodeBlock::unexpectedConstant): (JSC::CodeBlock::addRegExp): (JSC::CodeBlock::regexp): (JSC::CodeBlock::symbolTable): (JSC::CodeBlock::evalCodeCache): New inline setters/getters.

(JSC::ProgramCodeBlock::ProgramCodeBlock):
(JSC::ProgramCodeBlock::~ProgramCodeBlock):
(JSC::ProgramCodeBlock::clearGlobalObject):

  • bytecode/SamplingTool.cpp: (JSC::ScopeSampleRecord::sample): (JSC::SamplingTool::dump):
  • bytecompiler/BytecodeGenerator.cpp:
  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/Label.h:
  • interpreter/CallFrame.cpp:
  • interpreter/Interpreter.cpp:
  • jit/JIT.cpp:
  • jit/JITCall.cpp:
  • jit/JITInlineMethods.h:
  • jit/JITPropertyAccess.cpp:
  • parser/Nodes.cpp:
  • runtime/Arguments.h:
  • runtime/ExceptionHelpers.cpp:
  • runtime/JSActivation.cpp:
  • runtime/JSActivation.h:
  • runtime/JSGlobalObject.cpp: Change direct access to use new getter/setters.
File size: 209.8 KB
Line 
1/*
2 * Copyright (C) 2008 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 "CodeBlock.h"
36#include "DebuggerCallFrame.h"
37#include "EvalCodeCache.h"
38#include "ExceptionHelpers.h"
39#include "CallFrame.h"
40#include "GlobalEvalFunction.h"
41#include "JSActivation.h"
42#include "JSArray.h"
43#include "JSFunction.h"
44#include "JSNotAnObject.h"
45#include "JSPropertyNameIterator.h"
46#include "JSStaticScopeObject.h"
47#include "JSString.h"
48#include "ObjectPrototype.h"
49#include "Parser.h"
50#include "Profiler.h"
51#include "RegExpObject.h"
52#include "RegExpPrototype.h"
53#include "Register.h"
54#include "Collector.h"
55#include "Debugger.h"
56#include "Operations.h"
57#include "SamplingTool.h"
58#include <stdio.h>
59
60#if ENABLE(JIT)
61#include "JIT.h"
62#endif
63
64#if ENABLE(ASSEMBLER)
65#include "AssemblerBuffer.h"
66#endif
67
68#if PLATFORM(DARWIN)
69#include <mach/mach.h>
70#endif
71
72#if HAVE(SYS_TIME_H)
73#include <sys/time.h>
74#endif
75
76#if PLATFORM(WIN_OS)
77#include <windows.h>
78#endif
79
80#if PLATFORM(QT)
81#include <QDateTime>
82#endif
83
84using namespace std;
85
86namespace JSC {
87
88// Preferred number of milliseconds between each timeout check
89static const int preferredScriptCheckTimeInterval = 1000;
90
91#if ENABLE(JIT)
92
93static ALWAYS_INLINE Instruction* vPCForPC(CodeBlock* codeBlock, void* pc)
94{
95 if (pc >= codeBlock->instructions().begin() && pc < codeBlock->instructions().end())
96 return static_cast<Instruction*>(pc);
97
98 ASSERT(codeBlock->jitReturnAddressVPCMap().contains(pc));
99 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(pc);
100 return codeBlock->instructions().begin() + vPCIndex;
101}
102
103#else // ENABLE(JIT)
104
105static ALWAYS_INLINE Instruction* vPCForPC(CodeBlock*, void* pc)
106{
107 return static_cast<Instruction*>(pc);
108}
109
110#endif // ENABLE(JIT)
111
112// Returns the depth of the scope chain within a given call frame.
113static int depth(CodeBlock* codeBlock, ScopeChain& sc)
114{
115 if (!codeBlock->needsFullScopeChain())
116 return 0;
117 int scopeDepth = 0;
118 ScopeChainIterator iter = sc.begin();
119 ScopeChainIterator end = sc.end();
120 while (!(*iter)->isObject(&JSActivation::info)) {
121 ++iter;
122 if (iter == end)
123 break;
124 ++scopeDepth;
125 }
126 return scopeDepth;
127}
128
129// FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
130// FIXME: There's no need to have a "slow" version of this. All versions should be fast.
131static ALWAYS_INLINE bool fastIsNumber(JSValue* value, double& arg)
132{
133 if (JSImmediate::isNumber(value))
134 arg = JSImmediate::getTruncatedInt32(value);
135 else if (LIKELY(!JSImmediate::isImmediate(value)) && LIKELY(Heap::isNumber(asCell(value))))
136 arg = asNumberCell(value)->value();
137 else
138 return false;
139 return true;
140}
141
142// FIXME: Why doesn't JSValue*::toInt32 have the Heap::isNumber optimization?
143static bool fastToInt32(JSValue* value, int32_t& arg)
144{
145 if (JSImmediate::isNumber(value))
146 arg = JSImmediate::getTruncatedInt32(value);
147 else if (LIKELY(!JSImmediate::isImmediate(value)) && LIKELY(Heap::isNumber(asCell(value))))
148 arg = asNumberCell(value)->toInt32();
149 else
150 return false;
151 return true;
152}
153
154static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
155{
156 if (JSImmediate::isNumber(value)) {
157 if (JSImmediate::getTruncatedUInt32(value, arg))
158 return true;
159 bool scratch;
160 arg = toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
161 return true;
162 } else if (!JSImmediate::isImmediate(value) && Heap::isNumber(asCell(value)))
163 arg = asNumberCell(value)->toUInt32();
164 else
165 return false;
166 return true;
167}
168
169static inline bool jsLess(CallFrame* callFrame, JSValue* v1, JSValue* v2)
170{
171 if (JSImmediate::areBothImmediateNumbers(v1, v2))
172 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
173
174 double n1;
175 double n2;
176 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
177 return n1 < n2;
178
179 Interpreter* interpreter = callFrame->interpreter();
180 if (interpreter->isJSString(v1) && interpreter->isJSString(v2))
181 return asString(v1)->value() < asString(v2)->value();
182
183 JSValue* p1;
184 JSValue* p2;
185 bool wasNotString1 = v1->getPrimitiveNumber(callFrame, n1, p1);
186 bool wasNotString2 = v2->getPrimitiveNumber(callFrame, n2, p2);
187
188 if (wasNotString1 | wasNotString2)
189 return n1 < n2;
190
191 return asString(p1)->value() < asString(p2)->value();
192}
193
194static inline bool jsLessEq(CallFrame* callFrame, JSValue* v1, JSValue* v2)
195{
196 if (JSImmediate::areBothImmediateNumbers(v1, v2))
197 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
198
199 double n1;
200 double n2;
201 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
202 return n1 <= n2;
203
204 Interpreter* interpreter = callFrame->interpreter();
205 if (interpreter->isJSString(v1) && interpreter->isJSString(v2))
206 return !(asString(v2)->value() < asString(v1)->value());
207
208 JSValue* p1;
209 JSValue* p2;
210 bool wasNotString1 = v1->getPrimitiveNumber(callFrame, n1, p1);
211 bool wasNotString2 = v2->getPrimitiveNumber(callFrame, n2, p2);
212
213 if (wasNotString1 | wasNotString2)
214 return n1 <= n2;
215
216 return !(asString(p2)->value() < asString(p1)->value());
217}
218
219static NEVER_INLINE JSValue* jsAddSlowCase(CallFrame* callFrame, JSValue* v1, JSValue* v2)
220{
221 // exception for the Date exception in defaultValue()
222 JSValue* p1 = v1->toPrimitive(callFrame);
223 JSValue* p2 = v2->toPrimitive(callFrame);
224
225 if (p1->isString() || p2->isString()) {
226 RefPtr<UString::Rep> value = concatenate(p1->toString(callFrame).rep(), p2->toString(callFrame).rep());
227 if (!value)
228 return throwOutOfMemoryError(callFrame);
229 return jsString(callFrame, value.release());
230 }
231
232 return jsNumber(callFrame, p1->toNumber(callFrame) + p2->toNumber(callFrame));
233}
234
235// Fast-path choices here are based on frequency data from SunSpider:
236// <times> Add case: <t1> <t2>
237// ---------------------------
238// 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
239// 247412 Add case: 5 5
240// 20900 Add case: 5 6
241// 13962 Add case: 5 3
242// 4000 Add case: 3 5
243
244static ALWAYS_INLINE JSValue* jsAdd(CallFrame* callFrame, JSValue* v1, JSValue* v2)
245{
246 double left;
247 double right = 0.0;
248
249 bool rightIsNumber = fastIsNumber(v2, right);
250 if (rightIsNumber && fastIsNumber(v1, left))
251 return jsNumber(callFrame, left + right);
252
253 bool leftIsString = v1->isString();
254 if (leftIsString && v2->isString()) {
255 RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep());
256 if (!value)
257 return throwOutOfMemoryError(callFrame);
258 return jsString(callFrame, value.release());
259 }
260
261 if (rightIsNumber & leftIsString) {
262 RefPtr<UString::Rep> value = JSImmediate::isImmediate(v2) ?
263 concatenate(asString(v1)->value().rep(), JSImmediate::getTruncatedInt32(v2)) :
264 concatenate(asString(v1)->value().rep(), right);
265
266 if (!value)
267 return throwOutOfMemoryError(callFrame);
268 return jsString(callFrame, value.release());
269 }
270
271 // All other cases are pretty uncommon
272 return jsAddSlowCase(callFrame, v1, v2);
273}
274
275static JSValue* jsTypeStringForValue(CallFrame* callFrame, JSValue* v)
276{
277 if (v->isUndefined())
278 return jsNontrivialString(callFrame, "undefined");
279 if (v->isBoolean())
280 return jsNontrivialString(callFrame, "boolean");
281 if (v->isNumber())
282 return jsNontrivialString(callFrame, "number");
283 if (v->isString())
284 return jsNontrivialString(callFrame, "string");
285 if (v->isObject()) {
286 // Return "undefined" for objects that should be treated
287 // as null when doing comparisons.
288 if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined())
289 return jsNontrivialString(callFrame, "undefined");
290 CallData callData;
291 if (asObject(v)->getCallData(callData) != CallTypeNone)
292 return jsNontrivialString(callFrame, "function");
293 }
294 return jsNontrivialString(callFrame, "object");
295}
296
297static bool jsIsObjectType(JSValue* v)
298{
299 if (JSImmediate::isImmediate(v))
300 return v->isNull();
301
302 JSType type = asCell(v)->structure()->typeInfo().type();
303 if (type == NumberType || type == StringType)
304 return false;
305 if (type == ObjectType) {
306 if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined())
307 return false;
308 CallData callData;
309 if (asObject(v)->getCallData(callData) != CallTypeNone)
310 return false;
311 }
312 return true;
313}
314
315static bool jsIsFunctionType(JSValue* v)
316{
317 if (v->isObject()) {
318 CallData callData;
319 if (asObject(v)->getCallData(callData) != CallTypeNone)
320 return true;
321 }
322 return false;
323}
324
325NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue*& exceptionValue)
326{
327 int dst = (vPC + 1)->u.operand;
328 int property = (vPC + 2)->u.operand;
329
330 ScopeChainNode* scopeChain = callFrame->scopeChain();
331 ScopeChainIterator iter = scopeChain->begin();
332 ScopeChainIterator end = scopeChain->end();
333 ASSERT(iter != end);
334
335 CodeBlock* codeBlock = callFrame->codeBlock();
336 Identifier& ident = codeBlock->identifier(property);
337 do {
338 JSObject* o = *iter;
339 PropertySlot slot(o);
340 if (o->getPropertySlot(callFrame, ident, slot)) {
341 JSValue* result = slot.getValue(callFrame, ident);
342 exceptionValue = callFrame->globalData().exception;
343 if (exceptionValue)
344 return false;
345 callFrame[dst] = result;
346 return true;
347 }
348 } while (++iter != end);
349 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
350 return false;
351}
352
353NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue*& exceptionValue)
354{
355 CodeBlock* codeBlock = callFrame->codeBlock();
356
357 int dst = (vPC + 1)->u.operand;
358 int property = (vPC + 2)->u.operand;
359 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain();
360
361 ScopeChainNode* scopeChain = callFrame->scopeChain();
362 ScopeChainIterator iter = scopeChain->begin();
363 ScopeChainIterator end = scopeChain->end();
364 ASSERT(iter != end);
365 while (skip--) {
366 ++iter;
367 ASSERT(iter != end);
368 }
369 Identifier& ident = codeBlock->identifier(property);
370 do {
371 JSObject* o = *iter;
372 PropertySlot slot(o);
373 if (o->getPropertySlot(callFrame, ident, slot)) {
374 JSValue* result = slot.getValue(callFrame, ident);
375 exceptionValue = callFrame->globalData().exception;
376 if (exceptionValue)
377 return false;
378 callFrame[dst] = result;
379 return true;
380 }
381 } while (++iter != end);
382 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
383 return false;
384}
385
386NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue*& exceptionValue)
387{
388 int dst = (vPC + 1)->u.operand;
389 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
390 ASSERT(globalObject->isGlobalObject());
391 int property = (vPC + 3)->u.operand;
392 Structure* structure = (vPC + 4)->u.structure;
393 int offset = (vPC + 5)->u.operand;
394
395 if (structure == globalObject->structure()) {
396 callFrame[dst] = globalObject->getDirectOffset(offset);
397 return true;
398 }
399
400 CodeBlock* codeBlock = callFrame->codeBlock();
401 Identifier& ident = codeBlock->identifier(property);
402 PropertySlot slot(globalObject);
403 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
404 JSValue* result = slot.getValue(callFrame, ident);
405 if (slot.isCacheable()) {
406 if (vPC[4].u.structure)
407 vPC[4].u.structure->deref();
408 globalObject->structure()->ref();
409 vPC[4] = globalObject->structure();
410 vPC[5] = slot.cachedOffset();
411 callFrame[dst] = result;
412 return true;
413 }
414
415 exceptionValue = callFrame->globalData().exception;
416 if (exceptionValue)
417 return false;
418 callFrame[dst] = result;
419 return true;
420 }
421
422 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
423 return false;
424}
425
426static ALWAYS_INLINE JSValue* inlineResolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain)
427{
428 ScopeChainIterator iter = scopeChain->begin();
429 ScopeChainIterator next = iter;
430 ++next;
431 ScopeChainIterator end = scopeChain->end();
432 ASSERT(iter != end);
433
434 PropertySlot slot;
435 JSObject* base;
436 while (true) {
437 base = *iter;
438 if (next == end || base->getPropertySlot(callFrame, property, slot))
439 return base;
440
441 iter = next;
442 ++next;
443 }
444
445 ASSERT_NOT_REACHED();
446 return noValue();
447}
448
449NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
450{
451 int dst = (vPC + 1)->u.operand;
452 int property = (vPC + 2)->u.operand;
453 callFrame[dst] = inlineResolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain());
454}
455
456NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue*& exceptionValue)
457{
458 int baseDst = (vPC + 1)->u.operand;
459 int propDst = (vPC + 2)->u.operand;
460 int property = (vPC + 3)->u.operand;
461
462 ScopeChainNode* scopeChain = callFrame->scopeChain();
463 ScopeChainIterator iter = scopeChain->begin();
464 ScopeChainIterator end = scopeChain->end();
465
466 // FIXME: add scopeDepthIsZero optimization
467
468 ASSERT(iter != end);
469
470 CodeBlock* codeBlock = callFrame->codeBlock();
471 Identifier& ident = codeBlock->identifier(property);
472 JSObject* base;
473 do {
474 base = *iter;
475 PropertySlot slot(base);
476 if (base->getPropertySlot(callFrame, ident, slot)) {
477 JSValue* result = slot.getValue(callFrame, ident);
478 exceptionValue = callFrame->globalData().exception;
479 if (exceptionValue)
480 return false;
481 callFrame[propDst] = result;
482 callFrame[baseDst] = base;
483 return true;
484 }
485 ++iter;
486 } while (iter != end);
487
488 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
489 return false;
490}
491
492NEVER_INLINE bool Interpreter::resolveBaseAndFunc(CallFrame* callFrame, Instruction* vPC, JSValue*& exceptionValue)
493{
494 int baseDst = (vPC + 1)->u.operand;
495 int funcDst = (vPC + 2)->u.operand;
496 int property = (vPC + 3)->u.operand;
497
498 ScopeChainNode* scopeChain = callFrame->scopeChain();
499 ScopeChainIterator iter = scopeChain->begin();
500 ScopeChainIterator end = scopeChain->end();
501
502 // FIXME: add scopeDepthIsZero optimization
503
504 ASSERT(iter != end);
505
506 CodeBlock* codeBlock = callFrame->codeBlock();
507 Identifier& ident = codeBlock->identifier(property);
508 JSObject* base;
509 do {
510 base = *iter;
511 PropertySlot slot(base);
512 if (base->getPropertySlot(callFrame, ident, slot)) {
513 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
514 // However, section 10.2.3 says that in the case where the value provided
515 // by the caller is null, the global object should be used. It also says
516 // that the section does not apply to internal functions, but for simplicity
517 // of implementation we use the global object anyway here. This guarantees
518 // that in host objects you always get a valid object for this.
519 // We also handle wrapper substitution for the global object at the same time.
520 JSObject* thisObj = base->toThisObject(callFrame);
521 JSValue* result = slot.getValue(callFrame, ident);
522 exceptionValue = callFrame->globalData().exception;
523 if (exceptionValue)
524 return false;
525
526 callFrame[baseDst] = thisObj;
527 callFrame[funcDst] = result;
528 return true;
529 }
530 ++iter;
531 } while (iter != end);
532
533 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC, codeBlock);
534 return false;
535}
536
537ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
538{
539 Register* r = callFrame->registers();
540 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters;
541
542 if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments
543 if (UNLIKELY(!registerFile->grow(newEnd)))
544 return 0;
545 r += registerOffset;
546 } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks
547 size_t omittedArgCount = newCodeBlock->m_numParameters - argc;
548 registerOffset += omittedArgCount;
549 newEnd += omittedArgCount;
550 if (!registerFile->grow(newEnd))
551 return 0;
552 r += registerOffset;
553
554 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
555 for (size_t i = 0; i < omittedArgCount; ++i)
556 argv[i] = jsUndefined();
557 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
558 size_t numParameters = newCodeBlock->m_numParameters;
559 registerOffset += numParameters;
560 newEnd += numParameters;
561
562 if (!registerFile->grow(newEnd))
563 return 0;
564 r += registerOffset;
565
566 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
567 for (size_t i = 0; i < numParameters; ++i)
568 argv[i + argc] = argv[i];
569 }
570
571 return CallFrame::create(r);
572}
573
574static NEVER_INLINE bool isNotObject(CallFrame* callFrame, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
575{
576 if (value->isObject())
577 return false;
578 exceptionData = createInvalidParamError(callFrame, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
579 return true;
580}
581
582NEVER_INLINE JSValue* Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue*& exceptionValue)
583{
584 if (argc < 2)
585 return jsUndefined();
586
587 JSValue* program = argv[1].jsValue(callFrame);
588
589 if (!program->isString())
590 return program;
591
592 UString programSource = asString(program)->value();
593
594 ScopeChainNode* scopeChain = callFrame->scopeChain();
595 CodeBlock* codeBlock = callFrame->codeBlock();
596 RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue);
597
598 JSValue* result = jsUndefined();
599 if (evalNode)
600 result = callFrame->globalData().interpreter->execute(evalNode.get(), callFrame, callFrame->thisValue()->toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue);
601
602 return result;
603}
604
605Interpreter::Interpreter()
606 : m_sampler(0)
607#if ENABLE(JIT)
608 , m_ctiArrayLengthTrampoline(0)
609 , m_ctiStringLengthTrampoline(0)
610 , m_ctiVirtualCallPreLink(0)
611 , m_ctiVirtualCallLink(0)
612 , m_ctiVirtualCall(0)
613#endif
614 , m_reentryDepth(0)
615 , m_timeoutTime(0)
616 , m_timeAtLastCheckTimeout(0)
617 , m_timeExecuting(0)
618 , m_timeoutCheckCount(0)
619 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
620{
621 initTimeout();
622 privateExecute(InitializeAndReturn, 0, 0, 0);
623
624 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
625 void* storage = fastMalloc(sizeof(CollectorBlock));
626
627 JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull()));
628 m_jsArrayVptr = jsArray->vptr();
629 jsArray->~JSCell();
630
631 JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
632 m_jsStringVptr = jsString->vptr();
633 jsString->~JSCell();
634
635 JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull()));
636 m_jsFunctionVptr = jsFunction->vptr();
637 jsFunction->~JSCell();
638
639 fastFree(storage);
640}
641
642void Interpreter::initialize(JSGlobalData* globalData)
643{
644#if ENABLE(JIT)
645 JIT::compileCTIMachineTrampolines(globalData);
646#else
647 UNUSED_PARAM(globalData);
648#endif
649}
650
651Interpreter::~Interpreter()
652{
653#if ENABLE(JIT)
654 JIT::freeCTIMachineTrampolines(this);
655#endif
656}
657
658#ifndef NDEBUG
659
660void Interpreter::dumpCallFrame(CallFrame* callFrame)
661{
662 callFrame->codeBlock()->dump(callFrame);
663 dumpRegisters(callFrame);
664}
665
666void Interpreter::dumpRegisters(CallFrame* callFrame)
667{
668 printf("Register frame: \n\n");
669 printf("----------------------------------------------------\n");
670 printf(" use | address | value \n");
671 printf("----------------------------------------------------\n");
672
673 CodeBlock* codeBlock = callFrame->codeBlock();
674 RegisterFile* registerFile = &callFrame->scopeChain()->globalObject()->globalData()->interpreter->registerFile();
675 const Register* it;
676 const Register* end;
677
678 if (codeBlock->codeType() == GlobalCode) {
679 it = registerFile->lastGlobal();
680 end = it + registerFile->numGlobals();
681 while (it != end) {
682 printf("[global var] | %10p | %10p \n", it, (*it).v());
683 ++it;
684 }
685 printf("----------------------------------------------------\n");
686 }
687
688 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters;
689 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
690 end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this"
691 if (it != end) {
692 do {
693 printf("[param] | %10p | %10p \n", it, (*it).v());
694 ++it;
695 } while (it != end);
696 }
697 printf("----------------------------------------------------\n");
698
699 printf("[CodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
700 printf("[ScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
701 printf("[CallerRegisters] | %10p | %10p \n", it, (*it).v()); ++it;
702 printf("[ReturnPC] | %10p | %10p \n", it, (*it).v()); ++it;
703 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
704 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
705 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
706 printf("[OptionalCalleeArguments] | %10p | %10p \n", it, (*it).v()); ++it;
707 printf("----------------------------------------------------\n");
708
709 int registerCount = 0;
710
711 end = it + codeBlock->m_numVars;
712 if (it != end) {
713 do {
714 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
715 ++it;
716 ++registerCount;
717 } while (it != end);
718 }
719 printf("----------------------------------------------------\n");
720
721 end = it + codeBlock->m_numConstants;
722 if (it != end) {
723 do {
724 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
725 ++it;
726 ++registerCount;
727 } while (it != end);
728 }
729 printf("----------------------------------------------------\n");
730
731 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numConstants - codeBlock->m_numVars;
732 if (it != end) {
733 do {
734 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v());
735 ++it;
736 ++registerCount;
737 } while (it != end);
738 }
739 printf("----------------------------------------------------\n");
740}
741
742#endif
743
744bool Interpreter::isOpcode(Opcode opcode)
745{
746#if HAVE(COMPUTED_GOTO)
747 return opcode != HashTraits<Opcode>::emptyValue()
748 && !HashTraits<Opcode>::isDeletedValue(opcode)
749 && m_opcodeIDTable.contains(opcode);
750#else
751 return opcode >= 0 && opcode <= op_end;
752#endif
753}
754
755NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock)
756{
757 CodeBlock* oldCodeBlock = codeBlock;
758 ScopeChainNode* scopeChain = callFrame->scopeChain();
759
760 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
761 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
762 if (callFrame->callee())
763 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine());
764 else
765 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine());
766 }
767
768 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
769 if (callFrame->callee())
770 profiler->didExecute(callFrame, callFrame->callee());
771 else
772 profiler->didExecute(callFrame, codeBlock->ownerNode()->sourceURL(), codeBlock->ownerNode()->lineNo());
773 }
774
775 // If this call frame created an activation or an 'arguments' object, tear it off.
776 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
777 while (!scopeChain->object->isObject(&JSActivation::info))
778 scopeChain = scopeChain->pop();
779 static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments());
780 } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) {
781 if (!arguments->isTornOff())
782 arguments->copyRegisters();
783 }
784
785 if (oldCodeBlock->needsFullScopeChain())
786 scopeChain->deref();
787
788 void* returnPC = callFrame->returnPC();
789 callFrame = callFrame->callerFrame();
790 if (callFrame->hasHostCallFrameFlag())
791 return false;
792
793 codeBlock = callFrame->codeBlock();
794 vPC = vPCForPC(codeBlock, returnPC);
795 return true;
796}
797
798NEVER_INLINE Instruction* Interpreter::throwException(CallFrame*& callFrame, JSValue*& exceptionValue, const Instruction* vPC, bool explicitThrow)
799{
800 // Set up the exception object
801
802 CodeBlock* codeBlock = callFrame->codeBlock();
803 if (exceptionValue->isObject()) {
804 JSObject* exception = asObject(exceptionValue);
805 if (exception->isNotAnObjectErrorStub()) {
806 exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
807 exceptionValue = exception;
808 } else {
809 if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) &&
810 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) &&
811 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) &&
812 !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) &&
813 !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) &&
814 !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) {
815 if (explicitThrow) {
816 int startOffset = 0;
817 int endOffset = 0;
818 int divotPoint = 0;
819 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
820 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete);
821
822 // We only hit this path for error messages and throw statements, which don't have a specific failure position
823 // So we just give the full range of the error/throw statement.
824 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete);
825 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete);
826 } else
827 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
828 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerNode()->sourceID()), ReadOnly | DontDelete);
829 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerNode()->sourceURL()), ReadOnly | DontDelete);
830 }
831
832 if (exception->isWatchdogException()) {
833 while (unwindCallFrame(callFrame, exceptionValue, vPC, codeBlock)) {
834 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
835 }
836 return 0;
837 }
838 }
839 }
840
841 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
842 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
843 debugger->exception(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->lineNumberForVPC(vPC));
844 }
845
846 // If we throw in the middle of a call instruction, we need to notify
847 // the profiler manually that the call instruction has returned, since
848 // we'll never reach the relevant op_profile_did_call.
849 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
850 if (isCallBytecode(vPC[0].u.opcode))
851 profiler->didExecute(callFrame, callFrame[vPC[2].u.operand].jsValue(callFrame));
852 else if (vPC[8].u.opcode == getOpcode(op_construct))
853 profiler->didExecute(callFrame, callFrame[vPC[10].u.operand].jsValue(callFrame));
854 }
855
856 // Calculate an exception handler vPC, unwinding call frames as necessary.
857
858 int scopeDepth;
859 Instruction* handlerVPC;
860
861 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
862 if (!unwindCallFrame(callFrame, exceptionValue, vPC, codeBlock))
863 return 0;
864 }
865
866 // Now unwind the scope chain within the exception handler's call frame.
867
868 ScopeChain sc(callFrame->scopeChain());
869 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
870 ASSERT(scopeDelta >= 0);
871 while (scopeDelta--)
872 sc.pop();
873 callFrame->setScopeChain(sc.node());
874
875 return handlerVPC;
876}
877
878class DynamicGlobalObjectScope : Noncopyable {
879public:
880 DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject)
881 : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject)
882 , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot)
883 {
884 m_dynamicGlobalObjectSlot = dynamicGlobalObject;
885 }
886
887 ~DynamicGlobalObjectScope()
888 {
889 m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
890 }
891
892private:
893 JSGlobalObject*& m_dynamicGlobalObjectSlot;
894 JSGlobalObject* m_savedDynamicGlobalObject;
895};
896
897JSValue* Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
898{
899 ASSERT(!scopeChain->globalData->exception);
900
901 if (m_reentryDepth >= MaxReentryDepth) {
902 *exception = createStackOverflowError(callFrame);
903 return jsNull();
904 }
905
906 CodeBlock* codeBlock = &programNode->bytecode(scopeChain);
907
908 Register* oldEnd = m_registerFile.end();
909 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
910 if (!m_registerFile.grow(newEnd)) {
911 *exception = createStackOverflowError(callFrame);
912 return jsNull();
913 }
914
915 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject());
916
917 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
918 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
919 globalObject->copyGlobalsTo(m_registerFile);
920
921 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
922 newCallFrame[codeBlock->thisRegister()] = thisObj;
923 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0);
924
925 if (codeBlock->needsFullScopeChain())
926 scopeChain->ref();
927
928 Profiler** profiler = Profiler::enabledProfilerReference();
929 if (*profiler)
930 (*profiler)->willExecute(newCallFrame, programNode->sourceURL(), programNode->lineNo());
931
932 JSValue* result;
933 {
934 SamplingTool::CallRecord callRecord(m_sampler);
935
936 m_reentryDepth++;
937#if ENABLE(JIT)
938 if (!codeBlock->jitCode())
939 JIT::compile(scopeChain->globalData, codeBlock);
940 result = JIT::execute(codeBlock->jitCode(), &m_registerFile, newCallFrame, scopeChain->globalData, exception);
941#else
942 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
943#endif
944 m_reentryDepth--;
945 }
946
947 if (*profiler)
948 (*profiler)->didExecute(callFrame, programNode->sourceURL(), programNode->lineNo());
949
950 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
951 lastGlobalObject->copyGlobalsTo(m_registerFile);
952
953 m_registerFile.shrink(oldEnd);
954
955 return result;
956}
957
958JSValue* Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
959{
960 ASSERT(!scopeChain->globalData->exception);
961
962 if (m_reentryDepth >= MaxReentryDepth) {
963 *exception = createStackOverflowError(callFrame);
964 return jsNull();
965 }
966
967 Register* oldEnd = m_registerFile.end();
968 int argc = 1 + args.size(); // implicit "this" parameter
969
970 if (!m_registerFile.grow(oldEnd + argc)) {
971 *exception = createStackOverflowError(callFrame);
972 return jsNull();
973 }
974
975 DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject());
976
977 CallFrame* newCallFrame = CallFrame::create(oldEnd);
978 size_t dst = 0;
979 newCallFrame[0] = thisObj;
980 ArgList::const_iterator end = args.end();
981 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
982 newCallFrame[++dst] = *it;
983
984 CodeBlock* codeBlock = &functionBodyNode->bytecode(scopeChain);
985 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
986 if (UNLIKELY(!newCallFrame)) {
987 *exception = createStackOverflowError(callFrame);
988 m_registerFile.shrink(oldEnd);
989 return jsNull();
990 }
991 // a 0 codeBlock indicates a built-in caller
992 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
993
994 Profiler** profiler = Profiler::enabledProfilerReference();
995 if (*profiler)
996 (*profiler)->willExecute(newCallFrame, function);
997
998 JSValue* result;
999 {
1000 SamplingTool::CallRecord callRecord(m_sampler);
1001
1002 m_reentryDepth++;
1003#if ENABLE(JIT)
1004 if (!codeBlock->jitCode())
1005 JIT::compile(scopeChain->globalData, codeBlock);
1006 result = JIT::execute(codeBlock->jitCode(), &m_registerFile, newCallFrame, scopeChain->globalData, exception);
1007#else
1008 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
1009#endif
1010 m_reentryDepth--;
1011 }
1012
1013 if (*profiler)
1014 (*profiler)->didExecute(newCallFrame, function);
1015
1016 m_registerFile.shrink(oldEnd);
1017 return result;
1018}
1019
1020JSValue* Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception)
1021{
1022 return execute(evalNode, callFrame, thisObj, m_registerFile.size() + evalNode->bytecode(scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
1023}
1024
1025JSValue* Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue** exception)
1026{
1027 ASSERT(!scopeChain->globalData->exception);
1028
1029 if (m_reentryDepth >= MaxReentryDepth) {
1030 *exception = createStackOverflowError(callFrame);
1031 return jsNull();
1032 }
1033
1034 DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject());
1035
1036 EvalCodeBlock* codeBlock = &evalNode->bytecode(scopeChain);
1037
1038 JSVariableObject* variableObject;
1039 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
1040 ASSERT(node);
1041 if (node->object->isVariableObject()) {
1042 variableObject = static_cast<JSVariableObject*>(node->object);
1043 break;
1044 }
1045 }
1046
1047 { // Scope for BatchedTransitionOptimizer
1048
1049 BatchedTransitionOptimizer optimizer(variableObject);
1050
1051 const DeclarationStacks::VarStack& varStack = codeBlock->ownerNode()->varStack();
1052 DeclarationStacks::VarStack::const_iterator varStackEnd = varStack.end();
1053 for (DeclarationStacks::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
1054 const Identifier& ident = (*it).first;
1055 if (!variableObject->hasProperty(callFrame, ident)) {
1056 PutPropertySlot slot;
1057 variableObject->put(callFrame, ident, jsUndefined(), slot);
1058 }
1059 }
1060
1061 const DeclarationStacks::FunctionStack& functionStack = codeBlock->ownerNode()->functionStack();
1062 DeclarationStacks::FunctionStack::const_iterator functionStackEnd = functionStack.end();
1063 for (DeclarationStacks::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
1064 PutPropertySlot slot;
1065 variableObject->put(callFrame, (*it)->m_ident, (*it)->makeFunction(callFrame, scopeChain), slot);
1066 }
1067
1068 }
1069
1070 Register* oldEnd = m_registerFile.end();
1071 Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
1072 if (!m_registerFile.grow(newEnd)) {
1073 *exception = createStackOverflowError(callFrame);
1074 return jsNull();
1075 }
1076
1077 CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
1078
1079 // a 0 codeBlock indicates a built-in caller
1080 newCallFrame[codeBlock->thisRegister()] = thisObj;
1081 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0);
1082
1083 if (codeBlock->needsFullScopeChain())
1084 scopeChain->ref();
1085
1086 Profiler** profiler = Profiler::enabledProfilerReference();
1087 if (*profiler)
1088 (*profiler)->willExecute(newCallFrame, evalNode->sourceURL(), evalNode->lineNo());
1089
1090 JSValue* result;
1091 {
1092 SamplingTool::CallRecord callRecord(m_sampler);
1093
1094 m_reentryDepth++;
1095#if ENABLE(JIT)
1096 if (!codeBlock->jitCode())
1097 JIT::compile(scopeChain->globalData, codeBlock);
1098 result = JIT::execute(codeBlock->jitCode(), &m_registerFile, newCallFrame, scopeChain->globalData, exception);
1099#else
1100 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
1101#endif
1102 m_reentryDepth--;
1103 }
1104
1105 if (*profiler)
1106 (*profiler)->didExecute(callFrame, evalNode->sourceURL(), evalNode->lineNo());
1107
1108 m_registerFile.shrink(oldEnd);
1109 return result;
1110}
1111
1112NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
1113{
1114 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
1115 if (!debugger)
1116 return;
1117
1118 switch (debugHookID) {
1119 case DidEnterCallFrame:
1120 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine);
1121 return;
1122 case WillLeaveCallFrame:
1123 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine);
1124 return;
1125 case WillExecuteStatement:
1126 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine);
1127 return;
1128 case WillExecuteProgram:
1129 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine);
1130 return;
1131 case DidExecuteProgram:
1132 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine);
1133 return;
1134 case DidReachBreakpoint:
1135 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine);
1136 return;
1137 }
1138}
1139
1140void Interpreter::resetTimeoutCheck()
1141{
1142 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1143 m_timeAtLastCheckTimeout = 0;
1144 m_timeExecuting = 0;
1145}
1146
1147// Returns the time the current thread has spent executing, in milliseconds.
1148static inline unsigned getCPUTime()
1149{
1150#if PLATFORM(DARWIN)
1151 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1152 thread_basic_info_data_t info;
1153
1154 // Get thread information
1155 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1156
1157 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1158 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1159
1160 return time;
1161#elif HAVE(SYS_TIME_H)
1162 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1163 struct timeval tv;
1164 gettimeofday(&tv, 0);
1165 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1166#elif PLATFORM(QT)
1167 QDateTime t = QDateTime::currentDateTime();
1168 return t.toTime_t() * 1000 + t.time().msec();
1169#elif PLATFORM(WIN_OS)
1170 union {
1171 FILETIME fileTime;
1172 unsigned long long fileTimeAsLong;
1173 } userTime, kernelTime;
1174
1175 // GetThreadTimes won't accept NULL arguments so we pass these even though
1176 // they're not used.
1177 FILETIME creationTime, exitTime;
1178
1179 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1180
1181 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1182#else
1183#error Platform does not have getCurrentTime function
1184#endif
1185}
1186
1187// We have to return a JSValue here, gcc seems to produce worse code if
1188// we attempt to return a bool
1189ALWAYS_INLINE JSValue* Interpreter::checkTimeout(JSGlobalObject* globalObject)
1190{
1191 unsigned currentTime = getCPUTime();
1192
1193 if (!m_timeAtLastCheckTimeout) {
1194 // Suspicious amount of looping in a script -- start timing it
1195 m_timeAtLastCheckTimeout = currentTime;
1196 return noValue();
1197 }
1198
1199 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1200
1201 if (timeDiff == 0)
1202 timeDiff = 1;
1203
1204 m_timeExecuting += timeDiff;
1205 m_timeAtLastCheckTimeout = currentTime;
1206
1207 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1208 // preferredScriptCheckTimeInterval
1209 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1210 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1211 // preferred script check time interval.
1212 if (m_ticksUntilNextTimeoutCheck == 0)
1213 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1214
1215 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1216 if (globalObject->shouldInterruptScript())
1217 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1218
1219 resetTimeoutCheck();
1220 }
1221
1222 return noValue();
1223}
1224
1225NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
1226{
1227 int dst = (++vPC)->u.operand;
1228 CodeBlock* codeBlock = callFrame->codeBlock();
1229 Identifier& property = codeBlock->identifier((++vPC)->u.operand);
1230 JSValue* value = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1231 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
1232 callFrame[dst] = scope;
1233
1234 return callFrame->scopeChain()->push(scope);
1235}
1236
1237static StructureChain* cachePrototypeChain(CallFrame* callFrame, Structure* structure)
1238{
1239 JSValue* prototype = structure->prototypeForLookup(callFrame);
1240 if (JSImmediate::isImmediate(prototype))
1241 return 0;
1242 RefPtr<StructureChain> chain = StructureChain::create(asObject(prototype)->structure());
1243 structure->setCachedPrototypeChain(chain.release());
1244 return structure->cachedPrototypeChain();
1245}
1246
1247NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1248{
1249 // Recursive invocation may already have specialized this instruction.
1250 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1251 return;
1252
1253 if (JSImmediate::isImmediate(baseValue))
1254 return;
1255
1256 // Uncacheable: give up.
1257 if (!slot.isCacheable()) {
1258 vPC[0] = getOpcode(op_put_by_id_generic);
1259 return;
1260 }
1261
1262 JSCell* baseCell = asCell(baseValue);
1263 Structure* structure = baseCell->structure();
1264
1265 if (structure->isDictionary()) {
1266 vPC[0] = getOpcode(op_put_by_id_generic);
1267 return;
1268 }
1269
1270 // Cache miss: record Structure to compare against next time.
1271 Structure* lastStructure = vPC[4].u.structure;
1272 if (structure != lastStructure) {
1273 // First miss: record Structure to compare against next time.
1274 if (!lastStructure) {
1275 vPC[4] = structure;
1276 return;
1277 }
1278
1279 // Second miss: give up.
1280 vPC[0] = getOpcode(op_put_by_id_generic);
1281 return;
1282 }
1283
1284 // Cache hit: Specialize instruction and ref Structures.
1285
1286 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1287 if (baseCell != slot.base()) {
1288 vPC[0] = getOpcode(op_put_by_id_generic);
1289 return;
1290 }
1291
1292 // Structure transition, cache transition info
1293 if (slot.type() == PutPropertySlot::NewProperty) {
1294 vPC[0] = getOpcode(op_put_by_id_transition);
1295 vPC[4] = structure->previousID();
1296 vPC[5] = structure;
1297 StructureChain* chain = structure->cachedPrototypeChain();
1298 if (!chain) {
1299 chain = cachePrototypeChain(callFrame, structure);
1300 if (!chain) {
1301 // This happens if someone has manually inserted null into the prototype chain
1302 vPC[0] = getOpcode(op_put_by_id_generic);
1303 return;
1304 }
1305 }
1306 vPC[6] = chain;
1307 vPC[7] = slot.cachedOffset();
1308 codeBlock->refStructures(vPC);
1309 return;
1310 }
1311
1312 vPC[0] = getOpcode(op_put_by_id_replace);
1313 vPC[5] = slot.cachedOffset();
1314 codeBlock->refStructures(vPC);
1315}
1316
1317NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1318{
1319 codeBlock->derefStructures(vPC);
1320 vPC[0] = getOpcode(op_put_by_id);
1321 vPC[4] = 0;
1322}
1323
1324static size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValue* baseValue, const PropertySlot& slot)
1325{
1326 JSObject* o = asObject(baseValue);
1327 size_t count = 0;
1328
1329 while (slot.slotBase() != o) {
1330 JSValue* v = o->structure()->prototypeForLookup(callFrame);
1331
1332 // If we didn't find slotBase in baseValue's prototype chain, then baseValue
1333 // must be a proxy for another object.
1334
1335 if (v->isNull())
1336 return 0;
1337
1338 o = asObject(v);
1339
1340 // Heavy access to a prototype is a good indication that it's not being
1341 // used as a dictionary.
1342 if (o->structure()->isDictionary()) {
1343 RefPtr<Structure> transition = Structure::fromDictionaryTransition(o->structure());
1344 o->setStructure(transition.release());
1345 asObject(baseValue)->structure()->setCachedPrototypeChain(0);
1346 }
1347
1348 ++count;
1349 }
1350
1351 ASSERT(count);
1352 return count;
1353}
1354
1355NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1356{
1357 // Recursive invocation may already have specialized this instruction.
1358 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1359 return;
1360
1361 // FIXME: Cache property access for immediates.
1362 if (JSImmediate::isImmediate(baseValue)) {
1363 vPC[0] = getOpcode(op_get_by_id_generic);
1364 return;
1365 }
1366
1367 if (isJSArray(baseValue) && propertyName == callFrame->propertyNames().length) {
1368 vPC[0] = getOpcode(op_get_array_length);
1369 return;
1370 }
1371
1372 if (isJSString(baseValue) && propertyName == callFrame->propertyNames().length) {
1373 vPC[0] = getOpcode(op_get_string_length);
1374 return;
1375 }
1376
1377 // Uncacheable: give up.
1378 if (!slot.isCacheable()) {
1379 vPC[0] = getOpcode(op_get_by_id_generic);
1380 return;
1381 }
1382
1383 Structure* structure = asCell(baseValue)->structure();
1384
1385 if (structure->isDictionary()) {
1386 vPC[0] = getOpcode(op_get_by_id_generic);
1387 return;
1388 }
1389
1390 // Cache miss
1391 Structure* lastStructure = vPC[4].u.structure;
1392 if (structure != lastStructure) {
1393 // First miss: record Structure to compare against next time.
1394 if (!lastStructure) {
1395 vPC[4] = structure;
1396 return;
1397 }
1398
1399 // Second miss: give up.
1400 vPC[0] = getOpcode(op_get_by_id_generic);
1401 return;
1402 }
1403
1404 // Cache hit: Specialize instruction and ref Structures.
1405
1406 if (slot.slotBase() == baseValue) {
1407 vPC[0] = getOpcode(op_get_by_id_self);
1408 vPC[5] = slot.cachedOffset();
1409
1410 codeBlock->refStructures(vPC);
1411 return;
1412 }
1413
1414 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
1415 ASSERT(slot.slotBase()->isObject());
1416
1417 JSObject* baseObject = asObject(slot.slotBase());
1418
1419 // Heavy access to a prototype is a good indication that it's not being
1420 // used as a dictionary.
1421 if (baseObject->structure()->isDictionary()) {
1422 RefPtr<Structure> transition = Structure::fromDictionaryTransition(baseObject->structure());
1423 baseObject->setStructure(transition.release());
1424 asCell(baseValue)->structure()->setCachedPrototypeChain(0);
1425 }
1426
1427 vPC[0] = getOpcode(op_get_by_id_proto);
1428 vPC[5] = baseObject->structure();
1429 vPC[6] = slot.cachedOffset();
1430
1431 codeBlock->refStructures(vPC);
1432 return;
1433 }
1434
1435 size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);
1436 if (!count) {
1437 vPC[0] = getOpcode(op_get_by_id_generic);
1438 return;
1439 }
1440
1441 StructureChain* chain = structure->cachedPrototypeChain();
1442 if (!chain)
1443 chain = cachePrototypeChain(callFrame, structure);
1444 ASSERT(chain);
1445
1446 vPC[0] = getOpcode(op_get_by_id_chain);
1447 vPC[4] = structure;
1448 vPC[5] = chain;
1449 vPC[6] = count;
1450 vPC[7] = slot.cachedOffset();
1451 codeBlock->refStructures(vPC);
1452}
1453
1454NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1455{
1456 codeBlock->derefStructures(vPC);
1457 vPC[0] = getOpcode(op_get_by_id);
1458 vPC[4] = 0;
1459}
1460
1461JSValue* Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValue** exception)
1462{
1463 // One-time initialization of our address tables. We have to put this code
1464 // here because our labels are only in scope inside this function.
1465 if (flag == InitializeAndReturn) {
1466 #if HAVE(COMPUTED_GOTO)
1467 #define ADD_BYTECODE(id) m_opcodeTable[id] = &&id;
1468 FOR_EACH_OPCODE_ID(ADD_BYTECODE);
1469 #undef ADD_BYTECODE
1470
1471 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1472 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1473 #undef ADD_OPCODE_ID
1474 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1475 #endif // HAVE(COMPUTED_GOTO)
1476 return noValue();
1477 }
1478
1479#if ENABLE(JIT)
1480 // Currently with CTI enabled we never interpret functions
1481 ASSERT_NOT_REACHED();
1482#endif
1483
1484 JSGlobalData* globalData = &callFrame->globalData();
1485 JSValue* exceptionValue = noValue();
1486 Instruction* handlerVPC = 0;
1487
1488 Instruction* vPC = callFrame->codeBlock()->instructions().begin();
1489 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1490 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1491
1492#define CHECK_FOR_EXCEPTION() \
1493 do { \
1494 if (UNLIKELY(globalData->exception != noValue())) { \
1495 exceptionValue = globalData->exception; \
1496 goto vm_throw; \
1497 } \
1498 } while (0)
1499
1500#if ENABLE(OPCODE_STATS)
1501 OpcodeStats::resetLastInstruction();
1502#endif
1503
1504#define CHECK_FOR_TIMEOUT() \
1505 if (!--tickCount) { \
1506 if ((exceptionValue = checkTimeout(callFrame->dynamicGlobalObject()))) \
1507 goto vm_throw; \
1508 tickCount = m_ticksUntilNextTimeoutCheck; \
1509 }
1510
1511#if ENABLE(OPCODE_SAMPLING)
1512 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1513 #define CTI_SAMPLER ARG_globalData->interpreter->sampler()
1514#else
1515 #define SAMPLE(codeBlock, vPC)
1516 #define CTI_SAMPLER 0
1517#endif
1518
1519#if HAVE(COMPUTED_GOTO)
1520 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
1521#if ENABLE(OPCODE_STATS)
1522 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1523#else
1524 #define DEFINE_OPCODE(opcode) opcode:
1525#endif
1526 NEXT_INSTRUCTION();
1527#else
1528 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
1529#if ENABLE(OPCODE_STATS)
1530 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1531#else
1532 #define DEFINE_OPCODE(opcode) case opcode:
1533#endif
1534 while (1) { // iterator loop begins
1535 interpreterLoopStart:;
1536 switch (vPC->u.opcode)
1537#endif
1538 {
1539 DEFINE_OPCODE(op_new_object) {
1540 /* new_object dst(r)
1541
1542 Constructs a new empty Object instance using the original
1543 constructor, and puts the result in register dst.
1544 */
1545 int dst = (++vPC)->u.operand;
1546 callFrame[dst] = constructEmptyObject(callFrame);
1547
1548 ++vPC;
1549 NEXT_INSTRUCTION();
1550 }
1551 DEFINE_OPCODE(op_new_array) {
1552 /* new_array dst(r) firstArg(r) argCount(n)
1553
1554 Constructs a new Array instance using the original
1555 constructor, and puts the result in register dst.
1556 The array will contain argCount elements with values
1557 taken from registers starting at register firstArg.
1558 */
1559 int dst = (++vPC)->u.operand;
1560 int firstArg = (++vPC)->u.operand;
1561 int argCount = (++vPC)->u.operand;
1562 ArgList args(callFrame->registers() + firstArg, argCount);
1563 callFrame[dst] = constructArray(callFrame, args);
1564
1565 ++vPC;
1566 NEXT_INSTRUCTION();
1567 }
1568 DEFINE_OPCODE(op_new_regexp) {
1569 /* new_regexp dst(r) regExp(re)
1570
1571 Constructs a new RegExp instance using the original
1572 constructor from regexp regExp, and puts the result in
1573 register dst.
1574 */
1575 int dst = (++vPC)->u.operand;
1576 int regExp = (++vPC)->u.operand;
1577 callFrame[dst] = new (globalData) RegExpObject(callFrame->scopeChain()->globalObject()->regExpStructure(), callFrame->codeBlock()->regexp(regExp));
1578
1579 ++vPC;
1580 NEXT_INSTRUCTION();
1581 }
1582 DEFINE_OPCODE(op_mov) {
1583 /* mov dst(r) src(r)
1584
1585 Copies register src to register dst.
1586 */
1587 int dst = (++vPC)->u.operand;
1588 int src = (++vPC)->u.operand;
1589 callFrame[dst] = callFrame[src];
1590
1591 ++vPC;
1592 NEXT_INSTRUCTION();
1593 }
1594 DEFINE_OPCODE(op_eq) {
1595 /* eq dst(r) src1(r) src2(r)
1596
1597 Checks whether register src1 and register src2 are equal,
1598 as with the ECMAScript '==' operator, and puts the result
1599 as a boolean in register dst.
1600 */
1601 int dst = (++vPC)->u.operand;
1602 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1603 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1604 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1605 callFrame[dst] = jsBoolean(src1 == src2);
1606 else {
1607 JSValue* result = jsBoolean(equalSlowCase(callFrame, src1, src2));
1608 CHECK_FOR_EXCEPTION();
1609 callFrame[dst] = result;
1610 }
1611
1612 ++vPC;
1613 NEXT_INSTRUCTION();
1614 }
1615 DEFINE_OPCODE(op_eq_null) {
1616 /* eq_null dst(r) src(r)
1617
1618 Checks whether register src is null, as with the ECMAScript '!='
1619 operator, and puts the result as a boolean in register dst.
1620 */
1621 int dst = (++vPC)->u.operand;
1622 JSValue* src = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1623
1624 if (src->isUndefinedOrNull()) {
1625 callFrame[dst] = jsBoolean(true);
1626 ++vPC;
1627 NEXT_INSTRUCTION();
1628 }
1629
1630 callFrame[dst] = jsBoolean(!JSImmediate::isImmediate(src) && src->asCell()->structure()->typeInfo().masqueradesAsUndefined());
1631 ++vPC;
1632 NEXT_INSTRUCTION();
1633 }
1634 DEFINE_OPCODE(op_neq) {
1635 /* neq dst(r) src1(r) src2(r)
1636
1637 Checks whether register src1 and register src2 are not
1638 equal, as with the ECMAScript '!=' operator, and puts the
1639 result as a boolean in register dst.
1640 */
1641 int dst = (++vPC)->u.operand;
1642 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1643 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1644 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1645 callFrame[dst] = jsBoolean(src1 != src2);
1646 else {
1647 JSValue* result = jsBoolean(!equalSlowCase(callFrame, src1, src2));
1648 CHECK_FOR_EXCEPTION();
1649 callFrame[dst] = result;
1650 }
1651
1652 ++vPC;
1653 NEXT_INSTRUCTION();
1654 }
1655 DEFINE_OPCODE(op_neq_null) {
1656 /* neq_null dst(r) src(r)
1657
1658 Checks whether register src is not null, as with the ECMAScript '!='
1659 operator, and puts the result as a boolean in register dst.
1660 */
1661 int dst = (++vPC)->u.operand;
1662 JSValue* src = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1663
1664 if (src->isUndefinedOrNull()) {
1665 callFrame[dst] = jsBoolean(false);
1666 ++vPC;
1667 NEXT_INSTRUCTION();
1668 }
1669
1670 callFrame[dst] = jsBoolean(JSImmediate::isImmediate(src) || !asCell(src)->structure()->typeInfo().masqueradesAsUndefined());
1671 ++vPC;
1672 NEXT_INSTRUCTION();
1673 }
1674 DEFINE_OPCODE(op_stricteq) {
1675 /* stricteq dst(r) src1(r) src2(r)
1676
1677 Checks whether register src1 and register src2 are strictly
1678 equal, as with the ECMAScript '===' operator, and puts the
1679 result as a boolean in register dst.
1680 */
1681 int dst = (++vPC)->u.operand;
1682 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1683 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1684 if (JSImmediate::areBothImmediate(src1, src2))
1685 callFrame[dst] = jsBoolean(src1 == src2);
1686 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1687 callFrame[dst] = jsBoolean(false);
1688 else
1689 callFrame[dst] = jsBoolean(strictEqualSlowCase(src1, src2));
1690
1691 ++vPC;
1692 NEXT_INSTRUCTION();
1693 }
1694 DEFINE_OPCODE(op_nstricteq) {
1695 /* nstricteq dst(r) src1(r) src2(r)
1696
1697 Checks whether register src1 and register src2 are not
1698 strictly equal, as with the ECMAScript '!==' operator, and
1699 puts the result as a boolean in register dst.
1700 */
1701 int dst = (++vPC)->u.operand;
1702 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1703 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1704
1705 if (JSImmediate::areBothImmediate(src1, src2))
1706 callFrame[dst] = jsBoolean(src1 != src2);
1707 else if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
1708 callFrame[dst] = jsBoolean(true);
1709 else
1710 callFrame[dst] = jsBoolean(!strictEqualSlowCase(src1, src2));
1711
1712 ++vPC;
1713 NEXT_INSTRUCTION();
1714 }
1715 DEFINE_OPCODE(op_less) {
1716 /* less dst(r) src1(r) src2(r)
1717
1718 Checks whether register src1 is less than register src2, as
1719 with the ECMAScript '<' operator, and puts the result as
1720 a boolean in register dst.
1721 */
1722 int dst = (++vPC)->u.operand;
1723 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1724 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1725 JSValue* result = jsBoolean(jsLess(callFrame, src1, src2));
1726 CHECK_FOR_EXCEPTION();
1727 callFrame[dst] = result;
1728
1729 ++vPC;
1730 NEXT_INSTRUCTION();
1731 }
1732 DEFINE_OPCODE(op_lesseq) {
1733 /* lesseq dst(r) src1(r) src2(r)
1734
1735 Checks whether register src1 is less than or equal to
1736 register src2, as with the ECMAScript '<=' operator, and
1737 puts the result as a boolean in register dst.
1738 */
1739 int dst = (++vPC)->u.operand;
1740 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1741 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1742 JSValue* result = jsBoolean(jsLessEq(callFrame, src1, src2));
1743 CHECK_FOR_EXCEPTION();
1744 callFrame[dst] = result;
1745
1746 ++vPC;
1747 NEXT_INSTRUCTION();
1748 }
1749 DEFINE_OPCODE(op_pre_inc) {
1750 /* pre_inc srcDst(r)
1751
1752 Converts register srcDst to number, adds one, and puts the result
1753 back in register srcDst.
1754 */
1755 int srcDst = (++vPC)->u.operand;
1756 JSValue* v = callFrame[srcDst].jsValue(callFrame);
1757 if (JSImmediate::canDoFastAdditiveOperations(v))
1758 callFrame[srcDst] = JSImmediate::incImmediateNumber(v);
1759 else {
1760 JSValue* result = jsNumber(callFrame, v->toNumber(callFrame) + 1);
1761 CHECK_FOR_EXCEPTION();
1762 callFrame[srcDst] = result;
1763 }
1764
1765 ++vPC;
1766 NEXT_INSTRUCTION();
1767 }
1768 DEFINE_OPCODE(op_pre_dec) {
1769 /* pre_dec srcDst(r)
1770
1771 Converts register srcDst to number, subtracts one, and puts the result
1772 back in register srcDst.
1773 */
1774 int srcDst = (++vPC)->u.operand;
1775 JSValue* v = callFrame[srcDst].jsValue(callFrame);
1776 if (JSImmediate::canDoFastAdditiveOperations(v))
1777 callFrame[srcDst] = JSImmediate::decImmediateNumber(v);
1778 else {
1779 JSValue* result = jsNumber(callFrame, v->toNumber(callFrame) - 1);
1780 CHECK_FOR_EXCEPTION();
1781 callFrame[srcDst] = result;
1782 }
1783
1784 ++vPC;
1785 NEXT_INSTRUCTION();
1786 }
1787 DEFINE_OPCODE(op_post_inc) {
1788 /* post_inc dst(r) srcDst(r)
1789
1790 Converts register srcDst to number. The number itself is
1791 written to register dst, and the number plus one is written
1792 back to register srcDst.
1793 */
1794 int dst = (++vPC)->u.operand;
1795 int srcDst = (++vPC)->u.operand;
1796 JSValue* v = callFrame[srcDst].jsValue(callFrame);
1797 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1798 callFrame[dst] = v;
1799 callFrame[srcDst] = JSImmediate::incImmediateNumber(v);
1800 } else {
1801 JSValue* number = callFrame[srcDst].jsValue(callFrame)->toJSNumber(callFrame);
1802 CHECK_FOR_EXCEPTION();
1803 callFrame[dst] = number;
1804 callFrame[srcDst] = jsNumber(callFrame, number->uncheckedGetNumber() + 1);
1805 }
1806
1807 ++vPC;
1808 NEXT_INSTRUCTION();
1809 }
1810 DEFINE_OPCODE(op_post_dec) {
1811 /* post_dec dst(r) srcDst(r)
1812
1813 Converts register srcDst to number. The number itself is
1814 written to register dst, and the number minus one is written
1815 back to register srcDst.
1816 */
1817 int dst = (++vPC)->u.operand;
1818 int srcDst = (++vPC)->u.operand;
1819 JSValue* v = callFrame[srcDst].jsValue(callFrame);
1820 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1821 callFrame[dst] = v;
1822 callFrame[srcDst] = JSImmediate::decImmediateNumber(v);
1823 } else {
1824 JSValue* number = callFrame[srcDst].jsValue(callFrame)->toJSNumber(callFrame);
1825 CHECK_FOR_EXCEPTION();
1826 callFrame[dst] = number;
1827 callFrame[srcDst] = jsNumber(callFrame, number->uncheckedGetNumber() - 1);
1828 }
1829
1830 ++vPC;
1831 NEXT_INSTRUCTION();
1832 }
1833 DEFINE_OPCODE(op_to_jsnumber) {
1834 /* to_jsnumber dst(r) src(r)
1835
1836 Converts register src to number, and puts the result
1837 in register dst.
1838 */
1839 int dst = (++vPC)->u.operand;
1840 int src = (++vPC)->u.operand;
1841
1842 JSValue* srcVal = callFrame[src].jsValue(callFrame);
1843
1844 if (LIKELY(srcVal->isNumber()))
1845 callFrame[dst] = callFrame[src];
1846 else {
1847 JSValue* result = srcVal->toJSNumber(callFrame);
1848 CHECK_FOR_EXCEPTION();
1849 callFrame[dst] = result;
1850 }
1851
1852 ++vPC;
1853 NEXT_INSTRUCTION();
1854 }
1855 DEFINE_OPCODE(op_negate) {
1856 /* negate dst(r) src(r)
1857
1858 Converts register src to number, negates it, and puts the
1859 result in register dst.
1860 */
1861 int dst = (++vPC)->u.operand;
1862 JSValue* src = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1863 ++vPC;
1864 double v;
1865 if (fastIsNumber(src, v))
1866 callFrame[dst] = jsNumber(callFrame, -v);
1867 else {
1868 JSValue* result = jsNumber(callFrame, -src->toNumber(callFrame));
1869 CHECK_FOR_EXCEPTION();
1870 callFrame[dst] = result;
1871 }
1872
1873 NEXT_INSTRUCTION();
1874 }
1875 DEFINE_OPCODE(op_add) {
1876 /* add dst(r) src1(r) src2(r)
1877
1878 Adds register src1 and register src2, and puts the result
1879 in register dst. (JS add may be string concatenation or
1880 numeric add, depending on the types of the operands.)
1881 */
1882 int dst = (++vPC)->u.operand;
1883 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1884 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1885 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1886 callFrame[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1887 else {
1888 JSValue* result = jsAdd(callFrame, src1, src2);
1889 CHECK_FOR_EXCEPTION();
1890 callFrame[dst] = result;
1891 }
1892 vPC += 2;
1893 NEXT_INSTRUCTION();
1894 }
1895 DEFINE_OPCODE(op_mul) {
1896 /* mul dst(r) src1(r) src2(r)
1897
1898 Multiplies register src1 and register src2 (converted to
1899 numbers), and puts the product in register dst.
1900 */
1901 int dst = (++vPC)->u.operand;
1902 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1903 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1904 double left;
1905 double right;
1906 if (JSImmediate::areBothImmediateNumbers(src1, src2)) {
1907 int32_t left = JSImmediate::getTruncatedInt32(src1);
1908 int32_t right = JSImmediate::getTruncatedInt32(src2);
1909 if ((left | right) >> 15 == 0)
1910 callFrame[dst] = jsNumber(callFrame, left * right);
1911 else
1912 callFrame[dst] = jsNumber(callFrame, static_cast<double>(left) * static_cast<double>(right));
1913 } else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1914 callFrame[dst] = jsNumber(callFrame, left * right);
1915 else {
1916 JSValue* result = jsNumber(callFrame, src1->toNumber(callFrame) * src2->toNumber(callFrame));
1917 CHECK_FOR_EXCEPTION();
1918 callFrame[dst] = result;
1919 }
1920
1921 vPC += 2;
1922 NEXT_INSTRUCTION();
1923 }
1924 DEFINE_OPCODE(op_div) {
1925 /* div dst(r) dividend(r) divisor(r)
1926
1927 Divides register dividend (converted to number) by the
1928 register divisor (converted to number), and puts the
1929 quotient in register dst.
1930 */
1931 int dst = (++vPC)->u.operand;
1932 JSValue* dividend = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1933 JSValue* divisor = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1934 double left;
1935 double right;
1936 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1937 callFrame[dst] = jsNumber(callFrame, left / right);
1938 else {
1939 JSValue* result = jsNumber(callFrame, dividend->toNumber(callFrame) / divisor->toNumber(callFrame));
1940 CHECK_FOR_EXCEPTION();
1941 callFrame[dst] = result;
1942 }
1943 ++vPC;
1944 NEXT_INSTRUCTION();
1945 }
1946 DEFINE_OPCODE(op_mod) {
1947 /* mod dst(r) dividend(r) divisor(r)
1948
1949 Divides register dividend (converted to number) by
1950 register divisor (converted to number), and puts the
1951 remainder in register dst.
1952 */
1953 int dst = (++vPC)->u.operand;
1954 int dividend = (++vPC)->u.operand;
1955 int divisor = (++vPC)->u.operand;
1956
1957 JSValue* dividendValue = callFrame[dividend].jsValue(callFrame);
1958 JSValue* divisorValue = callFrame[divisor].jsValue(callFrame);
1959
1960 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1961 callFrame[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1962 ++vPC;
1963 NEXT_INSTRUCTION();
1964 }
1965
1966 double d = dividendValue->toNumber(callFrame);
1967 JSValue* result = jsNumber(callFrame, fmod(d, divisorValue->toNumber(callFrame)));
1968 CHECK_FOR_EXCEPTION();
1969 callFrame[dst] = result;
1970 ++vPC;
1971 NEXT_INSTRUCTION();
1972 }
1973 DEFINE_OPCODE(op_sub) {
1974 /* sub dst(r) src1(r) src2(r)
1975
1976 Subtracts register src2 (converted to number) from register
1977 src1 (converted to number), and puts the difference in
1978 register dst.
1979 */
1980 int dst = (++vPC)->u.operand;
1981 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1982 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
1983 double left;
1984 double right;
1985 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1986 callFrame[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1987 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1988 callFrame[dst] = jsNumber(callFrame, left - right);
1989 else {
1990 JSValue* result = jsNumber(callFrame, src1->toNumber(callFrame) - src2->toNumber(callFrame));
1991 CHECK_FOR_EXCEPTION();
1992 callFrame[dst] = result;
1993 }
1994 vPC += 2;
1995 NEXT_INSTRUCTION();
1996 }
1997 DEFINE_OPCODE(op_lshift) {
1998 /* lshift dst(r) val(r) shift(r)
1999
2000 Performs left shift of register val (converted to int32) by
2001 register shift (converted to uint32), and puts the result
2002 in register dst.
2003 */
2004 int dst = (++vPC)->u.operand;
2005 JSValue* val = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2006 JSValue* shift = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2007 int32_t left;
2008 uint32_t right;
2009 if (JSImmediate::areBothImmediateNumbers(val, shift))
2010 callFrame[dst] = jsNumber(callFrame, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
2011 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
2012 callFrame[dst] = jsNumber(callFrame, left << (right & 0x1f));
2013 else {
2014 JSValue* result = jsNumber(callFrame, (val->toInt32(callFrame)) << (shift->toUInt32(callFrame) & 0x1f));
2015 CHECK_FOR_EXCEPTION();
2016 callFrame[dst] = result;
2017 }
2018
2019 ++vPC;
2020 NEXT_INSTRUCTION();
2021 }
2022 DEFINE_OPCODE(op_rshift) {
2023 /* rshift dst(r) val(r) shift(r)
2024
2025 Performs arithmetic right shift of register val (converted
2026 to int32) by register shift (converted to
2027 uint32), and puts the result in register dst.
2028 */
2029 int dst = (++vPC)->u.operand;
2030 JSValue* val = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2031 JSValue* shift = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2032 int32_t left;
2033 uint32_t right;
2034 if (JSImmediate::areBothImmediateNumbers(val, shift))
2035 callFrame[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
2036 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
2037 callFrame[dst] = jsNumber(callFrame, left >> (right & 0x1f));
2038 else {
2039 JSValue* result = jsNumber(callFrame, (val->toInt32(callFrame)) >> (shift->toUInt32(callFrame) & 0x1f));
2040 CHECK_FOR_EXCEPTION();
2041 callFrame[dst] = result;
2042 }
2043
2044 ++vPC;
2045 NEXT_INSTRUCTION();
2046 }
2047 DEFINE_OPCODE(op_urshift) {
2048 /* rshift dst(r) val(r) shift(r)
2049
2050 Performs logical right shift of register val (converted
2051 to uint32) by register shift (converted to
2052 uint32), and puts the result in register dst.
2053 */
2054 int dst = (++vPC)->u.operand;
2055 JSValue* val = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2056 JSValue* shift = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2057 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
2058 callFrame[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
2059 else {
2060 JSValue* result = jsNumber(callFrame, (val->toUInt32(callFrame)) >> (shift->toUInt32(callFrame) & 0x1f));
2061 CHECK_FOR_EXCEPTION();
2062 callFrame[dst] = result;
2063 }
2064
2065 ++vPC;
2066 NEXT_INSTRUCTION();
2067 }
2068 DEFINE_OPCODE(op_bitand) {
2069 /* bitand dst(r) src1(r) src2(r)
2070
2071 Computes bitwise AND of register src1 (converted to int32)
2072 and register src2 (converted to int32), and puts the result
2073 in register dst.
2074 */
2075 int dst = (++vPC)->u.operand;
2076 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2077 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2078 int32_t left;
2079 int32_t right;
2080 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2081 callFrame[dst] = JSImmediate::andImmediateNumbers(src1, src2);
2082 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2083 callFrame[dst] = jsNumber(callFrame, left & right);
2084 else {
2085 JSValue* result = jsNumber(callFrame, src1->toInt32(callFrame) & src2->toInt32(callFrame));
2086 CHECK_FOR_EXCEPTION();
2087 callFrame[dst] = result;
2088 }
2089
2090 vPC += 2;
2091 NEXT_INSTRUCTION();
2092 }
2093 DEFINE_OPCODE(op_bitxor) {
2094 /* bitxor dst(r) src1(r) src2(r)
2095
2096 Computes bitwise XOR of register src1 (converted to int32)
2097 and register src2 (converted to int32), and puts the result
2098 in register dst.
2099 */
2100 int dst = (++vPC)->u.operand;
2101 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2102 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2103 int32_t left;
2104 int32_t right;
2105 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2106 callFrame[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
2107 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2108 callFrame[dst] = jsNumber(callFrame, left ^ right);
2109 else {
2110 JSValue* result = jsNumber(callFrame, src1->toInt32(callFrame) ^ src2->toInt32(callFrame));
2111 CHECK_FOR_EXCEPTION();
2112 callFrame[dst] = result;
2113 }
2114
2115 vPC += 2;
2116 NEXT_INSTRUCTION();
2117 }
2118 DEFINE_OPCODE(op_bitor) {
2119 /* bitor dst(r) src1(r) src2(r)
2120
2121 Computes bitwise OR of register src1 (converted to int32)
2122 and register src2 (converted to int32), and puts the
2123 result in register dst.
2124 */
2125 int dst = (++vPC)->u.operand;
2126 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2127 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2128 int32_t left;
2129 int32_t right;
2130 if (JSImmediate::areBothImmediateNumbers(src1, src2))
2131 callFrame[dst] = JSImmediate::orImmediateNumbers(src1, src2);
2132 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
2133 callFrame[dst] = jsNumber(callFrame, left | right);
2134 else {
2135 JSValue* result = jsNumber(callFrame, src1->toInt32(callFrame) | src2->toInt32(callFrame));
2136 CHECK_FOR_EXCEPTION();
2137 callFrame[dst] = result;
2138 }
2139
2140 vPC += 2;
2141 NEXT_INSTRUCTION();
2142 }
2143 DEFINE_OPCODE(op_bitnot) {
2144 /* bitnot dst(r) src(r)
2145
2146 Computes bitwise NOT of register src1 (converted to int32),
2147 and puts the result in register dst.
2148 */
2149 int dst = (++vPC)->u.operand;
2150 JSValue* src = callFrame[(++vPC)->u.operand].jsValue(callFrame);
2151 int32_t value;
2152 if (fastToInt32(src, value))
2153 callFrame[dst] = jsNumber(callFrame, ~value);
2154 else {
2155 JSValue* result = jsNumber(callFrame, ~src->toInt32(callFrame));
2156 CHECK_FOR_EXCEPTION();
2157 callFrame[dst] = result;
2158 }
2159 ++vPC;
2160 NEXT_INSTRUCTION();
2161 }
2162 DEFINE_OPCODE(op_not) {
2163 /* not dst(r) src(r)
2164
2165 Computes logical NOT of register src (converted to
2166 boolean), and puts the result in register dst.
2167 */
2168 int dst = (++vPC)->u.operand;
2169 int src = (++vPC)->u.operand;
2170 JSValue* result = jsBoolean(!callFrame[src].jsValue(callFrame)->toBoolean(callFrame));
2171 CHECK_FOR_EXCEPTION();
2172 callFrame[dst] = result;
2173
2174 ++vPC;
2175 NEXT_INSTRUCTION();
2176 }
2177 DEFINE_OPCODE(op_instanceof) {
2178 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2179
2180 Tests whether register value is an instance of register
2181 constructor, and puts the boolean result in register
2182 dst. Register constructorProto must contain the "prototype"
2183 property (not the actual prototype) of the object in
2184 register constructor. This lookup is separated so that
2185 polymorphic inline caching can apply.
2186
2187 Raises an exception if register constructor is not an
2188 object.
2189 */
2190 int dst = vPC[1].u.operand;
2191 int value = vPC[2].u.operand;
2192 int base = vPC[3].u.operand;
2193 int baseProto = vPC[4].u.operand;
2194
2195 JSValue* baseVal = callFrame[base].jsValue(callFrame);
2196
2197 if (isNotObject(callFrame, true, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
2198 goto vm_throw;
2199
2200 JSObject* baseObj = asObject(baseVal);
2201 callFrame[dst] = jsBoolean(baseObj->structure()->typeInfo().implementsHasInstance() ? baseObj->hasInstance(callFrame, callFrame[value].jsValue(callFrame), callFrame[baseProto].jsValue(callFrame)) : false);
2202
2203 vPC += 5;
2204 NEXT_INSTRUCTION();
2205 }
2206 DEFINE_OPCODE(op_typeof) {
2207 /* typeof dst(r) src(r)
2208
2209 Determines the type string for src according to ECMAScript
2210 rules, and puts the result in register dst.
2211 */
2212 int dst = (++vPC)->u.operand;
2213 int src = (++vPC)->u.operand;
2214 callFrame[dst] = jsTypeStringForValue(callFrame, callFrame[src].jsValue(callFrame));
2215
2216 ++vPC;
2217 NEXT_INSTRUCTION();
2218 }
2219 DEFINE_OPCODE(op_is_undefined) {
2220 /* is_undefined dst(r) src(r)
2221
2222 Determines whether the type string for src according to
2223 the ECMAScript rules is "undefined", and puts the result
2224 in register dst.
2225 */
2226 int dst = (++vPC)->u.operand;
2227 int src = (++vPC)->u.operand;
2228 JSValue* v = callFrame[src].jsValue(callFrame);
2229 callFrame[dst] = jsBoolean(JSImmediate::isImmediate(v) ? v->isUndefined() : v->asCell()->structure()->typeInfo().masqueradesAsUndefined());
2230
2231 ++vPC;
2232 NEXT_INSTRUCTION();
2233 }
2234 DEFINE_OPCODE(op_is_boolean) {
2235 /* is_boolean dst(r) src(r)
2236
2237 Determines whether the type string for src according to
2238 the ECMAScript rules is "boolean", and puts the result
2239 in register dst.
2240 */
2241 int dst = (++vPC)->u.operand;
2242 int src = (++vPC)->u.operand;
2243 callFrame[dst] = jsBoolean(callFrame[src].jsValue(callFrame)->isBoolean());
2244
2245 ++vPC;
2246 NEXT_INSTRUCTION();
2247 }
2248 DEFINE_OPCODE(op_is_number) {
2249 /* is_number dst(r) src(r)
2250
2251 Determines whether the type string for src according to
2252 the ECMAScript rules is "number", and puts the result
2253 in register dst.
2254 */
2255 int dst = (++vPC)->u.operand;
2256 int src = (++vPC)->u.operand;
2257 callFrame[dst] = jsBoolean(callFrame[src].jsValue(callFrame)->isNumber());
2258
2259 ++vPC;
2260 NEXT_INSTRUCTION();
2261 }
2262 DEFINE_OPCODE(op_is_string) {
2263 /* is_string dst(r) src(r)
2264
2265 Determines whether the type string for src according to
2266 the ECMAScript rules is "string", and puts the result
2267 in register dst.
2268 */
2269 int dst = (++vPC)->u.operand;
2270 int src = (++vPC)->u.operand;
2271 callFrame[dst] = jsBoolean(callFrame[src].jsValue(callFrame)->isString());
2272
2273 ++vPC;
2274 NEXT_INSTRUCTION();
2275 }
2276 DEFINE_OPCODE(op_is_object) {
2277 /* is_object dst(r) src(r)
2278
2279 Determines whether the type string for src according to
2280 the ECMAScript rules is "object", and puts the result
2281 in register dst.
2282 */
2283 int dst = (++vPC)->u.operand;
2284 int src = (++vPC)->u.operand;
2285 callFrame[dst] = jsBoolean(jsIsObjectType(callFrame[src].jsValue(callFrame)));
2286
2287 ++vPC;
2288 NEXT_INSTRUCTION();
2289 }
2290 DEFINE_OPCODE(op_is_function) {
2291 /* is_function dst(r) src(r)
2292
2293 Determines whether the type string for src according to
2294 the ECMAScript rules is "function", and puts the result
2295 in register dst.
2296 */
2297 int dst = (++vPC)->u.operand;
2298 int src = (++vPC)->u.operand;
2299 callFrame[dst] = jsBoolean(jsIsFunctionType(callFrame[src].jsValue(callFrame)));
2300
2301 ++vPC;
2302 NEXT_INSTRUCTION();
2303 }
2304 DEFINE_OPCODE(op_in) {
2305 /* in dst(r) property(r) base(r)
2306
2307 Tests whether register base has a property named register
2308 property, and puts the boolean result in register dst.
2309
2310 Raises an exception if register constructor is not an
2311 object.
2312 */
2313 int dst = (++vPC)->u.operand;
2314 int property = (++vPC)->u.operand;
2315 int base = (++vPC)->u.operand;
2316
2317 JSValue* baseVal = callFrame[base].jsValue(callFrame);
2318 if (isNotObject(callFrame, false, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
2319 goto vm_throw;
2320
2321 JSObject* baseObj = asObject(baseVal);
2322
2323 JSValue* propName = callFrame[property].jsValue(callFrame);
2324
2325 uint32_t i;
2326 if (propName->getUInt32(i))
2327 callFrame[dst] = jsBoolean(baseObj->hasProperty(callFrame, i));
2328 else {
2329 Identifier property(callFrame, propName->toString(callFrame));
2330 CHECK_FOR_EXCEPTION();
2331 callFrame[dst] = jsBoolean(baseObj->hasProperty(callFrame, property));
2332 }
2333
2334 ++vPC;
2335 NEXT_INSTRUCTION();
2336 }
2337 DEFINE_OPCODE(op_resolve) {
2338 /* resolve dst(r) property(id)
2339
2340 Looks up the property named by identifier property in the
2341 scope chain, and writes the resulting value to register
2342 dst. If the property is not found, raises an exception.
2343 */
2344 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
2345 goto vm_throw;
2346
2347 vPC += 3;
2348 NEXT_INSTRUCTION();
2349 }
2350 DEFINE_OPCODE(op_resolve_skip) {
2351 /* resolve_skip dst(r) property(id) skip(n)
2352
2353 Looks up the property named by identifier property in the
2354 scope chain skipping the top 'skip' levels, and writes the resulting
2355 value to register dst. If the property is not found, raises an exception.
2356 */
2357 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
2358 goto vm_throw;
2359
2360 vPC += 4;
2361
2362 NEXT_INSTRUCTION();
2363 }
2364 DEFINE_OPCODE(op_resolve_global) {
2365 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
2366
2367 Performs a dynamic property lookup for the given property, on the provided
2368 global object. If structure matches the Structure of the global then perform
2369 a fast lookup using the case offset, otherwise fall back to a full resolve and
2370 cache the new structure and offset
2371 */
2372 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
2373 goto vm_throw;
2374
2375 vPC += 6;
2376
2377 NEXT_INSTRUCTION();
2378 }
2379 DEFINE_OPCODE(op_get_global_var) {
2380 /* get_global_var dst(r) globalObject(c) index(n)
2381
2382 Gets the global var at global slot index and places it in register dst.
2383 */
2384 int dst = (++vPC)->u.operand;
2385 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2386 ASSERT(scope->isGlobalObject());
2387 int index = (++vPC)->u.operand;
2388
2389 callFrame[dst] = scope->registerAt(index);
2390 ++vPC;
2391 NEXT_INSTRUCTION();
2392 }
2393 DEFINE_OPCODE(op_put_global_var) {
2394 /* put_global_var globalObject(c) index(n) value(r)
2395
2396 Puts value into global slot index.
2397 */
2398 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2399 ASSERT(scope->isGlobalObject());
2400 int index = (++vPC)->u.operand;
2401 int value = (++vPC)->u.operand;
2402
2403 scope->registerAt(index) = callFrame[value].jsValue(callFrame);
2404 ++vPC;
2405 NEXT_INSTRUCTION();
2406 }
2407 DEFINE_OPCODE(op_get_scoped_var) {
2408 /* get_scoped_var dst(r) index(n) skip(n)
2409
2410 Loads the contents of the index-th local from the scope skip nodes from
2411 the top of the scope chain, and places it in register dst
2412 */
2413 int dst = (++vPC)->u.operand;
2414 int index = (++vPC)->u.operand;
2415 int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain();
2416
2417 ScopeChainNode* scopeChain = callFrame->scopeChain();
2418 ScopeChainIterator iter = scopeChain->begin();
2419 ScopeChainIterator end = scopeChain->end();
2420 ASSERT(iter != end);
2421 while (skip--) {
2422 ++iter;
2423 ASSERT(iter != end);
2424 }
2425
2426 ASSERT((*iter)->isVariableObject());
2427 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2428 callFrame[dst] = scope->registerAt(index);
2429 ++vPC;
2430 NEXT_INSTRUCTION();
2431 }
2432 DEFINE_OPCODE(op_put_scoped_var) {
2433 /* put_scoped_var index(n) skip(n) value(r)
2434
2435 */
2436 int index = (++vPC)->u.operand;
2437 int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain();
2438 int value = (++vPC)->u.operand;
2439
2440 ScopeChainNode* scopeChain = callFrame->scopeChain();
2441 ScopeChainIterator iter = scopeChain->begin();
2442 ScopeChainIterator end = scopeChain->end();
2443 ASSERT(iter != end);
2444 while (skip--) {
2445 ++iter;
2446 ASSERT(iter != end);
2447 }
2448
2449 ASSERT((*iter)->isVariableObject());
2450 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2451 scope->registerAt(index) = callFrame[value].jsValue(callFrame);
2452 ++vPC;
2453 NEXT_INSTRUCTION();
2454 }
2455 DEFINE_OPCODE(op_resolve_base) {
2456 /* resolve_base dst(r) property(id)
2457
2458 Searches the scope chain for an object containing
2459 identifier property, and if one is found, writes it to
2460 register dst. If none is found, the outermost scope (which
2461 will be the global object) is stored in register dst.
2462 */
2463 resolveBase(callFrame, vPC);
2464
2465 vPC += 3;
2466 NEXT_INSTRUCTION();
2467 }
2468 DEFINE_OPCODE(op_resolve_with_base) {
2469 /* resolve_with_base baseDst(r) propDst(r) property(id)
2470
2471 Searches the scope chain for an object containing
2472 identifier property, and if one is found, writes it to
2473 register srcDst, and the retrieved property value to register
2474 propDst. If the property is not found, raises an exception.
2475
2476 This is more efficient than doing resolve_base followed by
2477 resolve, or resolve_base followed by get_by_id, as it
2478 avoids duplicate hash lookups.
2479 */
2480 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
2481 goto vm_throw;
2482
2483 vPC += 4;
2484 NEXT_INSTRUCTION();
2485 }
2486 DEFINE_OPCODE(op_resolve_func) {
2487 /* resolve_func baseDst(r) funcDst(r) property(id)
2488
2489 Searches the scope chain for an object containing
2490 identifier property, and if one is found, writes the
2491 appropriate object to use as "this" when calling its
2492 properties to register baseDst; and the retrieved property
2493 value to register propDst. If the property is not found,
2494 raises an exception.
2495
2496 This differs from resolve_with_base, because the
2497 global this value will be substituted for activations or
2498 the global object, which is the right behavior for function
2499 calls but not for other property lookup.
2500 */
2501 if (UNLIKELY(!resolveBaseAndFunc(callFrame, vPC, exceptionValue)))
2502 goto vm_throw;
2503
2504 vPC += 4;
2505 NEXT_INSTRUCTION();
2506 }
2507 DEFINE_OPCODE(op_get_by_id) {
2508 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2509
2510 Generic property access: Gets the property named by identifier
2511 property from the value base, and puts the result in register dst.
2512 */
2513 int dst = vPC[1].u.operand;
2514 int base = vPC[2].u.operand;
2515 int property = vPC[3].u.operand;
2516
2517 CodeBlock* codeBlock = callFrame->codeBlock();
2518 Identifier& ident = codeBlock->identifier(property);
2519 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2520 PropertySlot slot(baseValue);
2521 JSValue* result = baseValue->get(callFrame, ident, slot);
2522 CHECK_FOR_EXCEPTION();
2523
2524 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
2525
2526 callFrame[dst] = result;
2527 vPC += 8;
2528 NEXT_INSTRUCTION();
2529 }
2530 DEFINE_OPCODE(op_get_by_id_self) {
2531 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2532
2533 Cached property access: Attempts to get a cached property from the
2534 value base. If the cache misses, op_get_by_id_self reverts to
2535 op_get_by_id.
2536 */
2537 int base = vPC[2].u.operand;
2538 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2539
2540 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2541 JSCell* baseCell = asCell(baseValue);
2542 Structure* structure = vPC[4].u.structure;
2543
2544 if (LIKELY(baseCell->structure() == structure)) {
2545 ASSERT(baseCell->isObject());
2546 JSObject* baseObject = asObject(baseCell);
2547 int dst = vPC[1].u.operand;
2548 int offset = vPC[5].u.operand;
2549
2550 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2551 callFrame[dst] = baseObject->getDirectOffset(offset);
2552
2553 vPC += 8;
2554 NEXT_INSTRUCTION();
2555 }
2556 }
2557
2558 uncacheGetByID(callFrame->codeBlock(), vPC);
2559 NEXT_INSTRUCTION();
2560 }
2561 DEFINE_OPCODE(op_get_by_id_proto) {
2562 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2563
2564 Cached property access: Attempts to get a cached property from the
2565 value base's prototype. If the cache misses, op_get_by_id_proto
2566 reverts to op_get_by_id.
2567 */
2568 int base = vPC[2].u.operand;
2569 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2570
2571 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2572 JSCell* baseCell = asCell(baseValue);
2573 Structure* structure = vPC[4].u.structure;
2574
2575 if (LIKELY(baseCell->structure() == structure)) {
2576 ASSERT(structure->prototypeForLookup(callFrame)->isObject());
2577 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2578 Structure* prototypeStructure = vPC[5].u.structure;
2579
2580 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2581 int dst = vPC[1].u.operand;
2582 int offset = vPC[6].u.operand;
2583
2584 ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2585 callFrame[dst] = protoObject->getDirectOffset(offset);
2586
2587 vPC += 8;
2588 NEXT_INSTRUCTION();
2589 }
2590 }
2591 }
2592
2593 uncacheGetByID(callFrame->codeBlock(), vPC);
2594 NEXT_INSTRUCTION();
2595 }
2596 DEFINE_OPCODE(op_get_by_id_self_list) {
2597 // Polymorphic self access caching currently only supported when JITting.
2598 ASSERT_NOT_REACHED();
2599 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2600 vPC += 8;
2601 NEXT_INSTRUCTION();
2602 }
2603 DEFINE_OPCODE(op_get_by_id_proto_list) {
2604 // Polymorphic prototype access caching currently only supported when JITting.
2605 ASSERT_NOT_REACHED();
2606 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2607 vPC += 8;
2608 NEXT_INSTRUCTION();
2609 }
2610 DEFINE_OPCODE(op_get_by_id_chain) {
2611 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2612
2613 Cached property access: Attempts to get a cached property from the
2614 value base's prototype chain. If the cache misses, op_get_by_id_chain
2615 reverts to op_get_by_id.
2616 */
2617 int base = vPC[2].u.operand;
2618 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2619
2620 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2621 JSCell* baseCell = asCell(baseValue);
2622 Structure* structure = vPC[4].u.structure;
2623
2624 if (LIKELY(baseCell->structure() == structure)) {
2625 RefPtr<Structure>* it = vPC[5].u.structureChain->head();
2626 size_t count = vPC[6].u.operand;
2627 RefPtr<Structure>* end = it + count;
2628
2629 JSObject* baseObject = asObject(baseCell);
2630 while (1) {
2631 baseObject = asObject(baseObject->structure()->prototypeForLookup(callFrame));
2632 if (UNLIKELY(baseObject->structure() != (*it).get()))
2633 break;
2634
2635 if (++it == end) {
2636 int dst = vPC[1].u.operand;
2637 int offset = vPC[7].u.operand;
2638
2639 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2640 callFrame[dst] = baseObject->getDirectOffset(offset);
2641
2642 vPC += 8;
2643 NEXT_INSTRUCTION();
2644 }
2645 }
2646 }
2647 }
2648
2649 uncacheGetByID(callFrame->codeBlock(), vPC);
2650 NEXT_INSTRUCTION();
2651 }
2652 DEFINE_OPCODE(op_get_by_id_generic) {
2653 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2654
2655 Generic property access: Gets the property named by identifier
2656 property from the value base, and puts the result in register dst.
2657 */
2658 int dst = vPC[1].u.operand;
2659 int base = vPC[2].u.operand;
2660 int property = vPC[3].u.operand;
2661
2662 Identifier& ident = callFrame->codeBlock()->identifier(property);
2663 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2664 PropertySlot slot(baseValue);
2665 JSValue* result = baseValue->get(callFrame, ident, slot);
2666 CHECK_FOR_EXCEPTION();
2667
2668 callFrame[dst] = result;
2669 vPC += 8;
2670 NEXT_INSTRUCTION();
2671 }
2672 DEFINE_OPCODE(op_get_array_length) {
2673 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2674
2675 Cached property access: Gets the length of the array in register base,
2676 and puts the result in register dst. If register base does not hold
2677 an array, op_get_array_length reverts to op_get_by_id.
2678 */
2679
2680 int base = vPC[2].u.operand;
2681 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2682 if (LIKELY(isJSArray(baseValue))) {
2683 int dst = vPC[1].u.operand;
2684 callFrame[dst] = jsNumber(callFrame, asArray(baseValue)->length());
2685 vPC += 8;
2686 NEXT_INSTRUCTION();
2687 }
2688
2689 uncacheGetByID(callFrame->codeBlock(), vPC);
2690 NEXT_INSTRUCTION();
2691 }
2692 DEFINE_OPCODE(op_get_string_length) {
2693 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2694
2695 Cached property access: Gets the length of the string in register base,
2696 and puts the result in register dst. If register base does not hold
2697 a string, op_get_string_length reverts to op_get_by_id.
2698 */
2699
2700 int base = vPC[2].u.operand;
2701 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2702 if (LIKELY(isJSString(baseValue))) {
2703 int dst = vPC[1].u.operand;
2704 callFrame[dst] = jsNumber(callFrame, asString(baseValue)->value().size());
2705 vPC += 8;
2706 NEXT_INSTRUCTION();
2707 }
2708
2709 uncacheGetByID(callFrame->codeBlock(), vPC);
2710 NEXT_INSTRUCTION();
2711 }
2712 DEFINE_OPCODE(op_put_by_id) {
2713 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2714
2715 Generic property access: Sets the property named by identifier
2716 property, belonging to register base, to register value.
2717
2718 Unlike many opcodes, this one does not write any output to
2719 the register file.
2720 */
2721
2722 int base = vPC[1].u.operand;
2723 int property = vPC[2].u.operand;
2724 int value = vPC[3].u.operand;
2725
2726 CodeBlock* codeBlock = callFrame->codeBlock();
2727 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2728 Identifier& ident = codeBlock->identifier(property);
2729 PutPropertySlot slot;
2730 baseValue->put(callFrame, ident, callFrame[value].jsValue(callFrame), slot);
2731 CHECK_FOR_EXCEPTION();
2732
2733 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
2734
2735 vPC += 8;
2736 NEXT_INSTRUCTION();
2737 }
2738 DEFINE_OPCODE(op_put_by_id_transition) {
2739 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)
2740
2741 Cached property access: Attempts to set a new property with a cached transition
2742 property named by identifier property, belonging to register base,
2743 to register value. If the cache misses, op_put_by_id_transition
2744 reverts to op_put_by_id_generic.
2745
2746 Unlike many opcodes, this one does not write any output to
2747 the register file.
2748 */
2749 int base = vPC[1].u.operand;
2750 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2751
2752 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2753 JSCell* baseCell = asCell(baseValue);
2754 Structure* oldStructure = vPC[4].u.structure;
2755 Structure* newStructure = vPC[5].u.structure;
2756
2757 if (LIKELY(baseCell->structure() == oldStructure)) {
2758 ASSERT(baseCell->isObject());
2759 JSObject* baseObject = asObject(baseCell);
2760
2761 RefPtr<Structure>* it = vPC[6].u.structureChain->head();
2762
2763 JSValue* proto = baseObject->structure()->prototypeForLookup(callFrame);
2764 while (!proto->isNull()) {
2765 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
2766 uncachePutByID(callFrame->codeBlock(), vPC);
2767 NEXT_INSTRUCTION();
2768 }
2769 ++it;
2770 proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
2771 }
2772
2773 baseObject->transitionTo(newStructure);
2774
2775 int value = vPC[3].u.operand;
2776 unsigned offset = vPC[7].u.operand;
2777 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2778 baseObject->putDirectOffset(offset, callFrame[value].jsValue(callFrame));
2779
2780 vPC += 8;
2781 NEXT_INSTRUCTION();
2782 }
2783 }
2784
2785 uncachePutByID(callFrame->codeBlock(), vPC);
2786 NEXT_INSTRUCTION();
2787 }
2788 DEFINE_OPCODE(op_put_by_id_replace) {
2789 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)
2790
2791 Cached property access: Attempts to set a pre-existing, cached
2792 property named by identifier property, belonging to register base,
2793 to register value. If the cache misses, op_put_by_id_replace
2794 reverts to op_put_by_id.
2795
2796 Unlike many opcodes, this one does not write any output to
2797 the register file.
2798 */
2799 int base = vPC[1].u.operand;
2800 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2801
2802 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2803 JSCell* baseCell = asCell(baseValue);
2804 Structure* structure = vPC[4].u.structure;
2805
2806 if (LIKELY(baseCell->structure() == structure)) {
2807 ASSERT(baseCell->isObject());
2808 JSObject* baseObject = asObject(baseCell);
2809 int value = vPC[3].u.operand;
2810 unsigned offset = vPC[5].u.operand;
2811
2812 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2813 baseObject->putDirectOffset(offset, callFrame[value].jsValue(callFrame));
2814
2815 vPC += 8;
2816 NEXT_INSTRUCTION();
2817 }
2818 }
2819
2820 uncachePutByID(callFrame->codeBlock(), vPC);
2821 NEXT_INSTRUCTION();
2822 }
2823 DEFINE_OPCODE(op_put_by_id_generic) {
2824 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2825
2826 Generic property access: Sets the property named by identifier
2827 property, belonging to register base, to register value.
2828
2829 Unlike many opcodes, this one does not write any output to
2830 the register file.
2831 */
2832 int base = vPC[1].u.operand;
2833 int property = vPC[2].u.operand;
2834 int value = vPC[3].u.operand;
2835
2836 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2837 Identifier& ident = callFrame->codeBlock()->identifier(property);
2838 PutPropertySlot slot;
2839 baseValue->put(callFrame, ident, callFrame[value].jsValue(callFrame), slot);
2840 CHECK_FOR_EXCEPTION();
2841
2842 vPC += 8;
2843 NEXT_INSTRUCTION();
2844 }
2845 DEFINE_OPCODE(op_del_by_id) {
2846 /* del_by_id dst(r) base(r) property(id)
2847
2848 Converts register base to Object, deletes the property
2849 named by identifier property from the object, and writes a
2850 boolean indicating success (if true) or failure (if false)
2851 to register dst.
2852 */
2853 int dst = (++vPC)->u.operand;
2854 int base = (++vPC)->u.operand;
2855 int property = (++vPC)->u.operand;
2856
2857 JSObject* baseObj = callFrame[base].jsValue(callFrame)->toObject(callFrame);
2858 Identifier& ident = callFrame->codeBlock()->identifier(property);
2859 JSValue* result = jsBoolean(baseObj->deleteProperty(callFrame, ident));
2860 CHECK_FOR_EXCEPTION();
2861 callFrame[dst] = result;
2862 ++vPC;
2863 NEXT_INSTRUCTION();
2864 }
2865 DEFINE_OPCODE(op_get_by_val) {
2866 /* get_by_val dst(r) base(r) property(r)
2867
2868 Converts register base to Object, gets the property named
2869 by register property from the object, and puts the result
2870 in register dst. property is nominally converted to string
2871 but numbers are treated more efficiently.
2872 */
2873 int dst = (++vPC)->u.operand;
2874 int base = (++vPC)->u.operand;
2875 int property = (++vPC)->u.operand;
2876
2877 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2878 JSValue* subscript = callFrame[property].jsValue(callFrame);
2879
2880 JSValue* result;
2881 unsigned i;
2882
2883 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2884 if (LIKELY(isUInt32)) {
2885 if (isJSArray(baseValue)) {
2886 JSArray* jsArray = asArray(baseValue);
2887 if (jsArray->canGetIndex(i))
2888 result = jsArray->getIndex(i);
2889 else
2890 result = jsArray->JSArray::get(callFrame, i);
2891 } else if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
2892 result = asString(baseValue)->getIndex(&callFrame->globalData(), i);
2893 else
2894 result = baseValue->get(callFrame, i);
2895 } else {
2896 Identifier property(callFrame, subscript->toString(callFrame));
2897 result = baseValue->get(callFrame, property);
2898 }
2899
2900 CHECK_FOR_EXCEPTION();
2901 callFrame[dst] = result;
2902 ++vPC;
2903 NEXT_INSTRUCTION();
2904 }
2905 DEFINE_OPCODE(op_put_by_val) {
2906 /* put_by_val base(r) property(r) value(r)
2907
2908 Sets register value on register base as the property named
2909 by register property. Base is converted to object
2910 first. register property is nominally converted to string
2911 but numbers are treated more efficiently.
2912
2913 Unlike many opcodes, this one does not write any output to
2914 the register file.
2915 */
2916 int base = (++vPC)->u.operand;
2917 int property = (++vPC)->u.operand;
2918 int value = (++vPC)->u.operand;
2919
2920 JSValue* baseValue = callFrame[base].jsValue(callFrame);
2921 JSValue* subscript = callFrame[property].jsValue(callFrame);
2922
2923 unsigned i;
2924
2925 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2926 if (LIKELY(isUInt32)) {
2927 if (isJSArray(baseValue)) {
2928 JSArray* jsArray = asArray(baseValue);
2929 if (jsArray->canSetIndex(i))
2930 jsArray->setIndex(i, callFrame[value].jsValue(callFrame));
2931 else
2932 jsArray->JSArray::put(callFrame, i, callFrame[value].jsValue(callFrame));
2933 } else
2934 baseValue->put(callFrame, i, callFrame[value].jsValue(callFrame));
2935 } else {
2936 Identifier property(callFrame, subscript->toString(callFrame));
2937 if (!globalData->exception) { // Don't put to an object if toString threw an exception.
2938 PutPropertySlot slot;
2939 baseValue->put(callFrame, property, callFrame[value].jsValue(callFrame), slot);
2940 }
2941 }
2942
2943 CHECK_FOR_EXCEPTION();
2944 ++vPC;
2945 NEXT_INSTRUCTION();
2946 }
2947 DEFINE_OPCODE(op_del_by_val) {
2948 /* del_by_val dst(r) base(r) property(r)
2949
2950 Converts register base to Object, deletes the property
2951 named by register property from the object, and writes a
2952 boolean indicating success (if true) or failure (if false)
2953 to register dst.
2954 */
2955 int dst = (++vPC)->u.operand;
2956 int base = (++vPC)->u.operand;
2957 int property = (++vPC)->u.operand;
2958
2959 JSObject* baseObj = callFrame[base].jsValue(callFrame)->toObject(callFrame); // may throw
2960
2961 JSValue* subscript = callFrame[property].jsValue(callFrame);
2962 JSValue* result;
2963 uint32_t i;
2964 if (subscript->getUInt32(i))
2965 result = jsBoolean(baseObj->deleteProperty(callFrame, i));
2966 else {
2967 CHECK_FOR_EXCEPTION();
2968 Identifier property(callFrame, subscript->toString(callFrame));
2969 CHECK_FOR_EXCEPTION();
2970 result = jsBoolean(baseObj->deleteProperty(callFrame, property));
2971 }
2972
2973 CHECK_FOR_EXCEPTION();
2974 callFrame[dst] = result;
2975 ++vPC;
2976 NEXT_INSTRUCTION();
2977 }
2978 DEFINE_OPCODE(op_put_by_index) {
2979 /* put_by_index base(r) property(n) value(r)
2980
2981 Sets register value on register base as the property named
2982 by the immediate number property. Base is converted to
2983 object first.
2984
2985 Unlike many opcodes, this one does not write any output to
2986 the register file.
2987
2988 This opcode is mainly used to initialize array literals.
2989 */
2990 int base = (++vPC)->u.operand;
2991 unsigned property = (++vPC)->u.operand;
2992 int value = (++vPC)->u.operand;
2993
2994 callFrame[base].jsValue(callFrame)->put(callFrame, property, callFrame[value].jsValue(callFrame));
2995
2996 ++vPC;
2997 NEXT_INSTRUCTION();
2998 }
2999 DEFINE_OPCODE(op_loop) {
3000 /* loop target(offset)
3001
3002 Jumps unconditionally to offset target from the current
3003 instruction.
3004
3005 Additionally this loop instruction may terminate JS execution is
3006 the JS timeout is reached.
3007 */
3008#if ENABLE(OPCODE_STATS)
3009 OpcodeStats::resetLastInstruction();
3010#endif
3011 int target = (++vPC)->u.operand;
3012 CHECK_FOR_TIMEOUT();
3013 vPC += target;
3014 NEXT_INSTRUCTION();
3015 }
3016 DEFINE_OPCODE(op_jmp) {
3017 /* jmp target(offset)
3018
3019 Jumps unconditionally to offset target from the current
3020 instruction.
3021 */
3022#if ENABLE(OPCODE_STATS)
3023 OpcodeStats::resetLastInstruction();
3024#endif
3025 int target = (++vPC)->u.operand;
3026
3027 vPC += target;
3028 NEXT_INSTRUCTION();
3029 }
3030 DEFINE_OPCODE(op_loop_if_true) {
3031 /* loop_if_true cond(r) target(offset)
3032
3033 Jumps to offset target from the current instruction, if and
3034 only if register cond converts to boolean as true.
3035
3036 Additionally this loop instruction may terminate JS execution is
3037 the JS timeout is reached.
3038 */
3039 int cond = (++vPC)->u.operand;
3040 int target = (++vPC)->u.operand;
3041 if (callFrame[cond].jsValue(callFrame)->toBoolean(callFrame)) {
3042 vPC += target;
3043 CHECK_FOR_TIMEOUT();
3044 NEXT_INSTRUCTION();
3045 }
3046
3047 ++vPC;
3048 NEXT_INSTRUCTION();
3049 }
3050 DEFINE_OPCODE(op_jtrue) {
3051 /* jtrue cond(r) target(offset)
3052
3053 Jumps to offset target from the current instruction, if and
3054 only if register cond converts to boolean as true.
3055 */
3056 int cond = (++vPC)->u.operand;
3057 int target = (++vPC)->u.operand;
3058 if (callFrame[cond].jsValue(callFrame)->toBoolean(callFrame)) {
3059 vPC += target;
3060 NEXT_INSTRUCTION();
3061 }
3062
3063 ++vPC;
3064 NEXT_INSTRUCTION();
3065 }
3066 DEFINE_OPCODE(op_jfalse) {
3067 /* jfalse cond(r) target(offset)
3068
3069 Jumps to offset target from the current instruction, if and
3070 only if register cond converts to boolean as false.
3071 */
3072 int cond = (++vPC)->u.operand;
3073 int target = (++vPC)->u.operand;
3074 if (!callFrame[cond].jsValue(callFrame)->toBoolean(callFrame)) {
3075 vPC += target;
3076 NEXT_INSTRUCTION();
3077 }
3078
3079 ++vPC;
3080 NEXT_INSTRUCTION();
3081 }
3082 DEFINE_OPCODE(op_jeq_null) {
3083 /* jeq_null src(r) target(offset)
3084
3085 Jumps to offset target from the current instruction, if and
3086 only if register src is null.
3087 */
3088 int src = (++vPC)->u.operand;
3089 int target = (++vPC)->u.operand;
3090 JSValue* srcValue = callFrame[src].jsValue(callFrame);
3091
3092 if (srcValue->isUndefinedOrNull() || (!JSImmediate::isImmediate(srcValue) && srcValue->asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
3093 vPC += target;
3094 NEXT_INSTRUCTION();
3095 }
3096
3097 ++vPC;
3098 NEXT_INSTRUCTION();
3099 }
3100 DEFINE_OPCODE(op_jneq_null) {
3101 /* jneq_null src(r) target(offset)
3102
3103 Jumps to offset target from the current instruction, if and
3104 only if register src is not null.
3105 */
3106 int src = (++vPC)->u.operand;
3107 int target = (++vPC)->u.operand;
3108 JSValue* srcValue = callFrame[src].jsValue(callFrame);
3109
3110 if (!srcValue->isUndefinedOrNull() || (!JSImmediate::isImmediate(srcValue) && !srcValue->asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
3111 vPC += target;
3112 NEXT_INSTRUCTION();
3113 }
3114
3115 ++vPC;
3116 NEXT_INSTRUCTION();
3117 }
3118 DEFINE_OPCODE(op_loop_if_less) {
3119 /* loop_if_less src1(r) src2(r) target(offset)
3120
3121 Checks whether register src1 is less than register src2, as
3122 with the ECMAScript '<' operator, and then jumps to offset
3123 target from the current instruction, if and only if the
3124 result of the comparison is true.
3125
3126 Additionally this loop instruction may terminate JS execution is
3127 the JS timeout is reached.
3128 */
3129 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3130 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3131 int target = (++vPC)->u.operand;
3132
3133 bool result = jsLess(callFrame, src1, src2);
3134 CHECK_FOR_EXCEPTION();
3135
3136 if (result) {
3137 vPC += target;
3138 CHECK_FOR_TIMEOUT();
3139 NEXT_INSTRUCTION();
3140 }
3141
3142 ++vPC;
3143 NEXT_INSTRUCTION();
3144 }
3145 DEFINE_OPCODE(op_loop_if_lesseq) {
3146 /* loop_if_lesseq src1(r) src2(r) target(offset)
3147
3148 Checks whether register src1 is less than or equal to register
3149 src2, as with the ECMAScript '<=' operator, and then jumps to
3150 offset target from the current instruction, if and only if the
3151 result of the comparison is true.
3152
3153 Additionally this loop instruction may terminate JS execution is
3154 the JS timeout is reached.
3155 */
3156 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3157 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3158 int target = (++vPC)->u.operand;
3159
3160 bool result = jsLessEq(callFrame, src1, src2);
3161 CHECK_FOR_EXCEPTION();
3162
3163 if (result) {
3164 vPC += target;
3165 CHECK_FOR_TIMEOUT();
3166 NEXT_INSTRUCTION();
3167 }
3168
3169 ++vPC;
3170 NEXT_INSTRUCTION();
3171 }
3172 DEFINE_OPCODE(op_jnless) {
3173 /* jnless src1(r) src2(r) target(offset)
3174
3175 Checks whether register src1 is less than register src2, as
3176 with the ECMAScript '<' operator, and then jumps to offset
3177 target from the current instruction, if and only if the
3178 result of the comparison is false.
3179 */
3180 JSValue* src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3181 JSValue* src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3182 int target = (++vPC)->u.operand;
3183
3184 bool result = jsLess(callFrame, src1, src2);
3185 CHECK_FOR_EXCEPTION();
3186
3187 if (!result) {
3188 vPC += target;
3189 NEXT_INSTRUCTION();
3190 }
3191
3192 ++vPC;
3193 NEXT_INSTRUCTION();
3194 }
3195 DEFINE_OPCODE(op_switch_imm) {
3196 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3197
3198 Performs a range checked switch on the scrutinee value, using
3199 the tableIndex-th immediate switch jump table. If the scrutinee value
3200 is an immediate number in the range covered by the referenced jump
3201 table, and the value at jumpTable[scrutinee value] is non-zero, then
3202 that value is used as the jump offset, otherwise defaultOffset is used.
3203 */
3204 int tableIndex = (++vPC)->u.operand;
3205 int defaultOffset = (++vPC)->u.operand;
3206 JSValue* scrutinee = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3207 if (!JSImmediate::isNumber(scrutinee))
3208 vPC += defaultOffset;
3209 else {
3210 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3211 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(value, defaultOffset);
3212 }
3213 NEXT_INSTRUCTION();
3214 }
3215 DEFINE_OPCODE(op_switch_char) {
3216 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3217
3218 Performs a range checked switch on the scrutinee value, using
3219 the tableIndex-th character switch jump table. If the scrutinee value
3220 is a single character string in the range covered by the referenced jump
3221 table, and the value at jumpTable[scrutinee value] is non-zero, then
3222 that value is used as the jump offset, otherwise defaultOffset is used.
3223 */
3224 int tableIndex = (++vPC)->u.operand;
3225 int defaultOffset = (++vPC)->u.operand;
3226 JSValue* scrutinee = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3227 if (!scrutinee->isString())
3228 vPC += defaultOffset;
3229 else {
3230 UString::Rep* value = asString(scrutinee)->value().rep();
3231 if (value->size() != 1)
3232 vPC += defaultOffset;
3233 else
3234 vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->data()[0], defaultOffset);
3235 }
3236 NEXT_INSTRUCTION();
3237 }
3238 DEFINE_OPCODE(op_switch_string) {
3239 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3240
3241 Performs a sparse hashmap based switch on the value in the scrutinee
3242 register, using the tableIndex-th string switch jump table. If the
3243 scrutinee value is a string that exists as a key in the referenced
3244 jump table, then the value associated with the string is used as the
3245 jump offset, otherwise defaultOffset is used.
3246 */
3247 int tableIndex = (++vPC)->u.operand;
3248 int defaultOffset = (++vPC)->u.operand;
3249 JSValue* scrutinee = callFrame[(++vPC)->u.operand].jsValue(callFrame);
3250 if (!scrutinee->isString())
3251 vPC += defaultOffset;
3252 else
3253 vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value().rep(), defaultOffset);
3254 NEXT_INSTRUCTION();
3255 }
3256 DEFINE_OPCODE(op_new_func) {
3257 /* new_func dst(r) func(f)
3258
3259 Constructs a new Function instance from function func and
3260 the current scope chain using the original Function
3261 constructor, using the rules for function declarations, and
3262 puts the result in register dst.
3263 */
3264 int dst = (++vPC)->u.operand;
3265 int func = (++vPC)->u.operand;
3266
3267 callFrame[dst] = callFrame->codeBlock()->function(func)->makeFunction(callFrame, callFrame->scopeChain());
3268
3269 ++vPC;
3270 NEXT_INSTRUCTION();
3271 }
3272 DEFINE_OPCODE(op_new_func_exp) {
3273 /* new_func_exp dst(r) func(f)
3274
3275 Constructs a new Function instance from function func and
3276 the current scope chain using the original Function
3277 constructor, using the rules for function expressions, and
3278 puts the result in register dst.
3279 */
3280 int dst = (++vPC)->u.operand;
3281 int func = (++vPC)->u.operand;
3282
3283 callFrame[dst] = callFrame->codeBlock()->functionExpression(func)->makeFunction(callFrame, callFrame->scopeChain());
3284
3285 ++vPC;
3286 NEXT_INSTRUCTION();
3287 }
3288 DEFINE_OPCODE(op_call_eval) {
3289 /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
3290
3291 Call a function named "eval" with no explicit "this" value
3292 (which may therefore be the eval operator). If register
3293 thisVal is the global object, and register func contains
3294 that global object's original global eval function, then
3295 perform the eval operator in local scope (interpreting
3296 the argument registers as for the "call"
3297 opcode). Otherwise, act exactly as the "call" opcode would.
3298 */
3299
3300 int dst = vPC[1].u.operand;
3301 int func = vPC[2].u.operand;
3302 int argCount = vPC[3].u.operand;
3303 int registerOffset = vPC[4].u.operand;
3304
3305 JSValue* funcVal = callFrame[func].jsValue(callFrame);
3306
3307 Register* newCallFrame = callFrame->registers() + registerOffset;
3308 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
3309 JSValue* thisValue = argv[0].jsValue(callFrame);
3310 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();
3311
3312 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
3313 JSValue* result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
3314 if (exceptionValue)
3315 goto vm_throw;
3316 callFrame[dst] = result;
3317
3318 vPC += 5;
3319 NEXT_INSTRUCTION();
3320 }
3321
3322 // We didn't find the blessed version of eval, so process this
3323 // instruction as a normal function call.
3324 // fall through to op_call
3325 }
3326 DEFINE_OPCODE(op_call) {
3327 /* call dst(r) func(r) argCount(n) registerOffset(n)
3328
3329 Perform a function call.
3330
3331 registerOffset is the distance the callFrame pointer should move
3332 before the VM initializes the new call frame's header.
3333
3334 dst is where op_ret should store its result.
3335 */
3336
3337 int dst = vPC[1].u.operand;
3338 int func = vPC[2].u.operand;
3339 int argCount = vPC[3].u.operand;
3340 int registerOffset = vPC[4].u.operand;
3341
3342 JSValue* v = callFrame[func].jsValue(callFrame);
3343
3344 CallData callData;
3345 CallType callType = v->getCallData(callData);
3346
3347 if (callType == CallTypeJS) {
3348 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3349 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3350 CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain);
3351
3352 CallFrame* previousCallFrame = callFrame;
3353
3354 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3355 if (UNLIKELY(!callFrame)) {
3356 callFrame = previousCallFrame;
3357 exceptionValue = createStackOverflowError(callFrame);
3358 goto vm_throw;
3359 }
3360
3361 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3362 vPC = newCodeBlock->instructions().begin();
3363
3364#if ENABLE(OPCODE_STATS)
3365 OpcodeStats::resetLastInstruction();
3366#endif
3367
3368 NEXT_INSTRUCTION();
3369 }
3370
3371 if (callType == CallTypeHost) {
3372 ScopeChainNode* scopeChain = callFrame->scopeChain();
3373 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3374 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
3375
3376 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
3377 ArgList args(thisRegister + 1, argCount - 1);
3378
3379 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3380 JSValue* thisValue = thisRegister->jsValue(callFrame);
3381 if (thisValue == jsNull())
3382 thisValue = callFrame->globalThisValue();
3383
3384 JSValue* returnValue;
3385 {
3386 SamplingTool::HostCallRecord callRecord(m_sampler);
3387 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
3388 }
3389 CHECK_FOR_EXCEPTION();
3390
3391 callFrame[dst] = returnValue;
3392
3393 vPC += 5;
3394 NEXT_INSTRUCTION();
3395 }
3396
3397 ASSERT(callType == CallTypeNone);
3398
3399 exceptionValue = createNotAFunctionError(callFrame, v, vPC, callFrame->codeBlock());
3400 goto vm_throw;
3401 }
3402 DEFINE_OPCODE(op_tear_off_activation) {
3403 /* tear_off_activation activation(r)
3404
3405 Copy all locals and parameters to new memory allocated on
3406 the heap, and make the passed activation use this memory
3407 in the future when looking up entries in the symbol table.
3408 If there is an 'arguments' object, then it will also use
3409 this memory for storing the named parameters, but not any
3410 extra arguments.
3411
3412 This opcode should only be used immediately before op_ret.
3413 */
3414
3415 int src = (++vPC)->u.operand;
3416 ASSERT(callFrame->codeBlock()->needsFullScopeChain());
3417
3418 asActivation(callFrame[src].getJSValue())->copyRegisters(callFrame->optionalCalleeArguments());
3419
3420 ++vPC;
3421 NEXT_INSTRUCTION();
3422 }
3423 DEFINE_OPCODE(op_tear_off_arguments) {
3424 /* tear_off_arguments
3425
3426 Copy all arguments to new memory allocated on the heap,
3427 and make the 'arguments' object use this memory in the
3428 future when looking up named parameters, but not any
3429 extra arguments. If an activation object exists for the
3430 current function context, then the tear_off_activation
3431 opcode should be used instead.
3432
3433 This opcode should only be used immediately before op_ret.
3434 */
3435
3436 ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());
3437
3438 callFrame->optionalCalleeArguments()->copyRegisters();
3439
3440 ++vPC;
3441 NEXT_INSTRUCTION();
3442 }
3443 DEFINE_OPCODE(op_ret) {
3444 /* ret result(r)
3445
3446 Return register result as the return value of the current
3447 function call, writing it into the caller's expected return
3448 value register. In addition, unwind one call frame and
3449 restore the scope chain, code block instruction pointer and
3450 register base to those of the calling function.
3451 */
3452
3453 int result = (++vPC)->u.operand;
3454
3455 if (callFrame->codeBlock()->needsFullScopeChain())
3456 callFrame->scopeChain()->deref();
3457
3458 JSValue* returnValue = callFrame[result].jsValue(callFrame);
3459
3460 vPC = callFrame->returnPC();
3461 int dst = callFrame->returnValueRegister();
3462 callFrame = callFrame->callerFrame();
3463
3464 if (callFrame->hasHostCallFrameFlag())
3465 return returnValue;
3466
3467 callFrame[dst] = returnValue;
3468
3469 NEXT_INSTRUCTION();
3470 }
3471 DEFINE_OPCODE(op_enter) {
3472 /* enter
3473
3474 Initializes local variables to undefined and fills constant
3475 registers with their values. If the code block requires an
3476 activation, enter_with_activation should be used instead.
3477
3478 This opcode should only be used at the beginning of a code
3479 block.
3480 */
3481
3482 size_t i = 0;
3483 CodeBlock* codeBlock = callFrame->codeBlock();
3484
3485 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3486 callFrame[i] = jsUndefined();
3487
3488 for (size_t count = codeBlock->numberOfConstantRegisters(), j = 0; j < count; ++i, ++j)
3489 callFrame[i] = codeBlock->constantRegister(j);
3490
3491 ++vPC;
3492 NEXT_INSTRUCTION();
3493 }
3494 DEFINE_OPCODE(op_enter_with_activation) {
3495 /* enter_with_activation dst(r)
3496
3497 Initializes local variables to undefined, fills constant
3498 registers with their values, creates an activation object,
3499 and places the new activation both in dst and at the top
3500 of the scope chain. If the code block does not require an
3501 activation, enter should be used instead.
3502
3503 This opcode should only be used at the beginning of a code
3504 block.
3505 */
3506
3507 size_t i = 0;
3508 CodeBlock* codeBlock = callFrame->codeBlock();
3509
3510 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3511 callFrame[i] = jsUndefined();
3512
3513 for (size_t count = codeBlock->numberOfConstantRegisters(), j = 0; j < count; ++i, ++j)
3514 callFrame[i] = codeBlock->constantRegister(j);
3515
3516 int dst = (++vPC)->u.operand;
3517 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionBodyNode*>(codeBlock->ownerNode()));
3518 callFrame[dst] = activation;
3519 callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation));
3520
3521 ++vPC;
3522 NEXT_INSTRUCTION();
3523 }
3524 DEFINE_OPCODE(op_convert_this) {
3525 /* convert_this this(r)
3526
3527 Takes the value in the 'this' register, converts it to a
3528 value that is suitable for use as the 'this' value, and
3529 stores it in the 'this' register. This opcode is emitted
3530 to avoid doing the conversion in the caller unnecessarily.
3531
3532 This opcode should only be used at the beginning of a code
3533 block.
3534 */
3535
3536 int thisRegister = (++vPC)->u.operand;
3537 JSValue* thisVal = callFrame[thisRegister].getJSValue();
3538 if (thisVal->needsThisConversion())
3539 callFrame[thisRegister] = thisVal->toThisObject(callFrame);
3540
3541 ++vPC;
3542 NEXT_INSTRUCTION();
3543 }
3544 DEFINE_OPCODE(op_create_arguments) {
3545 /* create_arguments
3546
3547 Creates the 'arguments' object and places it in both the
3548 'arguments' call frame slot and the local 'arguments'
3549 register.
3550
3551 This opcode should only be used at the beginning of a code
3552 block.
3553 */
3554
3555 Arguments* arguments = new (globalData) Arguments(callFrame);
3556 callFrame->setCalleeArguments(arguments);
3557 callFrame[RegisterFile::ArgumentsRegister] = arguments;
3558
3559 ++vPC;
3560 NEXT_INSTRUCTION();
3561 }
3562 DEFINE_OPCODE(op_construct) {
3563 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
3564
3565 Invoke register "func" as a constructor. For JS
3566 functions, the calling convention is exactly as for the
3567 "call" opcode, except that the "this" value is a newly
3568 created Object. For native constructors, no "this"
3569 value is passed. In either case, the argCount and registerOffset
3570 registers are interpreted as for the "call" opcode.
3571
3572 Register proto must contain the prototype property of
3573 register func. This is to enable polymorphic inline
3574 caching of this lookup.
3575 */
3576
3577 int dst = vPC[1].u.operand;
3578 int func = vPC[2].u.operand;
3579 int argCount = vPC[3].u.operand;
3580 int registerOffset = vPC[4].u.operand;
3581 int proto = vPC[5].u.operand;
3582 int thisRegister = vPC[6].u.operand;
3583
3584 JSValue* v = callFrame[func].jsValue(callFrame);
3585
3586 ConstructData constructData;
3587 ConstructType constructType = v->getConstructData(constructData);
3588
3589 if (constructType == ConstructTypeJS) {
3590 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3591 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3592 CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain);
3593
3594 Structure* structure;
3595 JSValue* prototype = callFrame[proto].jsValue(callFrame);
3596 if (prototype->isObject())
3597 structure = asObject(prototype)->inheritorID();
3598 else
3599 structure = callDataScopeChain->globalObject()->emptyObjectStructure();
3600 JSObject* newObject = new (globalData) JSObject(structure);
3601
3602 callFrame[thisRegister] = newObject; // "this" value
3603
3604 CallFrame* previousCallFrame = callFrame;
3605
3606 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3607 if (UNLIKELY(!callFrame)) {
3608 callFrame = previousCallFrame;
3609 exceptionValue = createStackOverflowError(callFrame);
3610 goto vm_throw;
3611 }
3612
3613 callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3614 vPC = newCodeBlock->instructions().begin();
3615
3616#if ENABLE(OPCODE_STATS)
3617 OpcodeStats::resetLastInstruction();
3618#endif
3619
3620 NEXT_INSTRUCTION();
3621 }
3622
3623 if (constructType == ConstructTypeHost) {
3624 ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1);
3625
3626 ScopeChainNode* scopeChain = callFrame->scopeChain();
3627 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3628 newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
3629
3630 JSValue* returnValue;
3631 {
3632 SamplingTool::HostCallRecord callRecord(m_sampler);
3633 returnValue = constructData.native.function(newCallFrame, asObject(v), args);
3634 }
3635 CHECK_FOR_EXCEPTION();
3636 callFrame[dst] = returnValue;
3637
3638 vPC += 7;
3639 NEXT_INSTRUCTION();
3640 }
3641
3642 ASSERT(constructType == ConstructTypeNone);
3643
3644 exceptionValue = createNotAConstructorError(callFrame, v, vPC, callFrame->codeBlock());
3645 goto vm_throw;
3646 }
3647 DEFINE_OPCODE(op_construct_verify) {
3648 /* construct_verify dst(r) override(r)
3649
3650 Verifies that register dst holds an object. If not, moves
3651 the object in register override to register dst.
3652 */
3653
3654 int dst = vPC[1].u.operand;;
3655 if (LIKELY(callFrame[dst].jsValue(callFrame)->isObject())) {
3656 vPC += 3;
3657 NEXT_INSTRUCTION();
3658 }
3659
3660 int override = vPC[2].u.operand;
3661 callFrame[dst] = callFrame[override];
3662
3663 vPC += 3;
3664 NEXT_INSTRUCTION();
3665 }
3666 DEFINE_OPCODE(op_push_scope) {
3667 /* push_scope scope(r)
3668
3669 Converts register scope to object, and pushes it onto the top
3670 of the current scope chain.
3671 */
3672 int scope = (++vPC)->u.operand;
3673 JSValue* v = callFrame[scope].jsValue(callFrame);
3674 JSObject* o = v->toObject(callFrame);
3675 CHECK_FOR_EXCEPTION();
3676
3677 callFrame->setScopeChain(callFrame->scopeChain()->push(o));
3678
3679 ++vPC;
3680 NEXT_INSTRUCTION();
3681 }
3682 DEFINE_OPCODE(op_pop_scope) {
3683 /* pop_scope
3684
3685 Removes the top item from the current scope chain.
3686 */
3687 callFrame->setScopeChain(callFrame->scopeChain()->pop());
3688
3689 ++vPC;
3690 NEXT_INSTRUCTION();
3691 }
3692 DEFINE_OPCODE(op_get_pnames) {
3693 /* get_pnames dst(r) base(r)
3694
3695 Creates a property name list for register base and puts it
3696 in register dst. This is not a true JavaScript value, just
3697 a synthetic value used to keep the iteration state in a
3698 register.
3699 */
3700 int dst = (++vPC)->u.operand;
3701 int base = (++vPC)->u.operand;
3702
3703 callFrame[dst] = JSPropertyNameIterator::create(callFrame, callFrame[base].jsValue(callFrame));
3704 ++vPC;
3705 NEXT_INSTRUCTION();
3706 }
3707 DEFINE_OPCODE(op_next_pname) {
3708 /* next_pname dst(r) iter(r) target(offset)
3709
3710 Tries to copies the next name from property name list in
3711 register iter. If there are names left, then copies one to
3712 register dst, and jumps to offset target. If there are none
3713 left, invalidates the iterator and continues to the next
3714 instruction.
3715 */
3716 int dst = (++vPC)->u.operand;
3717 int iter = (++vPC)->u.operand;
3718 int target = (++vPC)->u.operand;
3719
3720 JSPropertyNameIterator* it = callFrame[iter].propertyNameIterator();
3721 if (JSValue* temp = it->next(callFrame)) {
3722 CHECK_FOR_TIMEOUT();
3723 callFrame[dst] = temp;
3724 vPC += target;
3725 NEXT_INSTRUCTION();
3726 }
3727 it->invalidate();
3728
3729 ++vPC;
3730 NEXT_INSTRUCTION();
3731 }
3732 DEFINE_OPCODE(op_jmp_scopes) {
3733 /* jmp_scopes count(n) target(offset)
3734
3735 Removes the a number of items from the current scope chain
3736 specified by immediate number count, then jumps to offset
3737 target.
3738 */
3739 int count = (++vPC)->u.operand;
3740 int target = (++vPC)->u.operand;
3741
3742 ScopeChainNode* tmp = callFrame->scopeChain();
3743 while (count--)
3744 tmp = tmp->pop();
3745 callFrame->setScopeChain(tmp);
3746
3747 vPC += target;
3748 NEXT_INSTRUCTION();
3749 }
3750#if HAVE(COMPUTED_GOTO)
3751 // Appease GCC
3752 goto *(&&skip_new_scope);
3753#endif
3754 DEFINE_OPCODE(op_push_new_scope) {
3755 /* new_scope dst(r) property(id) value(r)
3756
3757 Constructs a new StaticScopeObject with property set to value. That scope
3758 object is then pushed onto the ScopeChain. The scope object is then stored
3759 in dst for GC.
3760 */
3761 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));
3762
3763 vPC += 4;
3764 NEXT_INSTRUCTION();
3765 }
3766#if HAVE(COMPUTED_GOTO)
3767 skip_new_scope:
3768#endif
3769 DEFINE_OPCODE(op_catch) {
3770 /* catch ex(r)
3771
3772 Retrieves the VMs current exception and puts it in register
3773 ex. This is only valid after an exception has been raised,
3774 and usually forms the beginning of an exception handler.
3775 */
3776 ASSERT(exceptionValue);
3777 ASSERT(!globalData->exception);
3778 int ex = (++vPC)->u.operand;
3779 callFrame[ex] = exceptionValue;
3780 exceptionValue = noValue();
3781
3782 ++vPC;
3783 NEXT_INSTRUCTION();
3784 }
3785 DEFINE_OPCODE(op_throw) {
3786 /* throw ex(r)
3787
3788 Throws register ex as an exception. This involves three
3789 steps: first, it is set as the current exception in the
3790 VM's internal state, then the stack is unwound until an
3791 exception handler or a native code boundary is found, and
3792 then control resumes at the exception handler if any or
3793 else the script returns control to the nearest native caller.
3794 */
3795
3796 int ex = (++vPC)->u.operand;
3797 exceptionValue = callFrame[ex].jsValue(callFrame);
3798
3799 handlerVPC = throwException(callFrame, exceptionValue, vPC, true);
3800 if (!handlerVPC) {
3801 *exception = exceptionValue;
3802 return jsNull();
3803 }
3804
3805 vPC = handlerVPC;
3806 NEXT_INSTRUCTION();
3807 }
3808 DEFINE_OPCODE(op_unexpected_load) {
3809 /* unexpected_load load dst(r) src(k)
3810
3811 Copies constant src to register dst.
3812 */
3813 int dst = (++vPC)->u.operand;
3814 int src = (++vPC)->u.operand;
3815 callFrame[dst] = callFrame->codeBlock()->unexpectedConstant(src);
3816
3817 ++vPC;
3818 NEXT_INSTRUCTION();
3819 }
3820 DEFINE_OPCODE(op_new_error) {
3821 /* new_error dst(r) type(n) message(k)
3822
3823 Constructs a new Error instance using the original
3824 constructor, using immediate number n as the type and
3825 constant message as the message string. The result is
3826 written to register dst.
3827 */
3828 int dst = (++vPC)->u.operand;
3829 int type = (++vPC)->u.operand;
3830 int message = (++vPC)->u.operand;
3831
3832 CodeBlock* codeBlock = callFrame->codeBlock();
3833 callFrame[dst] = Error::create(callFrame, (ErrorType)type, codeBlock->unexpectedConstant(message)->toString(callFrame), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL());
3834
3835 ++vPC;
3836 NEXT_INSTRUCTION();
3837 }
3838 DEFINE_OPCODE(op_end) {
3839 /* end result(r)
3840
3841 Return register result as the value of a global or eval
3842 program. Return control to the calling native code.
3843 */
3844
3845 if (callFrame->codeBlock()->needsFullScopeChain()) {
3846 ScopeChainNode* scopeChain = callFrame->scopeChain();
3847 ASSERT(scopeChain->refCount > 1);
3848 scopeChain->deref();
3849 }
3850 int result = (++vPC)->u.operand;
3851 return callFrame[result].jsValue(callFrame);
3852 }
3853 DEFINE_OPCODE(op_put_getter) {
3854 /* put_getter base(r) property(id) function(r)
3855
3856 Sets register function on register base as the getter named
3857 by identifier property. Base and function are assumed to be
3858 objects as this op should only be used for getters defined
3859 in object literal form.
3860
3861 Unlike many opcodes, this one does not write any output to
3862 the register file.
3863 */
3864 int base = (++vPC)->u.operand;
3865 int property = (++vPC)->u.operand;
3866 int function = (++vPC)->u.operand;
3867
3868 ASSERT(callFrame[base].jsValue(callFrame)->isObject());
3869 JSObject* baseObj = asObject(callFrame[base].jsValue(callFrame));
3870 Identifier& ident = callFrame->codeBlock()->identifier(property);
3871 ASSERT(callFrame[function].jsValue(callFrame)->isObject());
3872 baseObj->defineGetter(callFrame, ident, asObject(callFrame[function].jsValue(callFrame)));
3873
3874 ++vPC;
3875 NEXT_INSTRUCTION();
3876 }
3877 DEFINE_OPCODE(op_put_setter) {
3878 /* put_setter base(r) property(id) function(r)
3879
3880 Sets register function on register base as the setter named
3881 by identifier property. Base and function are assumed to be
3882 objects as this op should only be used for setters defined
3883 in object literal form.
3884
3885 Unlike many opcodes, this one does not write any output to
3886 the register file.
3887 */
3888 int base = (++vPC)->u.operand;
3889 int property = (++vPC)->u.operand;
3890 int function = (++vPC)->u.operand;
3891
3892 ASSERT(callFrame[base].jsValue(callFrame)->isObject());
3893 JSObject* baseObj = asObject(callFrame[base].jsValue(callFrame));
3894 Identifier& ident = callFrame->codeBlock()->identifier(property);
3895 ASSERT(callFrame[function].jsValue(callFrame)->isObject());
3896 baseObj->defineSetter(callFrame, ident, asObject(callFrame[function].jsValue(callFrame)));
3897
3898 ++vPC;
3899 NEXT_INSTRUCTION();
3900 }
3901 DEFINE_OPCODE(op_jsr) {
3902 /* jsr retAddrDst(r) target(offset)
3903
3904 Places the address of the next instruction into the retAddrDst
3905 register and jumps to offset target from the current instruction.
3906 */
3907 int retAddrDst = (++vPC)->u.operand;
3908 int target = (++vPC)->u.operand;
3909 callFrame[retAddrDst] = vPC + 1;
3910
3911 vPC += target;
3912 NEXT_INSTRUCTION();
3913 }
3914 DEFINE_OPCODE(op_sret) {
3915 /* sret retAddrSrc(r)
3916
3917 Jumps to the address stored in the retAddrSrc register. This
3918 differs from op_jmp because the target address is stored in a
3919 register, not as an immediate.
3920 */
3921 int retAddrSrc = (++vPC)->u.operand;
3922 vPC = callFrame[retAddrSrc].vPC();
3923 NEXT_INSTRUCTION();
3924 }
3925 DEFINE_OPCODE(op_debug) {
3926 /* debug debugHookID(n) firstLine(n) lastLine(n)
3927
3928 Notifies the debugger of the current state of execution. This opcode
3929 is only generated while the debugger is attached.
3930 */
3931 int debugHookID = (++vPC)->u.operand;
3932 int firstLine = (++vPC)->u.operand;
3933 int lastLine = (++vPC)->u.operand;
3934
3935 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3936
3937 ++vPC;
3938 NEXT_INSTRUCTION();
3939 }
3940 DEFINE_OPCODE(op_profile_will_call) {
3941 /* op_profile_will_call function(r)
3942
3943 Notifies the profiler of the beginning of a function call. This opcode
3944 is only generated if developer tools are enabled.
3945 */
3946 int function = vPC[1].u.operand;
3947
3948 if (*enabledProfilerReference)
3949 (*enabledProfilerReference)->willExecute(callFrame, callFrame[function].jsValue(callFrame));
3950
3951 vPC += 2;
3952 NEXT_INSTRUCTION();
3953 }
3954 DEFINE_OPCODE(op_profile_did_call) {
3955 /* op_profile_did_call function(r)
3956
3957 Notifies the profiler of the end of a function call. This opcode
3958 is only generated if developer tools are enabled.
3959 */
3960 int function = vPC[1].u.operand;
3961
3962 if (*enabledProfilerReference)
3963 (*enabledProfilerReference)->didExecute(callFrame, callFrame[function].jsValue(callFrame));
3964
3965 vPC += 2;
3966 NEXT_INSTRUCTION();
3967 }
3968 vm_throw: {
3969 globalData->exception = noValue();
3970 if (!tickCount) {
3971 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3972 // cannot fathom if we don't assign to the exceptionValue before branching)
3973 exceptionValue = createInterruptedExecutionException(globalData);
3974 }
3975 handlerVPC = throwException(callFrame, exceptionValue, vPC, false);
3976 if (!handlerVPC) {
3977 *exception = exceptionValue;
3978 return jsNull();
3979 }
3980 vPC = handlerVPC;
3981 NEXT_INSTRUCTION();
3982 }
3983 }
3984#if !HAVE(COMPUTED_GOTO)
3985 } // iterator loop ends
3986#endif
3987 #undef NEXT_INSTRUCTION
3988 #undef DEFINE_OPCODE
3989 #undef CHECK_FOR_EXCEPTION
3990 #undef CHECK_FOR_TIMEOUT
3991}
3992
3993JSValue* Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
3994{
3995 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
3996 if (!functionCallFrame)
3997 return jsNull();
3998
3999 CodeBlock* codeBlock = functionCallFrame->codeBlock();
4000 if (codeBlock->usesArguments()) {
4001 ASSERT(codeBlock->codeType() == FunctionCode);
4002 SymbolTable& symbolTable = codeBlock->symbolTable();
4003 int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();
4004 return functionCallFrame[argumentsIndex].jsValue(callFrame);
4005 }
4006
4007 Arguments* arguments = functionCallFrame->optionalCalleeArguments();
4008 if (!arguments) {
4009 arguments = new (functionCallFrame) Arguments(functionCallFrame);
4010 arguments->copyRegisters();
4011 callFrame->setCalleeArguments(arguments);
4012 }
4013
4014 return arguments;
4015}
4016
4017JSValue* Interpreter::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const
4018{
4019 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
4020 if (!functionCallFrame)
4021 return jsNull();
4022
4023 CallFrame* callerFrame = functionCallFrame->callerFrame();
4024 if (callerFrame->hasHostCallFrameFlag())
4025 return jsNull();
4026
4027 JSValue* caller = callerFrame->callee();
4028 if (!caller)
4029 return jsNull();
4030
4031 return caller;
4032}
4033
4034void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue*& function) const
4035{
4036 function = noValue();
4037 lineNumber = -1;
4038 sourceURL = UString();
4039
4040 CallFrame* callerFrame = callFrame->callerFrame();
4041 if (callerFrame->hasHostCallFrameFlag())
4042 return;
4043
4044 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
4045 if (!callerCodeBlock)
4046 return;
4047
4048 Instruction* vPC = vPCForPC(callerCodeBlock, callFrame->returnPC());
4049 lineNumber = callerCodeBlock->lineNumberForVPC(vPC - 1);
4050 sourceID = callerCodeBlock->ownerNode()->sourceID();
4051 sourceURL = callerCodeBlock->ownerNode()->sourceURL();
4052 function = callerFrame->callee();
4053}
4054
4055CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunction* function)
4056{
4057 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
4058 if (candidate->callee() == function)
4059 return candidate;
4060 }
4061 return 0;
4062}
4063
4064#if ENABLE(JIT)
4065
4066NEVER_INLINE void Interpreter::tryCTICachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const PutPropertySlot& slot)
4067{
4068 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
4069
4070 if (JSImmediate::isImmediate(baseValue))
4071 return;
4072
4073 // Uncacheable: give up.
4074 if (!slot.isCacheable()) {
4075 ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(cti_op_put_by_id_generic));
4076 return;
4077 }
4078
4079 JSCell* baseCell = asCell(baseValue);
4080 Structure* structure = baseCell->structure();
4081
4082 if (structure->isDictionary()) {
4083 ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(cti_op_put_by_id_generic));
4084 return;
4085 }
4086
4087 // In the interpreter the last structure is trapped here; in CTI we use the
4088 // *_second method to achieve a similar (but not quite the same) effect.
4089
4090 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(returnAddress);
4091 Instruction* vPC = codeBlock->instructions().begin() + vPCIndex;
4092
4093 // Cache hit: Specialize instruction and ref Structures.
4094
4095 // If baseCell != base, then baseCell must be a proxy for another object.
4096 if (baseCell != slot.base()) {
4097 ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(cti_op_put_by_id_generic));
4098 return;
4099 }
4100
4101 // Structure transition, cache transition info
4102 if (slot.type() == PutPropertySlot::NewProperty) {
4103 vPC[0] = getOpcode(op_put_by_id_transition);
4104 vPC[4] = structure->previousID();
4105 vPC[5] = structure;
4106 StructureChain* chain = structure->cachedPrototypeChain();
4107 if (!chain) {
4108 chain = cachePrototypeChain(callFrame, structure);
4109 if (!chain) {
4110 // This happens if someone has manually inserted null into the prototype chain
4111 vPC[0] = getOpcode(op_put_by_id_generic);
4112 return;
4113 }
4114 }
4115 vPC[6] = chain;
4116 vPC[7] = slot.cachedOffset();
4117 codeBlock->refStructures(vPC);
4118 JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, structure->previousID(), structure, slot.cachedOffset(), chain, returnAddress);
4119 return;
4120 }
4121
4122 vPC[0] = getOpcode(op_put_by_id_replace);
4123 vPC[4] = structure;
4124 vPC[5] = slot.cachedOffset();
4125 codeBlock->refStructures(vPC);
4126
4127#if USE(CTI_REPATCH_PIC)
4128 UNUSED_PARAM(callFrame);
4129 JIT::patchPutByIdReplace(codeBlock, structure, slot.cachedOffset(), returnAddress);
4130#else
4131 JIT::compilePutByIdReplace(callFrame->scopeChain()->globalData, callFrame, codeBlock, structure, slot.cachedOffset(), returnAddress);
4132#endif
4133}
4134
4135NEVER_INLINE void Interpreter::tryCTICacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
4136{
4137 // FIXME: Write a test that proves we need to check for recursion here just
4138 // like the interpreter does, then add a check for recursion.
4139
4140 // FIXME: Cache property access for immediates.
4141 if (JSImmediate::isImmediate(baseValue)) {
4142 ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(cti_op_get_by_id_generic));
4143 return;
4144 }
4145
4146 if (isJSArray(baseValue) && propertyName == callFrame->propertyNames().length) {
4147#if USE(CTI_REPATCH_PIC)
4148 JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress);
4149#else
4150 ctiRepatchCallByReturnAddress(returnAddress, m_ctiArrayLengthTrampoline);
4151#endif
4152 return;
4153 }
4154 if (isJSString(baseValue) && propertyName == callFrame->propertyNames().length) {
4155 // The tradeoff of compiling an repatched inline string length access routine does not seem
4156 // to pay off, so we currently only do this for arrays.
4157 ctiRepatchCallByReturnAddress(returnAddress, m_ctiStringLengthTrampoline);
4158 return;
4159 }
4160
4161 // Uncacheable: give up.
4162 if (!slot.isCacheable()) {
4163 ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(cti_op_get_by_id_generic));
4164 return;
4165 }
4166
4167 JSCell* baseCell = asCell(baseValue);
4168 Structure* structure = baseCell->structure();
4169
4170 if (structure->isDictionary()) {
4171 ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(cti_op_get_by_id_generic));
4172 return;
4173 }
4174
4175 // In the interpreter the last structure is trapped here; in CTI we use the
4176 // *_second method to achieve a similar (but not quite the same) effect.
4177
4178 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(returnAddress);
4179 Instruction* vPC = codeBlock->instructions().begin() + vPCIndex;
4180
4181 // Cache hit: Specialize instruction and ref Structures.
4182
4183 if (slot.slotBase() == baseValue) {
4184 // set this up, so derefStructures can do it's job.
4185 vPC[0] = getOpcode(op_get_by_id_self);
4186 vPC[4] = structure;
4187 vPC[5] = slot.cachedOffset();
4188 codeBlock->refStructures(vPC);
4189
4190#if USE(CTI_REPATCH_PIC)
4191 JIT::patchGetByIdSelf(codeBlock, structure, slot.cachedOffset(), returnAddress);
4192#else
4193 JIT::compileGetByIdSelf(callFrame->scopeChain()->globalData, callFrame, codeBlock, structure, slot.cachedOffset(), returnAddress);
4194#endif
4195 return;
4196 }
4197
4198 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
4199 ASSERT(slot.slotBase()->isObject());
4200
4201 JSObject* slotBaseObject = asObject(slot.slotBase());
4202
4203 // Heavy access to a prototype is a good indication that it's not being
4204 // used as a dictionary.
4205 if (slotBaseObject->structure()->isDictionary()) {
4206 RefPtr<Structure> transition = Structure::fromDictionaryTransition(slotBaseObject->structure());
4207 slotBaseObject->setStructure(transition.release());
4208 asObject(baseValue)->structure()->setCachedPrototypeChain(0);
4209 }
4210
4211 vPC[0] = getOpcode(op_get_by_id_proto);
4212 vPC[4] = structure;
4213 vPC[5] = slotBaseObject->structure();
4214 vPC[6] = slot.cachedOffset();
4215 codeBlock->refStructures(vPC);
4216
4217 JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, structure, slotBaseObject->structure(), slot.cachedOffset(), returnAddress);
4218 return;
4219 }
4220
4221 size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);
4222 if (!count) {
4223 vPC[0] = getOpcode(op_get_by_id_generic);
4224 return;
4225 }
4226
4227 StructureChain* chain = structure->cachedPrototypeChain();
4228 if (!chain)
4229 chain = cachePrototypeChain(callFrame, structure);
4230 ASSERT(chain);
4231
4232 vPC[0] = getOpcode(op_get_by_id_chain);
4233 vPC[4] = structure;
4234 vPC[5] = chain;
4235 vPC[6] = count;
4236 vPC[7] = slot.cachedOffset();
4237 codeBlock->refStructures(vPC);
4238
4239 JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, structure, chain, count, slot.cachedOffset(), returnAddress);
4240}
4241
4242#ifndef NDEBUG
4243
4244extern "C" {
4245
4246static void jscGeneratedNativeCode()
4247{
4248 // When executing a CTI function (which might do an allocation), we hack the return address
4249 // to pretend to be executing this function, to keep stack logging tools from blowing out
4250 // memory.
4251}
4252
4253}
4254
4255struct StackHack {
4256 ALWAYS_INLINE StackHack(void** location)
4257 {
4258 returnAddressLocation = location;
4259 savedReturnAddress = *returnAddressLocation;
4260 ctiSetReturnAddress(returnAddressLocation, reinterpret_cast<void*>(jscGeneratedNativeCode));
4261 }
4262 ALWAYS_INLINE ~StackHack()
4263 {
4264 ctiSetReturnAddress(returnAddressLocation, savedReturnAddress);
4265 }
4266
4267 void** returnAddressLocation;
4268 void* savedReturnAddress;
4269};
4270
4271#define CTI_STACK_HACK() StackHack stackHack(&CTI_RETURN_ADDRESS_SLOT)
4272#define CTI_SET_RETURN_ADDRESS(address) stackHack.savedReturnAddress = address
4273#define CTI_RETURN_ADDRESS stackHack.savedReturnAddress
4274
4275#else
4276
4277#define CTI_STACK_HACK() (void)0
4278#define CTI_SET_RETURN_ADDRESS(address) ctiSetReturnAddress(&CTI_RETURN_ADDRESS_SLOT, address);
4279#define CTI_RETURN_ADDRESS CTI_RETURN_ADDRESS_SLOT
4280
4281#endif
4282
4283// The reason this is not inlined is to avoid having to do a PIC branch
4284// to get the address of the ctiVMThrowTrampoline function. It's also
4285// good to keep the code size down by leaving as much of the exception
4286// handling code out of line as possible.
4287static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot)
4288{
4289 ASSERT(globalData->exception);
4290 globalData->exceptionLocation = exceptionLocation;
4291 ctiSetReturnAddress(&returnAddressSlot, reinterpret_cast<void*>(ctiVMThrowTrampoline));
4292}
4293
4294static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot)
4295{
4296 globalData->exception = createStackOverflowError(callFrame);
4297 returnToThrowTrampoline(globalData, exceptionLocation, returnAddressSlot);
4298}
4299
4300#define VM_THROW_EXCEPTION() \
4301 do { \
4302 VM_THROW_EXCEPTION_AT_END(); \
4303 return 0; \
4304 } while (0)
4305#define VM_THROW_EXCEPTION_2() \
4306 do { \
4307 VM_THROW_EXCEPTION_AT_END(); \
4308 VoidPtrPairValue pair = {{ 0, 0 }}; \
4309 return pair.i; \
4310 } while (0)
4311#define VM_THROW_EXCEPTION_AT_END() \
4312 returnToThrowTrampoline(ARG_globalData, CTI_RETURN_ADDRESS, CTI_RETURN_ADDRESS)
4313
4314#define CHECK_FOR_EXCEPTION() \
4315 do { \
4316 if (UNLIKELY(ARG_globalData->exception != noValue())) \
4317 VM_THROW_EXCEPTION(); \
4318 } while (0)
4319#define CHECK_FOR_EXCEPTION_AT_END() \
4320 do { \
4321 if (UNLIKELY(ARG_globalData->exception != noValue())) \
4322 VM_THROW_EXCEPTION_AT_END(); \
4323 } while (0)
4324#define CHECK_FOR_EXCEPTION_VOID() \
4325 do { \
4326 if (UNLIKELY(ARG_globalData->exception != noValue())) { \
4327 VM_THROW_EXCEPTION_AT_END(); \
4328 return; \
4329 } \
4330 } while (0)
4331
4332JSObject* Interpreter::cti_op_convert_this(CTI_ARGS)
4333{
4334 CTI_STACK_HACK();
4335
4336 JSValue* v1 = ARG_src1;
4337 CallFrame* callFrame = ARG_callFrame;
4338
4339 JSObject* result = v1->toThisObject(callFrame);
4340 CHECK_FOR_EXCEPTION_AT_END();
4341 return result;
4342}
4343
4344void Interpreter::cti_op_end(CTI_ARGS)
4345{
4346 CTI_STACK_HACK();
4347
4348 ScopeChainNode* scopeChain = ARG_callFrame->scopeChain();
4349 ASSERT(scopeChain->refCount > 1);
4350 scopeChain->deref();
4351}
4352
4353JSValue* Interpreter::cti_op_add(CTI_ARGS)
4354{
4355 CTI_STACK_HACK();
4356
4357 JSValue* v1 = ARG_src1;
4358 JSValue* v2 = ARG_src2;
4359
4360 double left;
4361 double right = 0.0;
4362
4363 bool rightIsNumber = fastIsNumber(v2, right);
4364 if (rightIsNumber && fastIsNumber(v1, left))
4365 return jsNumber(ARG_globalData, left + right);
4366
4367 CallFrame* callFrame = ARG_callFrame;
4368
4369 bool leftIsString = v1->isString();
4370 if (leftIsString && v2->isString()) {
4371 RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep());
4372 if (UNLIKELY(!value)) {
4373 throwOutOfMemoryError(callFrame);
4374 VM_THROW_EXCEPTION();
4375 }
4376
4377 return jsString(ARG_globalData, value.release());
4378 }
4379
4380 if (rightIsNumber & leftIsString) {
4381 RefPtr<UString::Rep> value = JSImmediate::isImmediate(v2) ?
4382 concatenate(asString(v1)->value().rep(), JSImmediate::getTruncatedInt32(v2)) :
4383 concatenate(asString(v1)->value().rep(), right);
4384
4385 if (UNLIKELY(!value)) {
4386 throwOutOfMemoryError(callFrame);
4387 VM_THROW_EXCEPTION();
4388 }
4389 return jsString(ARG_globalData, value.release());
4390 }
4391
4392 // All other cases are pretty uncommon
4393 JSValue* result = jsAddSlowCase(callFrame, v1, v2);
4394 CHECK_FOR_EXCEPTION_AT_END();
4395 return result;
4396}
4397
4398JSValue* Interpreter::cti_op_pre_inc(CTI_ARGS)
4399{
4400 CTI_STACK_HACK();
4401
4402 JSValue* v = ARG_src1;
4403
4404 CallFrame* callFrame = ARG_callFrame;
4405 JSValue* result = jsNumber(ARG_globalData, v->toNumber(callFrame) + 1);
4406 CHECK_FOR_EXCEPTION_AT_END();
4407 return result;
4408}
4409
4410int Interpreter::cti_timeout_check(CTI_ARGS)
4411{
4412 CTI_STACK_HACK();
4413 Interpreter* interpreter = ARG_globalData->interpreter;
4414
4415 if (interpreter->checkTimeout(ARG_callFrame->dynamicGlobalObject())) {
4416 ARG_globalData->exception = createInterruptedExecutionException(ARG_globalData);
4417 VM_THROW_EXCEPTION_AT_END();
4418 }
4419
4420 return interpreter->m_ticksUntilNextTimeoutCheck;
4421}
4422
4423void Interpreter::cti_register_file_check(CTI_ARGS)
4424{
4425 CTI_STACK_HACK();
4426
4427 if (LIKELY(ARG_registerFile->grow(ARG_callFrame + ARG_callFrame->codeBlock()->m_numCalleeRegisters)))
4428 return;
4429
4430 // Rewind to the previous call frame because op_call already optimistically
4431 // moved the call frame forward.
4432 CallFrame* oldCallFrame = ARG_callFrame->callerFrame();
4433 ARG_setCallFrame(oldCallFrame);
4434 throwStackOverflowError(oldCallFrame, ARG_globalData, oldCallFrame->returnPC(), CTI_RETURN_ADDRESS);
4435}
4436
4437int Interpreter::cti_op_loop_if_less(CTI_ARGS)
4438{
4439 CTI_STACK_HACK();
4440
4441 JSValue* src1 = ARG_src1;
4442 JSValue* src2 = ARG_src2;
4443 CallFrame* callFrame = ARG_callFrame;
4444
4445 bool result = jsLess(callFrame, src1, src2);
4446 CHECK_FOR_EXCEPTION_AT_END();
4447 return result;
4448}
4449
4450int Interpreter::cti_op_loop_if_lesseq(CTI_ARGS)
4451{
4452 CTI_STACK_HACK();
4453
4454 JSValue* src1 = ARG_src1;
4455 JSValue* src2 = ARG_src2;
4456 CallFrame* callFrame = ARG_callFrame;
4457
4458 bool result = jsLessEq(callFrame, src1, src2);
4459 CHECK_FOR_EXCEPTION_AT_END();
4460 return result;
4461}
4462
4463JSObject* Interpreter::cti_op_new_object(CTI_ARGS)
4464{
4465 CTI_STACK_HACK();
4466
4467 return constructEmptyObject(ARG_callFrame);
4468}
4469
4470void Interpreter::cti_op_put_by_id(CTI_ARGS)
4471{
4472 CTI_STACK_HACK();
4473
4474 CallFrame* callFrame = ARG_callFrame;
4475 Identifier& ident = *ARG_id2;
4476
4477 PutPropertySlot slot;
4478 ARG_src1->put(callFrame, ident, ARG_src3, slot);
4479
4480 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_put_by_id_second));
4481
4482 CHECK_FOR_EXCEPTION_AT_END();
4483}
4484
4485void Interpreter::cti_op_put_by_id_second(CTI_ARGS)
4486{
4487 CTI_STACK_HACK();
4488
4489 PutPropertySlot slot;
4490 ARG_src1->put(ARG_callFrame, *ARG_id2, ARG_src3, slot);
4491 ARG_globalData->interpreter->tryCTICachePutByID(ARG_callFrame, ARG_callFrame->codeBlock(), CTI_RETURN_ADDRESS, ARG_src1, slot);
4492 CHECK_FOR_EXCEPTION_AT_END();
4493}
4494
4495void Interpreter::cti_op_put_by_id_generic(CTI_ARGS)
4496{
4497 CTI_STACK_HACK();
4498
4499 PutPropertySlot slot;
4500 ARG_src1->put(ARG_callFrame, *ARG_id2, ARG_src3, slot);
4501 CHECK_FOR_EXCEPTION_AT_END();
4502}
4503
4504void Interpreter::cti_op_put_by_id_fail(CTI_ARGS)
4505{
4506 CTI_STACK_HACK();
4507
4508 CallFrame* callFrame = ARG_callFrame;
4509 Identifier& ident = *ARG_id2;
4510
4511 PutPropertySlot slot;
4512 ARG_src1->put(callFrame, ident, ARG_src3, slot);
4513
4514 CHECK_FOR_EXCEPTION_AT_END();
4515}
4516
4517JSValue* Interpreter::cti_op_get_by_id(CTI_ARGS)
4518{
4519 CTI_STACK_HACK();
4520
4521 CallFrame* callFrame = ARG_callFrame;
4522 Identifier& ident = *ARG_id2;
4523
4524 JSValue* baseValue = ARG_src1;
4525 PropertySlot slot(baseValue);
4526 JSValue* result = baseValue->get(callFrame, ident, slot);
4527
4528 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_second));
4529
4530 CHECK_FOR_EXCEPTION_AT_END();
4531 return result;
4532}
4533
4534JSValue* Interpreter::cti_op_get_by_id_second(CTI_ARGS)
4535{
4536 CTI_STACK_HACK();
4537
4538 CallFrame* callFrame = ARG_callFrame;
4539 Identifier& ident = *ARG_id2;
4540
4541 JSValue* baseValue = ARG_src1;
4542 PropertySlot slot(baseValue);
4543 JSValue* result = baseValue->get(callFrame, ident, slot);
4544
4545 ARG_globalData->interpreter->tryCTICacheGetByID(callFrame, callFrame->codeBlock(), CTI_RETURN_ADDRESS, baseValue, ident, slot);
4546
4547 CHECK_FOR_EXCEPTION_AT_END();
4548 return result;
4549}
4550
4551JSValue* Interpreter::cti_op_get_by_id_generic(CTI_ARGS)
4552{
4553 CTI_STACK_HACK();
4554
4555 CallFrame* callFrame = ARG_callFrame;
4556 Identifier& ident = *ARG_id2;
4557
4558 JSValue* baseValue = ARG_src1;
4559 PropertySlot slot(baseValue);
4560 JSValue* result = baseValue->get(callFrame, ident, slot);
4561
4562 CHECK_FOR_EXCEPTION_AT_END();
4563 return result;
4564}
4565
4566JSValue* Interpreter::cti_op_get_by_id_self_fail(CTI_ARGS)
4567{
4568 CTI_STACK_HACK();
4569
4570 CallFrame* callFrame = ARG_callFrame;
4571 Identifier& ident = *ARG_id2;
4572
4573 JSValue* baseValue = ARG_src1;
4574 PropertySlot slot(baseValue);
4575 JSValue* result = baseValue->get(callFrame, ident, slot);
4576
4577 CHECK_FOR_EXCEPTION();
4578
4579 if (baseValue->isObject()
4580 && slot.isCacheable()
4581 && !asCell(baseValue)->structure()->isDictionary()
4582 && slot.slotBase() == baseValue) {
4583
4584 CodeBlock* codeBlock = callFrame->codeBlock();
4585 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(CTI_RETURN_ADDRESS);
4586 Instruction* vPC = codeBlock->instructions().begin() + vPCIndex;
4587
4588 ASSERT(slot.slotBase()->isObject());
4589
4590 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(CTI_RETURN_ADDRESS);
4591
4592 PolymorphicAccessStructureList* polymorphicStructureList;
4593 int listIndex = 1;
4594
4595 if (vPC[0].u.opcode == ARG_globalData->interpreter->getOpcode(op_get_by_id_self)) {
4596 ASSERT(!stubInfo->stubRoutine);
4597 polymorphicStructureList = new PolymorphicAccessStructureList(vPC[5].u.operand, 0, vPC[4].u.structure);
4598
4599 vPC[0] = ARG_globalData->interpreter->getOpcode(op_get_by_id_self_list);
4600 vPC[4] = polymorphicStructureList;
4601 vPC[5] = 2;
4602 } else {
4603 polymorphicStructureList = vPC[4].u.polymorphicStructures;
4604 listIndex = vPC[5].u.operand;
4605
4606 vPC[5] = listIndex + 1;
4607 }
4608
4609 JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), slot.cachedOffset());
4610
4611 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
4612 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_generic));
4613 } else {
4614 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_generic));
4615 }
4616 return result;
4617}
4618
4619static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(Interpreter* interpreter, StructureStubInfo* stubInfo, Instruction* vPC, int& listIndex)
4620{
4621 PolymorphicAccessStructureList* prototypeStructureList;
4622 listIndex = 1;
4623
4624 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
4625 prototypeStructureList = new PolymorphicAccessStructureList(vPC[6].u.operand, stubInfo->stubRoutine, vPC[4].u.structure, vPC[5].u.structure);
4626 stubInfo->stubRoutine = 0;
4627
4628 vPC[0] = interpreter->getOpcode(op_get_by_id_proto_list);
4629 vPC[4] = prototypeStructureList;
4630 vPC[5] = 2;
4631 } else if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
4632 prototypeStructureList = new PolymorphicAccessStructureList(vPC[6].u.operand, stubInfo->stubRoutine, vPC[4].u.structure, vPC[5].u.structureChain);
4633 stubInfo->stubRoutine = 0;
4634
4635 vPC[0] = interpreter->getOpcode(op_get_by_id_proto_list);
4636 vPC[4] = prototypeStructureList;
4637 vPC[5] = 2;
4638 } else {
4639 ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list));
4640 prototypeStructureList = vPC[4].u.polymorphicStructures;
4641 listIndex = vPC[5].u.operand;
4642 vPC[5] = listIndex + 1;
4643
4644 ASSERT(listIndex < POLYMORPHIC_LIST_CACHE_SIZE);
4645 }
4646
4647 return prototypeStructureList;
4648}
4649
4650JSValue* Interpreter::cti_op_get_by_id_proto_list(CTI_ARGS)
4651{
4652 CTI_STACK_HACK();
4653
4654 CallFrame* callFrame = ARG_callFrame;
4655
4656 JSValue* baseValue = ARG_src1;
4657 PropertySlot slot(baseValue);
4658 JSValue* result = baseValue->get(callFrame, *ARG_id2, slot);
4659
4660 CHECK_FOR_EXCEPTION();
4661
4662 if (!baseValue->isObject() || !slot.isCacheable() || asCell(baseValue)->structure()->isDictionary()) {
4663 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_fail));
4664 return result;
4665 }
4666
4667 Structure* structure = asCell(baseValue)->structure();
4668 CodeBlock* codeBlock = callFrame->codeBlock();
4669 Instruction* vPC = codeBlock->instructions().begin() + codeBlock->jitReturnAddressVPCMap().get(CTI_RETURN_ADDRESS);
4670
4671 ASSERT(slot.slotBase()->isObject());
4672 JSObject* slotBaseObject = asObject(slot.slotBase());
4673
4674 if (slot.slotBase() == baseValue)
4675 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_fail));
4676 else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) {
4677 // Heavy access to a prototype is a good indication that it's not being
4678 // used as a dictionary.
4679 if (slotBaseObject->structure()->isDictionary()) {
4680 RefPtr<Structure> transition = Structure::fromDictionaryTransition(slotBaseObject->structure());
4681 slotBaseObject->setStructure(transition.release());
4682 asObject(baseValue)->structure()->setCachedPrototypeChain(0);
4683 }
4684
4685 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(CTI_RETURN_ADDRESS);
4686 int listIndex;
4687 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(ARG_globalData->interpreter, stubInfo, vPC, listIndex);
4688
4689 JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), slot.cachedOffset());
4690
4691 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
4692 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_list_full));
4693 } else if (size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot)) {
4694 StructureChain* chain = structure->cachedPrototypeChain();
4695 if (!chain)
4696 chain = cachePrototypeChain(callFrame, structure);
4697 ASSERT(chain);
4698
4699 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(CTI_RETURN_ADDRESS);
4700 int listIndex;
4701 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(ARG_globalData->interpreter, stubInfo, vPC, listIndex);
4702
4703 JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, chain, count, slot.cachedOffset());
4704
4705 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
4706 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_list_full));
4707 } else
4708 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_fail));
4709
4710 return result;
4711}
4712
4713JSValue* Interpreter::cti_op_get_by_id_proto_list_full(CTI_ARGS)
4714{
4715 CTI_STACK_HACK();
4716
4717 JSValue* baseValue = ARG_src1;
4718 PropertySlot slot(baseValue);
4719 JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
4720
4721 CHECK_FOR_EXCEPTION_AT_END();
4722 return result;
4723}
4724
4725JSValue* Interpreter::cti_op_get_by_id_proto_fail(CTI_ARGS)
4726{
4727 CTI_STACK_HACK();
4728
4729 JSValue* baseValue = ARG_src1;
4730 PropertySlot slot(baseValue);
4731 JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
4732
4733 CHECK_FOR_EXCEPTION_AT_END();
4734 return result;
4735}
4736
4737JSValue* Interpreter::cti_op_get_by_id_array_fail(CTI_ARGS)
4738{
4739 CTI_STACK_HACK();
4740
4741 JSValue* baseValue = ARG_src1;
4742 PropertySlot slot(baseValue);
4743 JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
4744
4745 CHECK_FOR_EXCEPTION_AT_END();
4746 return result;
4747}
4748
4749JSValue* Interpreter::cti_op_get_by_id_string_fail(CTI_ARGS)
4750{
4751 CTI_STACK_HACK();
4752
4753 JSValue* baseValue = ARG_src1;
4754 PropertySlot slot(baseValue);
4755 JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
4756
4757 CHECK_FOR_EXCEPTION_AT_END();
4758 return result;
4759}
4760
4761JSValue* Interpreter::cti_op_instanceof(CTI_ARGS)
4762{
4763 CTI_STACK_HACK();
4764
4765 CallFrame* callFrame = ARG_callFrame;
4766 JSValue* value = ARG_src1;
4767 JSValue* baseVal = ARG_src2;
4768 JSValue* proto = ARG_src3;
4769
4770 // at least one of these checks must have failed to get to the slow case
4771 ASSERT(JSImmediate::isAnyImmediate(value, baseVal, proto)
4772 || !value->isObject() || !baseVal->isObject() || !proto->isObject()
4773 || (asObject(baseVal)->structure()->typeInfo().flags() & (ImplementsHasInstance | OverridesHasInstance)) != ImplementsHasInstance);
4774
4775 if (!baseVal->isObject()) {
4776 CallFrame* callFrame = ARG_callFrame;
4777 CodeBlock* codeBlock = callFrame->codeBlock();
4778 ASSERT(codeBlock->jitReturnAddressVPCMap().contains(CTI_RETURN_ADDRESS));
4779 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(CTI_RETURN_ADDRESS);
4780 ARG_globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal, codeBlock->instructions().begin() + vPCIndex, codeBlock);
4781 VM_THROW_EXCEPTION();
4782 }
4783
4784 if (!asObject(baseVal)->structure()->typeInfo().implementsHasInstance())
4785 return jsBoolean(false);
4786
4787 if (!proto->isObject()) {
4788 throwError(callFrame, TypeError, "instanceof called on an object with an invalid prototype property.");
4789 VM_THROW_EXCEPTION();
4790 }
4791
4792 if (!value->isObject())
4793 return jsBoolean(false);
4794
4795 JSValue* result = jsBoolean(asObject(baseVal)->hasInstance(callFrame, value, proto));
4796 CHECK_FOR_EXCEPTION_AT_END();
4797
4798 return result;
4799}
4800
4801JSValue* Interpreter::cti_op_del_by_id(CTI_ARGS)
4802{
4803 CTI_STACK_HACK();
4804
4805 CallFrame* callFrame = ARG_callFrame;
4806
4807 JSObject* baseObj = ARG_src1->toObject(callFrame);
4808
4809 JSValue* result = jsBoolean(baseObj->deleteProperty(callFrame, *ARG_id2));
4810 CHECK_FOR_EXCEPTION_AT_END();
4811 return result;
4812}
4813
4814JSValue* Interpreter::cti_op_mul(CTI_ARGS)
4815{
4816 CTI_STACK_HACK();
4817
4818 JSValue* src1 = ARG_src1;
4819 JSValue* src2 = ARG_src2;
4820
4821 double left;
4822 double right;
4823 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
4824 return jsNumber(ARG_globalData, left * right);
4825
4826 CallFrame* callFrame = ARG_callFrame;
4827 JSValue* result = jsNumber(ARG_globalData, src1->toNumber(callFrame) * src2->toNumber(callFrame));
4828 CHECK_FOR_EXCEPTION_AT_END();
4829 return result;
4830}
4831
4832JSObject* Interpreter::cti_op_new_func(CTI_ARGS)
4833{
4834 CTI_STACK_HACK();
4835
4836 return ARG_func1->makeFunction(ARG_callFrame, ARG_callFrame->scopeChain());
4837}
4838
4839void* Interpreter::cti_op_call_JSFunction(CTI_ARGS)
4840{
4841 CTI_STACK_HACK();
4842
4843#ifndef NDEBUG
4844 CallData callData;
4845 ASSERT(ARG_src1->getCallData(callData) == CallTypeJS);
4846#endif
4847
4848 ScopeChainNode* callDataScopeChain = asFunction(ARG_src1)->m_scopeChain.node();
4849 CodeBlock* newCodeBlock = &asFunction(ARG_src1)->body()->bytecode(callDataScopeChain);
4850
4851 if (!newCodeBlock->jitCode())
4852 JIT::compile(ARG_globalData, newCodeBlock);
4853
4854 return newCodeBlock;
4855}
4856
4857VoidPtrPair Interpreter::cti_op_call_arityCheck(CTI_ARGS)
4858{
4859 CTI_STACK_HACK();
4860
4861 CallFrame* callFrame = ARG_callFrame;
4862 CodeBlock* newCodeBlock = ARG_codeBlock4;
4863 int argCount = ARG_int3;
4864
4865 ASSERT(argCount != newCodeBlock->m_numParameters);
4866
4867 CallFrame* oldCallFrame = callFrame->callerFrame();
4868
4869 if (argCount > newCodeBlock->m_numParameters) {
4870 size_t numParameters = newCodeBlock->m_numParameters;
4871 Register* r = callFrame->registers() + numParameters;
4872
4873 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
4874 for (size_t i = 0; i < numParameters; ++i)
4875 argv[i + argCount] = argv[i];
4876
4877 callFrame = CallFrame::create(r);
4878 callFrame->setCallerFrame(oldCallFrame);
4879 } else {
4880 size_t omittedArgCount = newCodeBlock->m_numParameters - argCount;
4881 Register* r = callFrame->registers() + omittedArgCount;
4882 Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
4883 if (!ARG_registerFile->grow(newEnd)) {
4884 // Rewind to the previous call frame because op_call already optimistically
4885 // moved the call frame forward.
4886 ARG_setCallFrame(oldCallFrame);
4887 throwStackOverflowError(oldCallFrame, ARG_globalData, ARG_returnAddress2, CTI_RETURN_ADDRESS);
4888 VoidPtrPairValue pair = {{ 0, 0 }};
4889 return pair.i;
4890 }
4891
4892 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
4893 for (size_t i = 0; i < omittedArgCount; ++i)
4894 argv[i] = jsUndefined();
4895
4896 callFrame = CallFrame::create(r);
4897 callFrame->setCallerFrame(oldCallFrame);
4898 }
4899
4900 VoidPtrPairValue pair = {{ newCodeBlock, callFrame }};
4901 return pair.i;
4902}
4903
4904void* Interpreter::cti_vm_dontLazyLinkCall(CTI_ARGS)
4905{
4906 CTI_STACK_HACK();
4907
4908 JSFunction* callee = asFunction(ARG_src1);
4909 CodeBlock* codeBlock = &callee->body()->bytecode(callee->m_scopeChain.node());
4910 if (!codeBlock->jitCode())
4911 JIT::compile(ARG_globalData, codeBlock);
4912
4913 ctiRepatchCallByReturnAddress(ARG_returnAddress2, ARG_globalData->interpreter->m_ctiVirtualCallLink);
4914
4915 return codeBlock->jitCode();
4916}
4917
4918void* Interpreter::cti_vm_lazyLinkCall(CTI_ARGS)
4919{
4920 CTI_STACK_HACK();
4921
4922 JSFunction* callee = asFunction(ARG_src1);
4923 CodeBlock* codeBlock = &callee->body()->bytecode(callee->m_scopeChain.node());
4924 if (!codeBlock->jitCode())
4925 JIT::compile(ARG_globalData, codeBlock);
4926
4927 CallLinkInfo* callLinkInfo = &ARG_callFrame->callerFrame()->codeBlock()->getCallLinkInfo(ARG_returnAddress2);
4928 JIT::linkCall(callee, codeBlock, codeBlock->jitCode(), callLinkInfo, ARG_int3);
4929
4930 return codeBlock->jitCode();
4931}
4932
4933JSObject* Interpreter::cti_op_push_activation(CTI_ARGS)
4934{
4935 CTI_STACK_HACK();
4936
4937 JSActivation* activation = new (ARG_globalData) JSActivation(ARG_callFrame, static_cast<FunctionBodyNode*>(ARG_callFrame->codeBlock()->ownerNode()));
4938 ARG_callFrame->setScopeChain(ARG_callFrame->scopeChain()->copy()->push(activation));
4939 return activation;
4940}
4941
4942JSValue* Interpreter::cti_op_call_NotJSFunction(CTI_ARGS)
4943{
4944 CTI_STACK_HACK();
4945
4946 JSValue* funcVal = ARG_src1;
4947
4948 CallData callData;
4949 CallType callType = funcVal->getCallData(callData);
4950
4951 ASSERT(callType != CallTypeJS);
4952
4953 if (callType == CallTypeHost) {
4954 int registerOffset = ARG_int2;
4955 int argCount = ARG_int3;
4956 CallFrame* previousCallFrame = ARG_callFrame;
4957 CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset);
4958
4959 callFrame->init(0, ARG_instr4 + 1, previousCallFrame->scopeChain(), previousCallFrame, 0, argCount, 0);
4960 ARG_setCallFrame(callFrame);
4961
4962 Register* argv = ARG_callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
4963 ArgList argList(argv + 1, argCount - 1);
4964
4965 JSValue* returnValue;
4966 {
4967 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
4968
4969 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
4970 JSValue* thisValue = argv[0].jsValue(callFrame);
4971 if (thisValue == jsNull())
4972 thisValue = callFrame->globalThisValue();
4973
4974 returnValue = callData.native.function(callFrame, asObject(funcVal), thisValue, argList);
4975 }
4976 ARG_setCallFrame(previousCallFrame);
4977 CHECK_FOR_EXCEPTION();
4978
4979 return returnValue;
4980 }
4981
4982 ASSERT(callType == CallTypeNone);
4983
4984 ARG_globalData->exception = createNotAFunctionError(ARG_callFrame, funcVal, ARG_instr4, ARG_callFrame->codeBlock());
4985 VM_THROW_EXCEPTION();
4986}
4987
4988void Interpreter::cti_op_create_arguments(CTI_ARGS)
4989{
4990 CTI_STACK_HACK();
4991
4992 Arguments* arguments = new (ARG_globalData) Arguments(ARG_callFrame);
4993 ARG_callFrame->setCalleeArguments(arguments);
4994 ARG_callFrame[RegisterFile::ArgumentsRegister] = arguments;
4995}
4996
4997void Interpreter::cti_op_create_arguments_no_params(CTI_ARGS)
4998{
4999 CTI_STACK_HACK();
5000
5001 Arguments* arguments = new (ARG_globalData) Arguments(ARG_callFrame, Arguments::NoParameters);
5002 ARG_callFrame->setCalleeArguments(arguments);
5003 ARG_callFrame[RegisterFile::ArgumentsRegister] = arguments;
5004}
5005
5006void Interpreter::cti_op_tear_off_activation(CTI_ARGS)
5007{
5008 CTI_STACK_HACK();
5009
5010 ASSERT(ARG_callFrame->codeBlock()->needsFullScopeChain());
5011 asActivation(ARG_src1)->copyRegisters(ARG_callFrame->optionalCalleeArguments());
5012}
5013
5014void Interpreter::cti_op_tear_off_arguments(CTI_ARGS)
5015{
5016 CTI_STACK_HACK();
5017
5018 ASSERT(ARG_callFrame->codeBlock()->usesArguments() && !ARG_callFrame->codeBlock()->needsFullScopeChain());
5019 ARG_callFrame->optionalCalleeArguments()->copyRegisters();
5020}
5021
5022void Interpreter::cti_op_profile_will_call(CTI_ARGS)
5023{
5024 CTI_STACK_HACK();
5025
5026 ASSERT(*ARG_profilerReference);
5027 (*ARG_profilerReference)->willExecute(ARG_callFrame, ARG_src1);
5028}
5029
5030void Interpreter::cti_op_profile_did_call(CTI_ARGS)
5031{
5032 CTI_STACK_HACK();
5033
5034 ASSERT(*ARG_profilerReference);
5035 (*ARG_profilerReference)->didExecute(ARG_callFrame, ARG_src1);
5036}
5037
5038void Interpreter::cti_op_ret_scopeChain(CTI_ARGS)
5039{
5040 CTI_STACK_HACK();
5041
5042 ASSERT(ARG_callFrame->codeBlock()->needsFullScopeChain());
5043 ARG_callFrame->scopeChain()->deref();
5044}
5045
5046JSObject* Interpreter::cti_op_new_array(CTI_ARGS)
5047{
5048 CTI_STACK_HACK();
5049
5050 ArgList argList(ARG_registers1, ARG_int2);
5051 return constructArray(ARG_callFrame, argList);
5052}
5053
5054JSValue* Interpreter::cti_op_resolve(CTI_ARGS)
5055{
5056 CTI_STACK_HACK();
5057
5058 CallFrame* callFrame = ARG_callFrame;
5059 ScopeChainNode* scopeChain = callFrame->scopeChain();
5060
5061 ScopeChainIterator iter = scopeChain->begin();
5062 ScopeChainIterator end = scopeChain->end();
5063 ASSERT(iter != end);
5064
5065 Identifier& ident = *ARG_id1;
5066 do {
5067 JSObject* o = *iter;
5068 PropertySlot slot(o);
5069 if (o->getPropertySlot(callFrame, ident, slot)) {
5070 JSValue* result = slot.getValue(callFrame, ident);
5071 CHECK_FOR_EXCEPTION_AT_END();
5072 return result;
5073 }
5074 } while (++iter != end);
5075
5076 CodeBlock* codeBlock = callFrame->codeBlock();
5077 ASSERT(codeBlock->jitReturnAddressVPCMap().contains(CTI_RETURN_ADDRESS));
5078 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(CTI_RETURN_ADDRESS);
5079 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, codeBlock->instructions().begin() + vPCIndex, codeBlock);
5080 VM_THROW_EXCEPTION();
5081}
5082
5083JSObject* Interpreter::cti_op_construct_JSConstruct(CTI_ARGS)
5084{
5085 CTI_STACK_HACK();
5086
5087#ifndef NDEBUG
5088 ConstructData constructData;
5089 ASSERT(asFunction(ARG_src1)->getConstructData(constructData) == ConstructTypeJS);
5090#endif
5091
5092 Structure* structure;
5093 if (ARG_src4->isObject())
5094 structure = asObject(ARG_src4)->inheritorID();
5095 else
5096 structure = asFunction(ARG_src1)->m_scopeChain.node()->globalObject()->emptyObjectStructure();
5097 return new (ARG_globalData) JSObject(structure);
5098}
5099
5100JSValue* Interpreter::cti_op_construct_NotJSConstruct(CTI_ARGS)
5101{
5102 CTI_STACK_HACK();
5103
5104 CallFrame* callFrame = ARG_callFrame;
5105
5106 JSValue* constrVal = ARG_src1;
5107 int argCount = ARG_int3;
5108 int thisRegister = ARG_int5;
5109
5110 ConstructData constructData;
5111 ConstructType constructType = constrVal->getConstructData(constructData);
5112
5113 if (constructType == ConstructTypeHost) {
5114 ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1);
5115
5116 JSValue* returnValue;
5117 {
5118 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
5119 returnValue = constructData.native.function(callFrame, asObject(constrVal), argList);
5120 }
5121 CHECK_FOR_EXCEPTION();
5122
5123 return returnValue;
5124 }
5125
5126 ASSERT(constructType == ConstructTypeNone);
5127
5128 ARG_globalData->exception = createNotAConstructorError(callFrame, constrVal, ARG_instr6, callFrame->codeBlock());
5129 VM_THROW_EXCEPTION();
5130}
5131
5132JSValue* Interpreter::cti_op_get_by_val(CTI_ARGS)
5133{
5134 CTI_STACK_HACK();
5135
5136 CallFrame* callFrame = ARG_callFrame;
5137 Interpreter* interpreter = ARG_globalData->interpreter;
5138
5139 JSValue* baseValue = ARG_src1;
5140 JSValue* subscript = ARG_src2;
5141
5142 JSValue* result;
5143 unsigned i;
5144
5145 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
5146 if (LIKELY(isUInt32)) {
5147 if (interpreter->isJSArray(baseValue)) {
5148 JSArray* jsArray = asArray(baseValue);
5149 if (jsArray->canGetIndex(i))
5150 result = jsArray->getIndex(i);
5151 else
5152 result = jsArray->JSArray::get(callFrame, i);
5153 } else if (interpreter->isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
5154 result = asString(baseValue)->getIndex(ARG_globalData, i);
5155 else
5156 result = baseValue->get(callFrame, i);
5157 } else {
5158 Identifier property(callFrame, subscript->toString(callFrame));
5159 result = baseValue->get(callFrame, property);
5160 }
5161
5162 CHECK_FOR_EXCEPTION_AT_END();
5163 return result;
5164}
5165
5166VoidPtrPair Interpreter::cti_op_resolve_func(CTI_ARGS)
5167{
5168 CTI_STACK_HACK();
5169
5170 CallFrame* callFrame = ARG_callFrame;
5171 ScopeChainNode* scopeChain = callFrame->scopeChain();
5172
5173 ScopeChainIterator iter = scopeChain->begin();
5174 ScopeChainIterator end = scopeChain->end();
5175
5176 // FIXME: add scopeDepthIsZero optimization
5177
5178 ASSERT(iter != end);
5179
5180 Identifier& ident = *ARG_id1;
5181 JSObject* base;
5182 do {
5183 base = *iter;
5184 PropertySlot slot(base);
5185 if (base->getPropertySlot(callFrame, ident, slot)) {
5186 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
5187 // However, section 10.2.3 says that in the case where the value provided
5188 // by the caller is null, the global object should be used. It also says
5189 // that the section does not apply to internal functions, but for simplicity
5190 // of implementation we use the global object anyway here. This guarantees
5191 // that in host objects you always get a valid object for this.
5192 // We also handle wrapper substitution for the global object at the same time.
5193 JSObject* thisObj = base->toThisObject(callFrame);
5194 JSValue* result = slot.getValue(callFrame, ident);
5195 CHECK_FOR_EXCEPTION_AT_END();
5196
5197 VoidPtrPairValue pair = {{ thisObj, asPointer(result) }};
5198 return pair.i;
5199 }
5200 ++iter;
5201 } while (iter != end);
5202
5203 CodeBlock* codeBlock = callFrame->codeBlock();
5204 ASSERT(codeBlock->jitReturnAddressVPCMap().contains(CTI_RETURN_ADDRESS));
5205 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(CTI_RETURN_ADDRESS);
5206 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, codeBlock->instructions().begin() + vPCIndex, codeBlock);
5207 VM_THROW_EXCEPTION_2();
5208}
5209
5210JSValue* Interpreter::cti_op_sub(CTI_ARGS)
5211{
5212 CTI_STACK_HACK();
5213
5214 JSValue* src1 = ARG_src1;
5215 JSValue* src2 = ARG_src2;
5216
5217 double left;
5218 double right;
5219 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
5220 return jsNumber(ARG_globalData, left - right);
5221
5222 CallFrame* callFrame = ARG_callFrame;
5223 JSValue* result = jsNumber(ARG_globalData, src1->toNumber(callFrame) - src2->toNumber(callFrame));
5224 CHECK_FOR_EXCEPTION_AT_END();
5225 return result;
5226}
5227
5228void Interpreter::cti_op_put_by_val(CTI_ARGS)
5229{
5230 CTI_STACK_HACK();
5231
5232 CallFrame* callFrame = ARG_callFrame;
5233 Interpreter* interpreter = ARG_globalData->interpreter;
5234
5235 JSValue* baseValue = ARG_src1;
5236 JSValue* subscript = ARG_src2;
5237 JSValue* value = ARG_src3;
5238
5239 unsigned i;
5240
5241 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
5242 if (LIKELY(isUInt32)) {
5243 if (interpreter->isJSArray(baseValue)) {
5244 JSArray* jsArray = asArray(baseValue);
5245 if (jsArray->canSetIndex(i))
5246 jsArray->setIndex(i, value);
5247 else
5248 jsArray->JSArray::put(callFrame, i, value);
5249 } else
5250 baseValue->put(callFrame, i, value);
5251 } else {
5252 Identifier property(callFrame, subscript->toString(callFrame));
5253 if (!ARG_globalData->exception) { // Don't put to an object if toString threw an exception.
5254 PutPropertySlot slot;
5255 baseValue->put(callFrame, property, value, slot);
5256 }
5257 }
5258
5259 CHECK_FOR_EXCEPTION_AT_END();
5260}
5261
5262void Interpreter::cti_op_put_by_val_array(CTI_ARGS)
5263{
5264 CTI_STACK_HACK();
5265
5266 CallFrame* callFrame = ARG_callFrame;
5267
5268 JSValue* baseValue = ARG_src1;
5269 int i = ARG_int2;
5270 JSValue* value = ARG_src3;
5271
5272 ASSERT(ARG_globalData->interpreter->isJSArray(baseValue));
5273
5274 if (LIKELY(i >= 0))
5275 asArray(baseValue)->JSArray::put(callFrame, i, value);
5276 else {
5277 Identifier property(callFrame, JSImmediate::from(i)->toString(callFrame));
5278 // FIXME: can toString throw an exception here?
5279 if (!ARG_globalData->exception) { // Don't put to an object if toString threw an exception.
5280 PutPropertySlot slot;
5281 baseValue->put(callFrame, property, value, slot);
5282 }
5283 }
5284
5285 CHECK_FOR_EXCEPTION_AT_END();
5286}
5287
5288JSValue* Interpreter::cti_op_lesseq(CTI_ARGS)
5289{
5290 CTI_STACK_HACK();
5291
5292 CallFrame* callFrame = ARG_callFrame;
5293 JSValue* result = jsBoolean(jsLessEq(callFrame, ARG_src1, ARG_src2));
5294 CHECK_FOR_EXCEPTION_AT_END();
5295 return result;
5296}
5297
5298int Interpreter::cti_op_loop_if_true(CTI_ARGS)
5299{
5300 CTI_STACK_HACK();
5301
5302 JSValue* src1 = ARG_src1;
5303
5304 CallFrame* callFrame = ARG_callFrame;
5305
5306 bool result = src1->toBoolean(callFrame);
5307 CHECK_FOR_EXCEPTION_AT_END();
5308 return result;
5309}
5310
5311JSValue* Interpreter::cti_op_negate(CTI_ARGS)
5312{
5313 CTI_STACK_HACK();
5314
5315 JSValue* src = ARG_src1;
5316
5317 double v;
5318 if (fastIsNumber(src, v))
5319 return jsNumber(ARG_globalData, -v);
5320
5321 CallFrame* callFrame = ARG_callFrame;
5322 JSValue* result = jsNumber(ARG_globalData, -src->toNumber(callFrame));
5323 CHECK_FOR_EXCEPTION_AT_END();
5324 return result;
5325}
5326
5327JSValue* Interpreter::cti_op_resolve_base(CTI_ARGS)
5328{
5329 CTI_STACK_HACK();
5330
5331 return inlineResolveBase(ARG_callFrame, *ARG_id1, ARG_callFrame->scopeChain());
5332}
5333
5334JSValue* Interpreter::cti_op_resolve_skip(CTI_ARGS)
5335{
5336 CTI_STACK_HACK();
5337
5338 CallFrame* callFrame = ARG_callFrame;
5339 ScopeChainNode* scopeChain = callFrame->scopeChain();
5340
5341 int skip = ARG_int2;
5342
5343 ScopeChainIterator iter = scopeChain->begin();
5344 ScopeChainIterator end = scopeChain->end();
5345 ASSERT(iter != end);
5346 while (skip--) {
5347 ++iter;
5348 ASSERT(iter != end);
5349 }
5350 Identifier& ident = *ARG_id1;
5351 do {
5352 JSObject* o = *iter;
5353 PropertySlot slot(o);
5354 if (o->getPropertySlot(callFrame, ident, slot)) {
5355 JSValue* result = slot.getValue(callFrame, ident);
5356 CHECK_FOR_EXCEPTION_AT_END();
5357 return result;
5358 }
5359 } while (++iter != end);
5360
5361 CodeBlock* codeBlock = callFrame->codeBlock();
5362 ASSERT(codeBlock->jitReturnAddressVPCMap().contains(CTI_RETURN_ADDRESS));
5363 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(CTI_RETURN_ADDRESS);
5364 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, codeBlock->instructions().begin() + vPCIndex, codeBlock);
5365 VM_THROW_EXCEPTION();
5366}
5367
5368JSValue* Interpreter::cti_op_resolve_global(CTI_ARGS)
5369{
5370 CTI_STACK_HACK();
5371
5372 CallFrame* callFrame = ARG_callFrame;
5373 JSGlobalObject* globalObject = asGlobalObject(ARG_src1);
5374 Identifier& ident = *ARG_id2;
5375 Instruction* vPC = ARG_instr3;
5376 ASSERT(globalObject->isGlobalObject());
5377
5378 PropertySlot slot(globalObject);
5379 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
5380 JSValue* result = slot.getValue(callFrame, ident);
5381 if (slot.isCacheable()) {
5382 if (vPC[4].u.structure)
5383 vPC[4].u.structure->deref();
5384 globalObject->structure()->ref();
5385 vPC[4] = globalObject->structure();
5386 vPC[5] = slot.cachedOffset();
5387 return result;
5388 }
5389
5390 CHECK_FOR_EXCEPTION_AT_END();
5391 return result;
5392 }
5393
5394 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, vPC, callFrame->codeBlock());
5395 VM_THROW_EXCEPTION();
5396}
5397
5398JSValue* Interpreter::cti_op_div(CTI_ARGS)
5399{
5400 CTI_STACK_HACK();
5401
5402 JSValue* src1 = ARG_src1;
5403 JSValue* src2 = ARG_src2;
5404
5405 double left;
5406 double right;
5407 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
5408 return jsNumber(ARG_globalData, left / right);
5409
5410 CallFrame* callFrame = ARG_callFrame;
5411 JSValue* result = jsNumber(ARG_globalData, src1->toNumber(callFrame) / src2->toNumber(callFrame));
5412 CHECK_FOR_EXCEPTION_AT_END();
5413 return result;
5414}
5415
5416JSValue* Interpreter::cti_op_pre_dec(CTI_ARGS)
5417{
5418 CTI_STACK_HACK();
5419
5420 JSValue* v = ARG_src1;
5421
5422 CallFrame* callFrame = ARG_callFrame;
5423 JSValue* result = jsNumber(ARG_globalData, v->toNumber(callFrame) - 1);
5424 CHECK_FOR_EXCEPTION_AT_END();
5425 return result;
5426}
5427
5428int Interpreter::cti_op_jless(CTI_ARGS)
5429{
5430 CTI_STACK_HACK();
5431
5432 JSValue* src1 = ARG_src1;
5433 JSValue* src2 = ARG_src2;
5434 CallFrame* callFrame = ARG_callFrame;
5435
5436 bool result = jsLess(callFrame, src1, src2);
5437 CHECK_FOR_EXCEPTION_AT_END();
5438 return result;
5439}
5440
5441JSValue* Interpreter::cti_op_not(CTI_ARGS)
5442{
5443 CTI_STACK_HACK();
5444
5445 JSValue* src = ARG_src1;
5446
5447 CallFrame* callFrame = ARG_callFrame;
5448
5449 JSValue* result = jsBoolean(!src->toBoolean(callFrame));
5450 CHECK_FOR_EXCEPTION_AT_END();
5451 return result;
5452}
5453
5454int SFX_CALL Interpreter::cti_op_jtrue(CTI_ARGS)
5455{
5456 CTI_STACK_HACK();
5457
5458 JSValue* src1 = ARG_src1;
5459
5460 CallFrame* callFrame = ARG_callFrame;
5461
5462 bool result = src1->toBoolean(callFrame);
5463 CHECK_FOR_EXCEPTION_AT_END();
5464 return result;
5465}
5466
5467VoidPtrPair Interpreter::cti_op_post_inc(CTI_ARGS)
5468{
5469 CTI_STACK_HACK();
5470
5471 JSValue* v = ARG_src1;
5472
5473 CallFrame* callFrame = ARG_callFrame;
5474
5475 JSValue* number = v->toJSNumber(callFrame);
5476 CHECK_FOR_EXCEPTION_AT_END();
5477
5478 VoidPtrPairValue pair = {{ asPointer(number), asPointer(jsNumber(ARG_globalData, number->uncheckedGetNumber() + 1)) }};
5479 return pair.i;
5480}
5481
5482JSValue* Interpreter::cti_op_eq(CTI_ARGS)
5483{
5484 CTI_STACK_HACK();
5485
5486 JSValue* src1 = ARG_src1;
5487 JSValue* src2 = ARG_src2;
5488
5489 CallFrame* callFrame = ARG_callFrame;
5490
5491 ASSERT(!JSImmediate::areBothImmediateNumbers(src1, src2));
5492 JSValue* result = jsBoolean(equalSlowCaseInline(callFrame, src1, src2));
5493 CHECK_FOR_EXCEPTION_AT_END();
5494 return result;
5495}
5496
5497JSValue* Interpreter::cti_op_lshift(CTI_ARGS)
5498{
5499 CTI_STACK_HACK();
5500
5501 JSValue* val = ARG_src1;
5502 JSValue* shift = ARG_src2;
5503
5504 int32_t left;
5505 uint32_t right;
5506 if (JSImmediate::areBothImmediateNumbers(val, shift))
5507 return jsNumber(ARG_globalData, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
5508 if (fastToInt32(val, left) && fastToUInt32(shift, right))
5509 return jsNumber(ARG_globalData, left << (right & 0x1f));
5510
5511 CallFrame* callFrame = ARG_callFrame;
5512 JSValue* result = jsNumber(ARG_globalData, (val->toInt32(callFrame)) << (shift->toUInt32(callFrame) & 0x1f));
5513 CHECK_FOR_EXCEPTION_AT_END();
5514 return result;
5515}
5516
5517JSValue* Interpreter::cti_op_bitand(CTI_ARGS)
5518{
5519 CTI_STACK_HACK();
5520
5521 JSValue* src1 = ARG_src1;
5522 JSValue* src2 = ARG_src2;
5523
5524 int32_t left;
5525 int32_t right;
5526 if (fastToInt32(src1, left) && fastToInt32(src2, right))
5527 return jsNumber(ARG_globalData, left & right);
5528
5529 CallFrame* callFrame = ARG_callFrame;
5530 JSValue* result = jsNumber(ARG_globalData, src1->toInt32(callFrame) & src2->toInt32(callFrame));
5531 CHECK_FOR_EXCEPTION_AT_END();
5532 return result;
5533}
5534
5535JSValue* Interpreter::cti_op_rshift(CTI_ARGS)
5536{
5537 CTI_STACK_HACK();
5538
5539 JSValue* val = ARG_src1;
5540 JSValue* shift = ARG_src2;
5541
5542 int32_t left;
5543 uint32_t right;
5544 if (JSImmediate::areBothImmediateNumbers(val, shift))
5545 return JSImmediate::rightShiftImmediateNumbers(val, shift);
5546 if (fastToInt32(val, left) && fastToUInt32(shift, right))
5547 return jsNumber(ARG_globalData, left >> (right & 0x1f));
5548
5549 CallFrame* callFrame = ARG_callFrame;
5550 JSValue* result = jsNumber(ARG_globalData, (val->toInt32(callFrame)) >> (shift->toUInt32(callFrame) & 0x1f));
5551 CHECK_FOR_EXCEPTION_AT_END();
5552 return result;
5553}
5554
5555JSValue* Interpreter::cti_op_bitnot(CTI_ARGS)
5556{
5557 CTI_STACK_HACK();
5558
5559 JSValue* src = ARG_src1;
5560
5561 int value;
5562 if (fastToInt32(src, value))
5563 return jsNumber(ARG_globalData, ~value);
5564
5565 CallFrame* callFrame = ARG_callFrame;
5566 JSValue* result = jsNumber(ARG_globalData, ~src->toInt32(callFrame));
5567 CHECK_FOR_EXCEPTION_AT_END();
5568 return result;
5569}
5570
5571VoidPtrPair Interpreter::cti_op_resolve_with_base(CTI_ARGS)
5572{
5573 CTI_STACK_HACK();
5574
5575 CallFrame* callFrame = ARG_callFrame;
5576 ScopeChainNode* scopeChain = callFrame->scopeChain();
5577
5578 ScopeChainIterator iter = scopeChain->begin();
5579 ScopeChainIterator end = scopeChain->end();
5580
5581 // FIXME: add scopeDepthIsZero optimization
5582
5583 ASSERT(iter != end);
5584
5585 Identifier& ident = *ARG_id1;
5586 JSObject* base;
5587 do {
5588 base = *iter;
5589 PropertySlot slot(base);
5590 if (base->getPropertySlot(callFrame, ident, slot)) {
5591 JSValue* result = slot.getValue(callFrame, ident);
5592 CHECK_FOR_EXCEPTION_AT_END();
5593
5594 VoidPtrPairValue pair = {{ base, asPointer(result) }};
5595 return pair.i;
5596 }
5597 ++iter;
5598 } while (iter != end);
5599
5600 CodeBlock* codeBlock = callFrame->codeBlock();
5601 ASSERT(codeBlock->jitReturnAddressVPCMap().contains(CTI_RETURN_ADDRESS));
5602 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(CTI_RETURN_ADDRESS);
5603 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, codeBlock->instructions().begin() + vPCIndex, codeBlock);
5604 VM_THROW_EXCEPTION_2();
5605}
5606
5607JSObject* Interpreter::cti_op_new_func_exp(CTI_ARGS)
5608{
5609 CTI_STACK_HACK();
5610
5611 return ARG_funcexp1->makeFunction(ARG_callFrame, ARG_callFrame->scopeChain());
5612}
5613
5614JSValue* Interpreter::cti_op_mod(CTI_ARGS)
5615{
5616 CTI_STACK_HACK();
5617
5618 JSValue* dividendValue = ARG_src1;
5619 JSValue* divisorValue = ARG_src2;
5620
5621 CallFrame* callFrame = ARG_callFrame;
5622 double d = dividendValue->toNumber(callFrame);
5623 JSValue* result = jsNumber(ARG_globalData, fmod(d, divisorValue->toNumber(callFrame)));
5624 CHECK_FOR_EXCEPTION_AT_END();
5625 return result;
5626}
5627
5628JSValue* Interpreter::cti_op_less(CTI_ARGS)
5629{
5630 CTI_STACK_HACK();
5631
5632 CallFrame* callFrame = ARG_callFrame;
5633 JSValue* result = jsBoolean(jsLess(callFrame, ARG_src1, ARG_src2));
5634 CHECK_FOR_EXCEPTION_AT_END();
5635 return result;
5636}
5637
5638JSValue* Interpreter::cti_op_neq(CTI_ARGS)
5639{
5640 CTI_STACK_HACK();
5641
5642 JSValue* src1 = ARG_src1;
5643 JSValue* src2 = ARG_src2;
5644
5645 ASSERT(!JSImmediate::areBothImmediateNumbers(src1, src2));
5646
5647 CallFrame* callFrame = ARG_callFrame;
5648 JSValue* result = jsBoolean(!equalSlowCaseInline(callFrame, src1, src2));
5649 CHECK_FOR_EXCEPTION_AT_END();
5650 return result;
5651}
5652
5653VoidPtrPair Interpreter::cti_op_post_dec(CTI_ARGS)
5654{
5655 CTI_STACK_HACK();
5656
5657 JSValue* v = ARG_src1;
5658
5659 CallFrame* callFrame = ARG_callFrame;
5660
5661 JSValue* number = v->toJSNumber(callFrame);
5662 CHECK_FOR_EXCEPTION_AT_END();
5663
5664 VoidPtrPairValue pair = {{ asPointer(number), asPointer(jsNumber(ARG_globalData, number->uncheckedGetNumber() - 1)) }};
5665 return pair.i;
5666}
5667
5668JSValue* Interpreter::cti_op_urshift(CTI_ARGS)
5669{
5670 CTI_STACK_HACK();
5671
5672 JSValue* val = ARG_src1;
5673 JSValue* shift = ARG_src2;
5674
5675 CallFrame* callFrame = ARG_callFrame;
5676
5677 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
5678 return JSImmediate::rightShiftImmediateNumbers(val, shift);
5679 else {
5680 JSValue* result = jsNumber(ARG_globalData, (val->toUInt32(callFrame)) >> (shift->toUInt32(callFrame) & 0x1f));
5681 CHECK_FOR_EXCEPTION_AT_END();
5682 return result;
5683 }
5684}
5685
5686JSValue* Interpreter::cti_op_bitxor(CTI_ARGS)
5687{
5688 CTI_STACK_HACK();
5689
5690 JSValue* src1 = ARG_src1;
5691 JSValue* src2 = ARG_src2;
5692
5693 CallFrame* callFrame = ARG_callFrame;
5694
5695 JSValue* result = jsNumber(ARG_globalData, src1->toInt32(callFrame) ^ src2->toInt32(callFrame));
5696 CHECK_FOR_EXCEPTION_AT_END();
5697 return result;
5698}
5699
5700JSObject* Interpreter::cti_op_new_regexp(CTI_ARGS)
5701{
5702 CTI_STACK_HACK();
5703
5704 return new (ARG_globalData) RegExpObject(ARG_callFrame->lexicalGlobalObject()->regExpStructure(), ARG_regexp1);
5705}
5706
5707JSValue* Interpreter::cti_op_bitor(CTI_ARGS)
5708{
5709 CTI_STACK_HACK();
5710
5711 JSValue* src1 = ARG_src1;
5712 JSValue* src2 = ARG_src2;
5713
5714 CallFrame* callFrame = ARG_callFrame;
5715
5716 JSValue* result = jsNumber(ARG_globalData, src1->toInt32(callFrame) | src2->toInt32(callFrame));
5717 CHECK_FOR_EXCEPTION_AT_END();
5718 return result;
5719}
5720
5721JSValue* Interpreter::cti_op_call_eval(CTI_ARGS)
5722{
5723 CTI_STACK_HACK();
5724
5725 CallFrame* callFrame = ARG_callFrame;
5726 RegisterFile* registerFile = ARG_registerFile;
5727
5728 Interpreter* interpreter = ARG_globalData->interpreter;
5729
5730 JSValue* funcVal = ARG_src1;
5731 int registerOffset = ARG_int2;
5732 int argCount = ARG_int3;
5733
5734 Register* newCallFrame = callFrame->registers() + registerOffset;
5735 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
5736 JSValue* thisValue = argv[0].jsValue(callFrame);
5737 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();
5738
5739 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
5740 JSValue* exceptionValue = noValue();
5741 JSValue* result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
5742 if (UNLIKELY(exceptionValue != noValue())) {
5743 ARG_globalData->exception = exceptionValue;
5744 VM_THROW_EXCEPTION_AT_END();
5745 }
5746 return result;
5747 }
5748
5749 return JSImmediate::impossibleValue();
5750}
5751
5752JSValue* Interpreter::cti_op_throw(CTI_ARGS)
5753{
5754 CTI_STACK_HACK();
5755
5756 CallFrame* callFrame = ARG_callFrame;
5757 CodeBlock* codeBlock = callFrame->codeBlock();
5758
5759 ASSERT(codeBlock->jitReturnAddressVPCMap().contains(CTI_RETURN_ADDRESS));
5760 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(CTI_RETURN_ADDRESS);
5761
5762 JSValue* exceptionValue = ARG_src1;
5763 ASSERT(exceptionValue);
5764
5765 Instruction* handlerVPC = ARG_globalData->interpreter->throwException(callFrame, exceptionValue, codeBlock->instructions().begin() + vPCIndex, true);
5766
5767 if (!handlerVPC) {
5768 *ARG_exception = exceptionValue;
5769 return JSImmediate::nullImmediate();
5770 }
5771
5772 ARG_setCallFrame(callFrame);
5773 void* catchRoutine = callFrame->codeBlock()->nativeExceptionCodeForHandlerVPC(handlerVPC);
5774 ASSERT(catchRoutine);
5775 CTI_SET_RETURN_ADDRESS(catchRoutine);
5776 return exceptionValue;
5777}
5778
5779JSPropertyNameIterator* Interpreter::cti_op_get_pnames(CTI_ARGS)
5780{
5781 CTI_STACK_HACK();
5782
5783 return JSPropertyNameIterator::create(ARG_callFrame, ARG_src1);
5784}
5785
5786JSValue* Interpreter::cti_op_next_pname(CTI_ARGS)
5787{
5788 CTI_STACK_HACK();
5789
5790 JSPropertyNameIterator* it = ARG_pni1;
5791 JSValue* temp = it->next(ARG_callFrame);
5792 if (!temp)
5793 it->invalidate();
5794 return temp;
5795}
5796
5797void Interpreter::cti_op_push_scope(CTI_ARGS)
5798{
5799 CTI_STACK_HACK();
5800
5801 JSObject* o = ARG_src1->toObject(ARG_callFrame);
5802 CHECK_FOR_EXCEPTION_VOID();
5803 ARG_callFrame->setScopeChain(ARG_callFrame->scopeChain()->push(o));
5804}
5805
5806void Interpreter::cti_op_pop_scope(CTI_ARGS)
5807{
5808 CTI_STACK_HACK();
5809
5810 ARG_callFrame->setScopeChain(ARG_callFrame->scopeChain()->pop());
5811}
5812
5813JSValue* Interpreter::cti_op_typeof(CTI_ARGS)
5814{
5815 CTI_STACK_HACK();
5816
5817 return jsTypeStringForValue(ARG_callFrame, ARG_src1);
5818}
5819
5820JSValue* Interpreter::cti_op_is_undefined(CTI_ARGS)
5821{
5822 CTI_STACK_HACK();
5823
5824 JSValue* v = ARG_src1;
5825 return jsBoolean(JSImmediate::isImmediate(v) ? v->isUndefined() : v->asCell()->structure()->typeInfo().masqueradesAsUndefined());
5826}
5827
5828JSValue* Interpreter::cti_op_is_boolean(CTI_ARGS)
5829{
5830 CTI_STACK_HACK();
5831
5832 return jsBoolean(ARG_src1->isBoolean());
5833}
5834
5835JSValue* Interpreter::cti_op_is_number(CTI_ARGS)
5836{
5837 CTI_STACK_HACK();
5838
5839 return jsBoolean(ARG_src1->isNumber());
5840}
5841
5842JSValue* Interpreter::cti_op_is_string(CTI_ARGS)
5843{
5844 CTI_STACK_HACK();
5845
5846 return jsBoolean(ARG_globalData->interpreter->isJSString(ARG_src1));
5847}
5848
5849JSValue* Interpreter::cti_op_is_object(CTI_ARGS)
5850{
5851 CTI_STACK_HACK();
5852
5853 return jsBoolean(jsIsObjectType(ARG_src1));
5854}
5855
5856JSValue* Interpreter::cti_op_is_function(CTI_ARGS)
5857{
5858 CTI_STACK_HACK();
5859
5860 return jsBoolean(jsIsFunctionType(ARG_src1));
5861}
5862
5863JSValue* Interpreter::cti_op_stricteq(CTI_ARGS)
5864{
5865 CTI_STACK_HACK();
5866
5867 JSValue* src1 = ARG_src1;
5868 JSValue* src2 = ARG_src2;
5869
5870 // handled inline as fast cases
5871 ASSERT(!JSImmediate::areBothImmediate(src1, src2));
5872 ASSERT(!(JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate())));
5873
5874 return jsBoolean(strictEqualSlowCaseInline(src1, src2));
5875}
5876
5877JSValue* Interpreter::cti_op_nstricteq(CTI_ARGS)
5878{
5879 CTI_STACK_HACK();
5880
5881 JSValue* src1 = ARG_src1;
5882 JSValue* src2 = ARG_src2;
5883
5884 // handled inline as fast cases
5885 ASSERT(!JSImmediate::areBothImmediate(src1, src2));
5886 ASSERT(!(JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate())));
5887
5888 return jsBoolean(!strictEqualSlowCaseInline(src1, src2));
5889}
5890
5891JSValue* Interpreter::cti_op_to_jsnumber(CTI_ARGS)
5892{
5893 CTI_STACK_HACK();
5894
5895 JSValue* src = ARG_src1;
5896 CallFrame* callFrame = ARG_callFrame;
5897
5898 JSValue* result = src->toJSNumber(callFrame);
5899 CHECK_FOR_EXCEPTION_AT_END();
5900 return result;
5901}
5902
5903JSValue* Interpreter::cti_op_in(CTI_ARGS)
5904{
5905 CTI_STACK_HACK();
5906
5907 CallFrame* callFrame = ARG_callFrame;
5908 JSValue* baseVal = ARG_src2;
5909
5910 if (!baseVal->isObject()) {
5911 CallFrame* callFrame = ARG_callFrame;
5912 CodeBlock* codeBlock = callFrame->codeBlock();
5913 ASSERT(codeBlock->jitReturnAddressVPCMap().contains(CTI_RETURN_ADDRESS));
5914 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(CTI_RETURN_ADDRESS);
5915 ARG_globalData->exception = createInvalidParamError(callFrame, "in", baseVal, codeBlock->instructions().begin() + vPCIndex, codeBlock);
5916 VM_THROW_EXCEPTION();
5917 }
5918
5919 JSValue* propName = ARG_src1;
5920 JSObject* baseObj = asObject(baseVal);
5921
5922 uint32_t i;
5923 if (propName->getUInt32(i))
5924 return jsBoolean(baseObj->hasProperty(callFrame, i));
5925
5926 Identifier property(callFrame, propName->toString(callFrame));
5927 CHECK_FOR_EXCEPTION();
5928 return jsBoolean(baseObj->hasProperty(callFrame, property));
5929}
5930
5931JSObject* Interpreter::cti_op_push_new_scope(CTI_ARGS)
5932{
5933 CTI_STACK_HACK();
5934
5935 JSObject* scope = new (ARG_globalData) JSStaticScopeObject(ARG_callFrame, *ARG_id1, ARG_src2, DontDelete);
5936
5937 CallFrame* callFrame = ARG_callFrame;
5938 callFrame->setScopeChain(callFrame->scopeChain()->push(scope));
5939 return scope;
5940}
5941
5942void Interpreter::cti_op_jmp_scopes(CTI_ARGS)
5943{
5944 CTI_STACK_HACK();
5945
5946 unsigned count = ARG_int1;
5947 CallFrame* callFrame = ARG_callFrame;
5948
5949 ScopeChainNode* tmp = callFrame->scopeChain();
5950 while (count--)
5951 tmp = tmp->pop();
5952 callFrame->setScopeChain(tmp);
5953}
5954
5955void Interpreter::cti_op_put_by_index(CTI_ARGS)
5956{
5957 CTI_STACK_HACK();
5958
5959 CallFrame* callFrame = ARG_callFrame;
5960 unsigned property = ARG_int2;
5961
5962 ARG_src1->put(callFrame, property, ARG_src3);
5963}
5964
5965void* Interpreter::cti_op_switch_imm(CTI_ARGS)
5966{
5967 CTI_STACK_HACK();
5968
5969 JSValue* scrutinee = ARG_src1;
5970 unsigned tableIndex = ARG_int2;
5971 CallFrame* callFrame = ARG_callFrame;
5972 CodeBlock* codeBlock = callFrame->codeBlock();
5973
5974 if (JSImmediate::isNumber(scrutinee)) {
5975 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
5976 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(value);
5977 }
5978
5979 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault;
5980}
5981
5982void* Interpreter::cti_op_switch_char(CTI_ARGS)
5983{
5984 CTI_STACK_HACK();
5985
5986 JSValue* scrutinee = ARG_src1;
5987 unsigned tableIndex = ARG_int2;
5988 CallFrame* callFrame = ARG_callFrame;
5989 CodeBlock* codeBlock = callFrame->codeBlock();
5990
5991 void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault;
5992
5993 if (scrutinee->isString()) {
5994 UString::Rep* value = asString(scrutinee)->value().rep();
5995 if (value->size() == 1)
5996 result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->data()[0]);
5997 }
5998
5999 return result;
6000}
6001
6002void* Interpreter::cti_op_switch_string(CTI_ARGS)
6003{
6004 CTI_STACK_HACK();
6005
6006 JSValue* scrutinee = ARG_src1;
6007 unsigned tableIndex = ARG_int2;
6008 CallFrame* callFrame = ARG_callFrame;
6009 CodeBlock* codeBlock = callFrame->codeBlock();
6010
6011 void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault;
6012
6013 if (scrutinee->isString()) {
6014 UString::Rep* value = asString(scrutinee)->value().rep();
6015 result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value);
6016 }
6017
6018 return result;
6019}
6020
6021JSValue* Interpreter::cti_op_del_by_val(CTI_ARGS)
6022{
6023 CTI_STACK_HACK();
6024
6025 CallFrame* callFrame = ARG_callFrame;
6026
6027 JSValue* baseValue = ARG_src1;
6028 JSObject* baseObj = baseValue->toObject(callFrame); // may throw
6029
6030 JSValue* subscript = ARG_src2;
6031 JSValue* result;
6032 uint32_t i;
6033 if (subscript->getUInt32(i))
6034 result = jsBoolean(baseObj->deleteProperty(callFrame, i));
6035 else {
6036 CHECK_FOR_EXCEPTION();
6037 Identifier property(callFrame, subscript->toString(callFrame));
6038 CHECK_FOR_EXCEPTION();
6039 result = jsBoolean(baseObj->deleteProperty(callFrame, property));
6040 }
6041
6042 CHECK_FOR_EXCEPTION_AT_END();
6043 return result;
6044}
6045
6046void Interpreter::cti_op_put_getter(CTI_ARGS)
6047{
6048 CTI_STACK_HACK();
6049
6050 CallFrame* callFrame = ARG_callFrame;
6051
6052 ASSERT(ARG_src1->isObject());
6053 JSObject* baseObj = asObject(ARG_src1);
6054 ASSERT(ARG_src3->isObject());
6055 baseObj->defineGetter(callFrame, *ARG_id2, asObject(ARG_src3));
6056}
6057
6058void Interpreter::cti_op_put_setter(CTI_ARGS)
6059{
6060 CTI_STACK_HACK();
6061
6062 CallFrame* callFrame = ARG_callFrame;
6063
6064 ASSERT(ARG_src1->isObject());
6065 JSObject* baseObj = asObject(ARG_src1);
6066 ASSERT(ARG_src3->isObject());
6067 baseObj->defineSetter(callFrame, *ARG_id2, asObject(ARG_src3));
6068}
6069
6070JSObject* Interpreter::cti_op_new_error(CTI_ARGS)
6071{
6072 CTI_STACK_HACK();
6073
6074 CallFrame* callFrame = ARG_callFrame;
6075 CodeBlock* codeBlock = callFrame->codeBlock();
6076 unsigned type = ARG_int1;
6077 JSValue* message = ARG_src2;
6078 unsigned lineNumber = ARG_int3;
6079
6080 return Error::create(callFrame, static_cast<ErrorType>(type), message->toString(callFrame), lineNumber, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL());
6081}
6082
6083void Interpreter::cti_op_debug(CTI_ARGS)
6084{
6085 CTI_STACK_HACK();
6086
6087 CallFrame* callFrame = ARG_callFrame;
6088
6089 int debugHookID = ARG_int1;
6090 int firstLine = ARG_int2;
6091 int lastLine = ARG_int3;
6092
6093 ARG_globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
6094}
6095
6096JSValue* Interpreter::cti_vm_throw(CTI_ARGS)
6097{
6098 CTI_STACK_HACK();
6099
6100 CallFrame* callFrame = ARG_callFrame;
6101 CodeBlock* codeBlock = callFrame->codeBlock();
6102 JSGlobalData* globalData = ARG_globalData;
6103
6104 ASSERT(codeBlock->jitReturnAddressVPCMap().contains(globalData->exceptionLocation));
6105 unsigned vPCIndex = codeBlock->jitReturnAddressVPCMap().get(globalData->exceptionLocation);
6106
6107 JSValue* exceptionValue = globalData->exception;
6108 ASSERT(exceptionValue);
6109 globalData->exception = noValue();
6110
6111 Instruction* handlerVPC = globalData->interpreter->throwException(callFrame, exceptionValue, codeBlock->instructions().begin() + vPCIndex, false);
6112
6113 if (!handlerVPC) {
6114 *ARG_exception = exceptionValue;
6115 return JSImmediate::nullImmediate();
6116 }
6117
6118 ARG_setCallFrame(callFrame);
6119 void* catchRoutine = callFrame->codeBlock()->nativeExceptionCodeForHandlerVPC(handlerVPC);
6120 ASSERT(catchRoutine);
6121 CTI_SET_RETURN_ADDRESS(catchRoutine);
6122 return exceptionValue;
6123}
6124
6125#undef CTI_RETURN_ADDRESS
6126#undef CTI_SET_RETURN_ADDRESS
6127#undef CTI_STACK_HACK
6128#undef CHECK_FOR_EXCEPTION
6129#undef CHECK_FOR_EXCEPTION_AT_END
6130#undef CHECK_FOR_EXCEPTION_VOID
6131#undef VM_THROW_EXCEPTION
6132#undef VM_THROW_EXCEPTION_2
6133#undef VM_THROW_EXCEPTION_AT_END
6134
6135#endif // ENABLE(JIT)
6136
6137} // namespace JSC
Note: See TracBrowser for help on using the repository browser.