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

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

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

Reviewed by Geoffrey Garen.

Encapsulate access to jump tables in the CodeBlock in preparation
of moving them to a rare data structure.

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): (JSC::CodeBlock::shrinkToFit):
  • bytecode/CodeBlock.h: (JSC::CodeBlock::numberOfImmediateSwitchJumpTables): (JSC::CodeBlock::addImmediateSwitchJumpTable): (JSC::CodeBlock::immediateSwitchJumpTable): (JSC::CodeBlock::numberOfCharacterSwitchJumpTables): (JSC::CodeBlock::addCharacterSwitchJumpTable): (JSC::CodeBlock::characterSwitchJumpTable): (JSC::CodeBlock::numberOfStringSwitchJumpTables): (JSC::CodeBlock::addStringSwitchJumpTable): (JSC::CodeBlock::stringSwitchJumpTable):
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::endSwitch):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute): (JSC::Interpreter::cti_op_switch_imm): (JSC::Interpreter::cti_op_switch_char): (JSC::Interpreter::cti_op_switch_string):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass):
File size: 209.5 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->ctiReturnAddressVPCMap.contains(pc));
99 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.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->identifiers[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->identifiers[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->identifiers[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()->identifiers[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->identifiers[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->identifiers[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->numCalleeRegisters;
541
542 if (LIKELY(argc == newCodeBlock->numParameters)) { // correct number of arguments
543 if (UNLIKELY(!registerFile->grow(newEnd)))
544 return 0;
545 r += registerOffset;
546 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
547 size_t omittedArgCount = newCodeBlock->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->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->numParameters;
689 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
690 end = it + max(codeBlock->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->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->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->numCalleeRegisters - codeBlock->numConstants - codeBlock->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->numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->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->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->ctiCode)
939 JIT::compile(scopeChain->globalData, codeBlock);
940 result = JIT::execute(codeBlock->ctiCode, &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->ctiCode)
1005 JIT::compile(scopeChain->globalData, codeBlock);
1006 result = JIT::execute(codeBlock->ctiCode, &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).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->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->ctiCode)
1097 JIT::compile(scopeChain->globalData, codeBlock);
1098 result = JIT::execute(codeBlock->ctiCode, &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->identifiers[(++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()->regexps[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->identifiers[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()->identifiers[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()->identifiers[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()->identifiers[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()->identifiers[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->identifiers[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()->identifiers[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()->identifiers[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()->identifiers[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()->identifiers[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()->functions[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()->functionExpressions[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->numVars; i < count; ++i)
3486 callFrame[i] = jsUndefined();
3487
3488 for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
3489 callFrame[i] = codeBlock->constantRegisters[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->numVars; i < count; ++i)
3511 callFrame[i] = jsUndefined();
3512
3513 for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
3514 callFrame[i] = codeBlock->constantRegisters[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()->unexpectedConstants[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->unexpectedConstants[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()->identifiers[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()->identifiers[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->ctiReturnAddressVPCMap.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->ctiReturnAddressVPCMap.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
4410void Interpreter::cti_timeout_check(CTI_ARGS)
4411{
4412 CTI_STACK_HACK();
4413
4414 if (ARG_globalData->interpreter->checkTimeout(ARG_callFrame->dynamicGlobalObject())) {
4415 ARG_globalData->exception = createInterruptedExecutionException(ARG_globalData);
4416 VM_THROW_EXCEPTION_AT_END();
4417 }
4418}
4419
4420void Interpreter::cti_register_file_check(CTI_ARGS)
4421{
4422 CTI_STACK_HACK();
4423
4424 if (LIKELY(ARG_registerFile->grow(ARG_callFrame + ARG_callFrame->codeBlock()->numCalleeRegisters)))
4425 return;
4426
4427 // Rewind to the previous call frame because op_call already optimistically
4428 // moved the call frame forward.
4429 CallFrame* oldCallFrame = ARG_callFrame->callerFrame();
4430 ARG_setCallFrame(oldCallFrame);
4431 throwStackOverflowError(oldCallFrame, ARG_globalData, oldCallFrame->returnPC(), CTI_RETURN_ADDRESS);
4432}
4433
4434int Interpreter::cti_op_loop_if_less(CTI_ARGS)
4435{
4436 CTI_STACK_HACK();
4437
4438 JSValue* src1 = ARG_src1;
4439 JSValue* src2 = ARG_src2;
4440 CallFrame* callFrame = ARG_callFrame;
4441
4442 bool result = jsLess(callFrame, src1, src2);
4443 CHECK_FOR_EXCEPTION_AT_END();
4444 return result;
4445}
4446
4447int Interpreter::cti_op_loop_if_lesseq(CTI_ARGS)
4448{
4449 CTI_STACK_HACK();
4450
4451 JSValue* src1 = ARG_src1;
4452 JSValue* src2 = ARG_src2;
4453 CallFrame* callFrame = ARG_callFrame;
4454
4455 bool result = jsLessEq(callFrame, src1, src2);
4456 CHECK_FOR_EXCEPTION_AT_END();
4457 return result;
4458}
4459
4460JSObject* Interpreter::cti_op_new_object(CTI_ARGS)
4461{
4462 CTI_STACK_HACK();
4463
4464 return constructEmptyObject(ARG_callFrame);
4465}
4466
4467void Interpreter::cti_op_put_by_id(CTI_ARGS)
4468{
4469 CTI_STACK_HACK();
4470
4471 CallFrame* callFrame = ARG_callFrame;
4472 Identifier& ident = *ARG_id2;
4473
4474 PutPropertySlot slot;
4475 ARG_src1->put(callFrame, ident, ARG_src3, slot);
4476
4477 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_put_by_id_second));
4478
4479 CHECK_FOR_EXCEPTION_AT_END();
4480}
4481
4482void Interpreter::cti_op_put_by_id_second(CTI_ARGS)
4483{
4484 CTI_STACK_HACK();
4485
4486 PutPropertySlot slot;
4487 ARG_src1->put(ARG_callFrame, *ARG_id2, ARG_src3, slot);
4488 ARG_globalData->interpreter->tryCTICachePutByID(ARG_callFrame, ARG_callFrame->codeBlock(), CTI_RETURN_ADDRESS, ARG_src1, slot);
4489 CHECK_FOR_EXCEPTION_AT_END();
4490}
4491
4492void Interpreter::cti_op_put_by_id_generic(CTI_ARGS)
4493{
4494 CTI_STACK_HACK();
4495
4496 PutPropertySlot slot;
4497 ARG_src1->put(ARG_callFrame, *ARG_id2, ARG_src3, slot);
4498 CHECK_FOR_EXCEPTION_AT_END();
4499}
4500
4501void Interpreter::cti_op_put_by_id_fail(CTI_ARGS)
4502{
4503 CTI_STACK_HACK();
4504
4505 CallFrame* callFrame = ARG_callFrame;
4506 Identifier& ident = *ARG_id2;
4507
4508 PutPropertySlot slot;
4509 ARG_src1->put(callFrame, ident, ARG_src3, slot);
4510
4511 CHECK_FOR_EXCEPTION_AT_END();
4512}
4513
4514JSValue* Interpreter::cti_op_get_by_id(CTI_ARGS)
4515{
4516 CTI_STACK_HACK();
4517
4518 CallFrame* callFrame = ARG_callFrame;
4519 Identifier& ident = *ARG_id2;
4520
4521 JSValue* baseValue = ARG_src1;
4522 PropertySlot slot(baseValue);
4523 JSValue* result = baseValue->get(callFrame, ident, slot);
4524
4525 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_second));
4526
4527 CHECK_FOR_EXCEPTION_AT_END();
4528 return result;
4529}
4530
4531JSValue* Interpreter::cti_op_get_by_id_second(CTI_ARGS)
4532{
4533 CTI_STACK_HACK();
4534
4535 CallFrame* callFrame = ARG_callFrame;
4536 Identifier& ident = *ARG_id2;
4537
4538 JSValue* baseValue = ARG_src1;
4539 PropertySlot slot(baseValue);
4540 JSValue* result = baseValue->get(callFrame, ident, slot);
4541
4542 ARG_globalData->interpreter->tryCTICacheGetByID(callFrame, callFrame->codeBlock(), CTI_RETURN_ADDRESS, baseValue, ident, slot);
4543
4544 CHECK_FOR_EXCEPTION_AT_END();
4545 return result;
4546}
4547
4548JSValue* Interpreter::cti_op_get_by_id_generic(CTI_ARGS)
4549{
4550 CTI_STACK_HACK();
4551
4552 CallFrame* callFrame = ARG_callFrame;
4553 Identifier& ident = *ARG_id2;
4554
4555 JSValue* baseValue = ARG_src1;
4556 PropertySlot slot(baseValue);
4557 JSValue* result = baseValue->get(callFrame, ident, slot);
4558
4559 CHECK_FOR_EXCEPTION_AT_END();
4560 return result;
4561}
4562
4563JSValue* Interpreter::cti_op_get_by_id_self_fail(CTI_ARGS)
4564{
4565 CTI_STACK_HACK();
4566
4567 CallFrame* callFrame = ARG_callFrame;
4568 Identifier& ident = *ARG_id2;
4569
4570 JSValue* baseValue = ARG_src1;
4571 PropertySlot slot(baseValue);
4572 JSValue* result = baseValue->get(callFrame, ident, slot);
4573
4574 CHECK_FOR_EXCEPTION();
4575
4576 if (baseValue->isObject()
4577 && slot.isCacheable()
4578 && !asCell(baseValue)->structure()->isDictionary()
4579 && slot.slotBase() == baseValue) {
4580
4581 CodeBlock* codeBlock = callFrame->codeBlock();
4582 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
4583 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
4584
4585 ASSERT(slot.slotBase()->isObject());
4586
4587 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(CTI_RETURN_ADDRESS);
4588
4589 PolymorphicAccessStructureList* polymorphicStructureList;
4590 int listIndex = 1;
4591
4592 if (vPC[0].u.opcode == ARG_globalData->interpreter->getOpcode(op_get_by_id_self)) {
4593 ASSERT(!stubInfo->stubRoutine);
4594 polymorphicStructureList = new PolymorphicAccessStructureList(vPC[5].u.operand, 0, vPC[4].u.structure);
4595
4596 vPC[0] = ARG_globalData->interpreter->getOpcode(op_get_by_id_self_list);
4597 vPC[4] = polymorphicStructureList;
4598 vPC[5] = 2;
4599 } else {
4600 polymorphicStructureList = vPC[4].u.polymorphicStructures;
4601 listIndex = vPC[5].u.operand;
4602
4603 vPC[5] = listIndex + 1;
4604 }
4605
4606 JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), slot.cachedOffset());
4607
4608 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
4609 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_generic));
4610 } else {
4611 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_generic));
4612 }
4613 return result;
4614}
4615
4616static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(Interpreter* interpreter, StructureStubInfo* stubInfo, Instruction* vPC, int& listIndex)
4617{
4618 PolymorphicAccessStructureList* prototypeStructureList;
4619 listIndex = 1;
4620
4621 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
4622 prototypeStructureList = new PolymorphicAccessStructureList(vPC[6].u.operand, stubInfo->stubRoutine, vPC[4].u.structure, vPC[5].u.structure);
4623 stubInfo->stubRoutine = 0;
4624
4625 vPC[0] = interpreter->getOpcode(op_get_by_id_proto_list);
4626 vPC[4] = prototypeStructureList;
4627 vPC[5] = 2;
4628 } else if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
4629 prototypeStructureList = new PolymorphicAccessStructureList(vPC[6].u.operand, stubInfo->stubRoutine, vPC[4].u.structure, vPC[5].u.structureChain);
4630 stubInfo->stubRoutine = 0;
4631
4632 vPC[0] = interpreter->getOpcode(op_get_by_id_proto_list);
4633 vPC[4] = prototypeStructureList;
4634 vPC[5] = 2;
4635 } else {
4636 ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list));
4637 prototypeStructureList = vPC[4].u.polymorphicStructures;
4638 listIndex = vPC[5].u.operand;
4639 vPC[5] = listIndex + 1;
4640
4641 ASSERT(listIndex < POLYMORPHIC_LIST_CACHE_SIZE);
4642 }
4643
4644 return prototypeStructureList;
4645}
4646
4647JSValue* Interpreter::cti_op_get_by_id_proto_list(CTI_ARGS)
4648{
4649 CTI_STACK_HACK();
4650
4651 CallFrame* callFrame = ARG_callFrame;
4652
4653 JSValue* baseValue = ARG_src1;
4654 PropertySlot slot(baseValue);
4655 JSValue* result = baseValue->get(callFrame, *ARG_id2, slot);
4656
4657 CHECK_FOR_EXCEPTION();
4658
4659 if (!baseValue->isObject() || !slot.isCacheable() || asCell(baseValue)->structure()->isDictionary()) {
4660 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_fail));
4661 return result;
4662 }
4663
4664 Structure* structure = asCell(baseValue)->structure();
4665 CodeBlock* codeBlock = callFrame->codeBlock();
4666 Instruction* vPC = codeBlock->instructions.begin() + codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
4667
4668 ASSERT(slot.slotBase()->isObject());
4669 JSObject* slotBaseObject = asObject(slot.slotBase());
4670
4671 if (slot.slotBase() == baseValue)
4672 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_fail));
4673 else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) {
4674 // Heavy access to a prototype is a good indication that it's not being
4675 // used as a dictionary.
4676 if (slotBaseObject->structure()->isDictionary()) {
4677 RefPtr<Structure> transition = Structure::fromDictionaryTransition(slotBaseObject->structure());
4678 slotBaseObject->setStructure(transition.release());
4679 asObject(baseValue)->structure()->setCachedPrototypeChain(0);
4680 }
4681
4682 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(CTI_RETURN_ADDRESS);
4683 int listIndex;
4684 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(ARG_globalData->interpreter, stubInfo, vPC, listIndex);
4685
4686 JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), slot.cachedOffset());
4687
4688 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
4689 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_list_full));
4690 } else if (size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot)) {
4691 StructureChain* chain = structure->cachedPrototypeChain();
4692 if (!chain)
4693 chain = cachePrototypeChain(callFrame, structure);
4694 ASSERT(chain);
4695
4696 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(CTI_RETURN_ADDRESS);
4697 int listIndex;
4698 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(ARG_globalData->interpreter, stubInfo, vPC, listIndex);
4699
4700 JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, chain, count, slot.cachedOffset());
4701
4702 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
4703 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_list_full));
4704 } else
4705 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, reinterpret_cast<void*>(cti_op_get_by_id_proto_fail));
4706
4707 return result;
4708}
4709
4710JSValue* Interpreter::cti_op_get_by_id_proto_list_full(CTI_ARGS)
4711{
4712 CTI_STACK_HACK();
4713
4714 JSValue* baseValue = ARG_src1;
4715 PropertySlot slot(baseValue);
4716 JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
4717
4718 CHECK_FOR_EXCEPTION_AT_END();
4719 return result;
4720}
4721
4722JSValue* Interpreter::cti_op_get_by_id_proto_fail(CTI_ARGS)
4723{
4724 CTI_STACK_HACK();
4725
4726 JSValue* baseValue = ARG_src1;
4727 PropertySlot slot(baseValue);
4728 JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
4729
4730 CHECK_FOR_EXCEPTION_AT_END();
4731 return result;
4732}
4733
4734JSValue* Interpreter::cti_op_get_by_id_array_fail(CTI_ARGS)
4735{
4736 CTI_STACK_HACK();
4737
4738 JSValue* baseValue = ARG_src1;
4739 PropertySlot slot(baseValue);
4740 JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
4741
4742 CHECK_FOR_EXCEPTION_AT_END();
4743 return result;
4744}
4745
4746JSValue* Interpreter::cti_op_get_by_id_string_fail(CTI_ARGS)
4747{
4748 CTI_STACK_HACK();
4749
4750 JSValue* baseValue = ARG_src1;
4751 PropertySlot slot(baseValue);
4752 JSValue* result = baseValue->get(ARG_callFrame, *ARG_id2, slot);
4753
4754 CHECK_FOR_EXCEPTION_AT_END();
4755 return result;
4756}
4757
4758JSValue* Interpreter::cti_op_instanceof(CTI_ARGS)
4759{
4760 CTI_STACK_HACK();
4761
4762 CallFrame* callFrame = ARG_callFrame;
4763 JSValue* value = ARG_src1;
4764 JSValue* baseVal = ARG_src2;
4765 JSValue* proto = ARG_src3;
4766
4767 // at least one of these checks must have failed to get to the slow case
4768 ASSERT(JSImmediate::isAnyImmediate(value, baseVal, proto)
4769 || !value->isObject() || !baseVal->isObject() || !proto->isObject()
4770 || (asObject(baseVal)->structure()->typeInfo().flags() & (ImplementsHasInstance | OverridesHasInstance)) != ImplementsHasInstance);
4771
4772 if (!baseVal->isObject()) {
4773 CallFrame* callFrame = ARG_callFrame;
4774 CodeBlock* codeBlock = callFrame->codeBlock();
4775 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
4776 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
4777 ARG_globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal, codeBlock->instructions.begin() + vPCIndex, codeBlock);
4778 VM_THROW_EXCEPTION();
4779 }
4780
4781 if (!asObject(baseVal)->structure()->typeInfo().implementsHasInstance())
4782 return jsBoolean(false);
4783
4784 if (!proto->isObject()) {
4785 throwError(callFrame, TypeError, "instanceof called on an object with an invalid prototype property.");
4786 VM_THROW_EXCEPTION();
4787 }
4788
4789 if (!value->isObject())
4790 return jsBoolean(false);
4791
4792 JSValue* result = jsBoolean(asObject(baseVal)->hasInstance(callFrame, value, proto));
4793 CHECK_FOR_EXCEPTION_AT_END();
4794
4795 return result;
4796}
4797
4798JSValue* Interpreter::cti_op_del_by_id(CTI_ARGS)
4799{
4800 CTI_STACK_HACK();
4801
4802 CallFrame* callFrame = ARG_callFrame;
4803
4804 JSObject* baseObj = ARG_src1->toObject(callFrame);
4805
4806 JSValue* result = jsBoolean(baseObj->deleteProperty(callFrame, *ARG_id2));
4807 CHECK_FOR_EXCEPTION_AT_END();
4808 return result;
4809}
4810
4811JSValue* Interpreter::cti_op_mul(CTI_ARGS)
4812{
4813 CTI_STACK_HACK();
4814
4815 JSValue* src1 = ARG_src1;
4816 JSValue* src2 = ARG_src2;
4817
4818 double left;
4819 double right;
4820 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
4821 return jsNumber(ARG_globalData, left * right);
4822
4823 CallFrame* callFrame = ARG_callFrame;
4824 JSValue* result = jsNumber(ARG_globalData, src1->toNumber(callFrame) * src2->toNumber(callFrame));
4825 CHECK_FOR_EXCEPTION_AT_END();
4826 return result;
4827}
4828
4829JSObject* Interpreter::cti_op_new_func(CTI_ARGS)
4830{
4831 CTI_STACK_HACK();
4832
4833 return ARG_func1->makeFunction(ARG_callFrame, ARG_callFrame->scopeChain());
4834}
4835
4836void* Interpreter::cti_op_call_JSFunction(CTI_ARGS)
4837{
4838 CTI_STACK_HACK();
4839
4840#ifndef NDEBUG
4841 CallData callData;
4842 ASSERT(ARG_src1->getCallData(callData) == CallTypeJS);
4843#endif
4844
4845 ScopeChainNode* callDataScopeChain = asFunction(ARG_src1)->m_scopeChain.node();
4846 CodeBlock* newCodeBlock = &asFunction(ARG_src1)->body()->bytecode(callDataScopeChain);
4847
4848 if (!newCodeBlock->ctiCode)
4849 JIT::compile(ARG_globalData, newCodeBlock);
4850
4851 return newCodeBlock;
4852}
4853
4854VoidPtrPair Interpreter::cti_op_call_arityCheck(CTI_ARGS)
4855{
4856 CTI_STACK_HACK();
4857
4858 CallFrame* callFrame = ARG_callFrame;
4859 CodeBlock* newCodeBlock = ARG_codeBlock4;
4860 int argCount = ARG_int3;
4861
4862 ASSERT(argCount != newCodeBlock->numParameters);
4863
4864 CallFrame* oldCallFrame = callFrame->callerFrame();
4865
4866 if (argCount > newCodeBlock->numParameters) {
4867 size_t numParameters = newCodeBlock->numParameters;
4868 Register* r = callFrame->registers() + numParameters;
4869
4870 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
4871 for (size_t i = 0; i < numParameters; ++i)
4872 argv[i + argCount] = argv[i];
4873
4874 callFrame = CallFrame::create(r);
4875 callFrame->setCallerFrame(oldCallFrame);
4876 } else {
4877 size_t omittedArgCount = newCodeBlock->numParameters - argCount;
4878 Register* r = callFrame->registers() + omittedArgCount;
4879 Register* newEnd = r + newCodeBlock->numCalleeRegisters;
4880 if (!ARG_registerFile->grow(newEnd)) {
4881 // Rewind to the previous call frame because op_call already optimistically
4882 // moved the call frame forward.
4883 ARG_setCallFrame(oldCallFrame);
4884 throwStackOverflowError(oldCallFrame, ARG_globalData, ARG_returnAddress2, CTI_RETURN_ADDRESS);
4885 VoidPtrPairValue pair = {{ 0, 0 }};
4886 return pair.i;
4887 }
4888
4889 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
4890 for (size_t i = 0; i < omittedArgCount; ++i)
4891 argv[i] = jsUndefined();
4892
4893 callFrame = CallFrame::create(r);
4894 callFrame->setCallerFrame(oldCallFrame);
4895 }
4896
4897 VoidPtrPairValue pair = {{ newCodeBlock, callFrame }};
4898 return pair.i;
4899}
4900
4901void* Interpreter::cti_vm_dontLazyLinkCall(CTI_ARGS)
4902{
4903 CTI_STACK_HACK();
4904
4905 JSFunction* callee = asFunction(ARG_src1);
4906 CodeBlock* codeBlock = &callee->body()->bytecode(callee->m_scopeChain.node());
4907 if (!codeBlock->ctiCode)
4908 JIT::compile(ARG_globalData, codeBlock);
4909
4910 ctiRepatchCallByReturnAddress(ARG_returnAddress2, ARG_globalData->interpreter->m_ctiVirtualCallLink);
4911
4912 return codeBlock->ctiCode;
4913}
4914
4915void* Interpreter::cti_vm_lazyLinkCall(CTI_ARGS)
4916{
4917 CTI_STACK_HACK();
4918
4919 JSFunction* callee = asFunction(ARG_src1);
4920 CodeBlock* codeBlock = &callee->body()->bytecode(callee->m_scopeChain.node());
4921 if (!codeBlock->ctiCode)
4922 JIT::compile(ARG_globalData, codeBlock);
4923
4924 CallLinkInfo* callLinkInfo = &ARG_callFrame->callerFrame()->codeBlock()->getCallLinkInfo(ARG_returnAddress2);
4925 JIT::linkCall(callee, codeBlock, codeBlock->ctiCode, callLinkInfo, ARG_int3);
4926
4927 return codeBlock->ctiCode;
4928}
4929
4930JSObject* Interpreter::cti_op_push_activation(CTI_ARGS)
4931{
4932 CTI_STACK_HACK();
4933
4934 JSActivation* activation = new (ARG_globalData) JSActivation(ARG_callFrame, static_cast<FunctionBodyNode*>(ARG_callFrame->codeBlock()->ownerNode));
4935 ARG_callFrame->setScopeChain(ARG_callFrame->scopeChain()->copy()->push(activation));
4936 return activation;
4937}
4938
4939JSValue* Interpreter::cti_op_call_NotJSFunction(CTI_ARGS)
4940{
4941 CTI_STACK_HACK();
4942
4943 JSValue* funcVal = ARG_src1;
4944
4945 CallData callData;
4946 CallType callType = funcVal->getCallData(callData);
4947
4948 ASSERT(callType != CallTypeJS);
4949
4950 if (callType == CallTypeHost) {
4951 int registerOffset = ARG_int2;
4952 int argCount = ARG_int3;
4953 CallFrame* previousCallFrame = ARG_callFrame;
4954 CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset);
4955
4956 callFrame->init(0, ARG_instr4 + 1, previousCallFrame->scopeChain(), previousCallFrame, 0, argCount, 0);
4957 ARG_setCallFrame(callFrame);
4958
4959 Register* argv = ARG_callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
4960 ArgList argList(argv + 1, argCount - 1);
4961
4962 JSValue* returnValue;
4963 {
4964 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
4965
4966 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
4967 JSValue* thisValue = argv[0].jsValue(callFrame);
4968 if (thisValue == jsNull())
4969 thisValue = callFrame->globalThisValue();
4970
4971 returnValue = callData.native.function(callFrame, asObject(funcVal), thisValue, argList);
4972 }
4973 ARG_setCallFrame(previousCallFrame);
4974 CHECK_FOR_EXCEPTION();
4975
4976 return returnValue;
4977 }
4978
4979 ASSERT(callType == CallTypeNone);
4980
4981 ARG_globalData->exception = createNotAFunctionError(ARG_callFrame, funcVal, ARG_instr4, ARG_callFrame->codeBlock());
4982 VM_THROW_EXCEPTION();
4983}
4984
4985void Interpreter::cti_op_create_arguments(CTI_ARGS)
4986{
4987 CTI_STACK_HACK();
4988
4989 Arguments* arguments = new (ARG_globalData) Arguments(ARG_callFrame);
4990 ARG_callFrame->setCalleeArguments(arguments);
4991 ARG_callFrame[RegisterFile::ArgumentsRegister] = arguments;
4992}
4993
4994void Interpreter::cti_op_create_arguments_no_params(CTI_ARGS)
4995{
4996 CTI_STACK_HACK();
4997
4998 Arguments* arguments = new (ARG_globalData) Arguments(ARG_callFrame, Arguments::NoParameters);
4999 ARG_callFrame->setCalleeArguments(arguments);
5000 ARG_callFrame[RegisterFile::ArgumentsRegister] = arguments;
5001}
5002
5003void Interpreter::cti_op_tear_off_activation(CTI_ARGS)
5004{
5005 CTI_STACK_HACK();
5006
5007 ASSERT(ARG_callFrame->codeBlock()->needsFullScopeChain);
5008 asActivation(ARG_src1)->copyRegisters(ARG_callFrame->optionalCalleeArguments());
5009}
5010
5011void Interpreter::cti_op_tear_off_arguments(CTI_ARGS)
5012{
5013 CTI_STACK_HACK();
5014
5015 ASSERT(ARG_callFrame->codeBlock()->usesArguments && !ARG_callFrame->codeBlock()->needsFullScopeChain);
5016 ARG_callFrame->optionalCalleeArguments()->copyRegisters();
5017}
5018
5019void Interpreter::cti_op_profile_will_call(CTI_ARGS)
5020{
5021 CTI_STACK_HACK();
5022
5023 ASSERT(*ARG_profilerReference);
5024 (*ARG_profilerReference)->willExecute(ARG_callFrame, ARG_src1);
5025}
5026
5027void Interpreter::cti_op_profile_did_call(CTI_ARGS)
5028{
5029 CTI_STACK_HACK();
5030
5031 ASSERT(*ARG_profilerReference);
5032 (*ARG_profilerReference)->didExecute(ARG_callFrame, ARG_src1);
5033}
5034
5035void Interpreter::cti_op_ret_scopeChain(CTI_ARGS)
5036{
5037 CTI_STACK_HACK();
5038
5039 ASSERT(ARG_callFrame->codeBlock()->needsFullScopeChain);
5040 ARG_callFrame->scopeChain()->deref();
5041}
5042
5043JSObject* Interpreter::cti_op_new_array(CTI_ARGS)
5044{
5045 CTI_STACK_HACK();
5046
5047 ArgList argList(ARG_registers1, ARG_int2);
5048 return constructArray(ARG_callFrame, argList);
5049}
5050
5051JSValue* Interpreter::cti_op_resolve(CTI_ARGS)
5052{
5053 CTI_STACK_HACK();
5054
5055 CallFrame* callFrame = ARG_callFrame;
5056 ScopeChainNode* scopeChain = callFrame->scopeChain();
5057
5058 ScopeChainIterator iter = scopeChain->begin();
5059 ScopeChainIterator end = scopeChain->end();
5060 ASSERT(iter != end);
5061
5062 Identifier& ident = *ARG_id1;
5063 do {
5064 JSObject* o = *iter;
5065 PropertySlot slot(o);
5066 if (o->getPropertySlot(callFrame, ident, slot)) {
5067 JSValue* result = slot.getValue(callFrame, ident);
5068 CHECK_FOR_EXCEPTION_AT_END();
5069 return result;
5070 }
5071 } while (++iter != end);
5072
5073 CodeBlock* codeBlock = callFrame->codeBlock();
5074 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
5075 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
5076 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock);
5077 VM_THROW_EXCEPTION();
5078}
5079
5080JSObject* Interpreter::cti_op_construct_JSConstruct(CTI_ARGS)
5081{
5082 CTI_STACK_HACK();
5083
5084#ifndef NDEBUG
5085 ConstructData constructData;
5086 ASSERT(asFunction(ARG_src1)->getConstructData(constructData) == ConstructTypeJS);
5087#endif
5088
5089 Structure* structure;
5090 if (ARG_src4->isObject())
5091 structure = asObject(ARG_src4)->inheritorID();
5092 else
5093 structure = asFunction(ARG_src1)->m_scopeChain.node()->globalObject()->emptyObjectStructure();
5094 return new (ARG_globalData) JSObject(structure);
5095}
5096
5097JSValue* Interpreter::cti_op_construct_NotJSConstruct(CTI_ARGS)
5098{
5099 CTI_STACK_HACK();
5100
5101 CallFrame* callFrame = ARG_callFrame;
5102
5103 JSValue* constrVal = ARG_src1;
5104 int argCount = ARG_int3;
5105 int thisRegister = ARG_int5;
5106
5107 ConstructData constructData;
5108 ConstructType constructType = constrVal->getConstructData(constructData);
5109
5110 if (constructType == ConstructTypeHost) {
5111 ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1);
5112
5113 JSValue* returnValue;
5114 {
5115 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
5116 returnValue = constructData.native.function(callFrame, asObject(constrVal), argList);
5117 }
5118 CHECK_FOR_EXCEPTION();
5119
5120 return returnValue;
5121 }
5122
5123 ASSERT(constructType == ConstructTypeNone);
5124
5125 ARG_globalData->exception = createNotAConstructorError(callFrame, constrVal, ARG_instr6, callFrame->codeBlock());
5126 VM_THROW_EXCEPTION();
5127}
5128
5129JSValue* Interpreter::cti_op_get_by_val(CTI_ARGS)
5130{
5131 CTI_STACK_HACK();
5132
5133 CallFrame* callFrame = ARG_callFrame;
5134 Interpreter* interpreter = ARG_globalData->interpreter;
5135
5136 JSValue* baseValue = ARG_src1;
5137 JSValue* subscript = ARG_src2;
5138
5139 JSValue* result;
5140 unsigned i;
5141
5142 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
5143 if (LIKELY(isUInt32)) {
5144 if (interpreter->isJSArray(baseValue)) {
5145 JSArray* jsArray = asArray(baseValue);
5146 if (jsArray->canGetIndex(i))
5147 result = jsArray->getIndex(i);
5148 else
5149 result = jsArray->JSArray::get(callFrame, i);
5150 } else if (interpreter->isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
5151 result = asString(baseValue)->getIndex(ARG_globalData, i);
5152 else
5153 result = baseValue->get(callFrame, i);
5154 } else {
5155 Identifier property(callFrame, subscript->toString(callFrame));
5156 result = baseValue->get(callFrame, property);
5157 }
5158
5159 CHECK_FOR_EXCEPTION_AT_END();
5160 return result;
5161}
5162
5163VoidPtrPair Interpreter::cti_op_resolve_func(CTI_ARGS)
5164{
5165 CTI_STACK_HACK();
5166
5167 CallFrame* callFrame = ARG_callFrame;
5168 ScopeChainNode* scopeChain = callFrame->scopeChain();
5169
5170 ScopeChainIterator iter = scopeChain->begin();
5171 ScopeChainIterator end = scopeChain->end();
5172
5173 // FIXME: add scopeDepthIsZero optimization
5174
5175 ASSERT(iter != end);
5176
5177 Identifier& ident = *ARG_id1;
5178 JSObject* base;
5179 do {
5180 base = *iter;
5181 PropertySlot slot(base);
5182 if (base->getPropertySlot(callFrame, ident, slot)) {
5183 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
5184 // However, section 10.2.3 says that in the case where the value provided
5185 // by the caller is null, the global object should be used. It also says
5186 // that the section does not apply to internal functions, but for simplicity
5187 // of implementation we use the global object anyway here. This guarantees
5188 // that in host objects you always get a valid object for this.
5189 // We also handle wrapper substitution for the global object at the same time.
5190 JSObject* thisObj = base->toThisObject(callFrame);
5191 JSValue* result = slot.getValue(callFrame, ident);
5192 CHECK_FOR_EXCEPTION_AT_END();
5193
5194 VoidPtrPairValue pair = {{ thisObj, asPointer(result) }};
5195 return pair.i;
5196 }
5197 ++iter;
5198 } while (iter != end);
5199
5200 CodeBlock* codeBlock = callFrame->codeBlock();
5201 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
5202 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
5203 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock);
5204 VM_THROW_EXCEPTION_2();
5205}
5206
5207JSValue* Interpreter::cti_op_sub(CTI_ARGS)
5208{
5209 CTI_STACK_HACK();
5210
5211 JSValue* src1 = ARG_src1;
5212 JSValue* src2 = ARG_src2;
5213
5214 double left;
5215 double right;
5216 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
5217 return jsNumber(ARG_globalData, left - right);
5218
5219 CallFrame* callFrame = ARG_callFrame;
5220 JSValue* result = jsNumber(ARG_globalData, src1->toNumber(callFrame) - src2->toNumber(callFrame));
5221 CHECK_FOR_EXCEPTION_AT_END();
5222 return result;
5223}
5224
5225void Interpreter::cti_op_put_by_val(CTI_ARGS)
5226{
5227 CTI_STACK_HACK();
5228
5229 CallFrame* callFrame = ARG_callFrame;
5230 Interpreter* interpreter = ARG_globalData->interpreter;
5231
5232 JSValue* baseValue = ARG_src1;
5233 JSValue* subscript = ARG_src2;
5234 JSValue* value = ARG_src3;
5235
5236 unsigned i;
5237
5238 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
5239 if (LIKELY(isUInt32)) {
5240 if (interpreter->isJSArray(baseValue)) {
5241 JSArray* jsArray = asArray(baseValue);
5242 if (jsArray->canSetIndex(i))
5243 jsArray->setIndex(i, value);
5244 else
5245 jsArray->JSArray::put(callFrame, i, value);
5246 } else
5247 baseValue->put(callFrame, i, value);
5248 } else {
5249 Identifier property(callFrame, subscript->toString(callFrame));
5250 if (!ARG_globalData->exception) { // Don't put to an object if toString threw an exception.
5251 PutPropertySlot slot;
5252 baseValue->put(callFrame, property, value, slot);
5253 }
5254 }
5255
5256 CHECK_FOR_EXCEPTION_AT_END();
5257}
5258
5259void Interpreter::cti_op_put_by_val_array(CTI_ARGS)
5260{
5261 CTI_STACK_HACK();
5262
5263 CallFrame* callFrame = ARG_callFrame;
5264
5265 JSValue* baseValue = ARG_src1;
5266 int i = ARG_int2;
5267 JSValue* value = ARG_src3;
5268
5269 ASSERT(ARG_globalData->interpreter->isJSArray(baseValue));
5270
5271 if (LIKELY(i >= 0))
5272 asArray(baseValue)->JSArray::put(callFrame, i, value);
5273 else {
5274 Identifier property(callFrame, JSImmediate::from(i)->toString(callFrame));
5275 // FIXME: can toString throw an exception here?
5276 if (!ARG_globalData->exception) { // Don't put to an object if toString threw an exception.
5277 PutPropertySlot slot;
5278 baseValue->put(callFrame, property, value, slot);
5279 }
5280 }
5281
5282 CHECK_FOR_EXCEPTION_AT_END();
5283}
5284
5285JSValue* Interpreter::cti_op_lesseq(CTI_ARGS)
5286{
5287 CTI_STACK_HACK();
5288
5289 CallFrame* callFrame = ARG_callFrame;
5290 JSValue* result = jsBoolean(jsLessEq(callFrame, ARG_src1, ARG_src2));
5291 CHECK_FOR_EXCEPTION_AT_END();
5292 return result;
5293}
5294
5295int Interpreter::cti_op_loop_if_true(CTI_ARGS)
5296{
5297 CTI_STACK_HACK();
5298
5299 JSValue* src1 = ARG_src1;
5300
5301 CallFrame* callFrame = ARG_callFrame;
5302
5303 bool result = src1->toBoolean(callFrame);
5304 CHECK_FOR_EXCEPTION_AT_END();
5305 return result;
5306}
5307
5308JSValue* Interpreter::cti_op_negate(CTI_ARGS)
5309{
5310 CTI_STACK_HACK();
5311
5312 JSValue* src = ARG_src1;
5313
5314 double v;
5315 if (fastIsNumber(src, v))
5316 return jsNumber(ARG_globalData, -v);
5317
5318 CallFrame* callFrame = ARG_callFrame;
5319 JSValue* result = jsNumber(ARG_globalData, -src->toNumber(callFrame));
5320 CHECK_FOR_EXCEPTION_AT_END();
5321 return result;
5322}
5323
5324JSValue* Interpreter::cti_op_resolve_base(CTI_ARGS)
5325{
5326 CTI_STACK_HACK();
5327
5328 return inlineResolveBase(ARG_callFrame, *ARG_id1, ARG_callFrame->scopeChain());
5329}
5330
5331JSValue* Interpreter::cti_op_resolve_skip(CTI_ARGS)
5332{
5333 CTI_STACK_HACK();
5334
5335 CallFrame* callFrame = ARG_callFrame;
5336 ScopeChainNode* scopeChain = callFrame->scopeChain();
5337
5338 int skip = ARG_int2;
5339
5340 ScopeChainIterator iter = scopeChain->begin();
5341 ScopeChainIterator end = scopeChain->end();
5342 ASSERT(iter != end);
5343 while (skip--) {
5344 ++iter;
5345 ASSERT(iter != end);
5346 }
5347 Identifier& ident = *ARG_id1;
5348 do {
5349 JSObject* o = *iter;
5350 PropertySlot slot(o);
5351 if (o->getPropertySlot(callFrame, ident, slot)) {
5352 JSValue* result = slot.getValue(callFrame, ident);
5353 CHECK_FOR_EXCEPTION_AT_END();
5354 return result;
5355 }
5356 } while (++iter != end);
5357
5358 CodeBlock* codeBlock = callFrame->codeBlock();
5359 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
5360 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
5361 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock);
5362 VM_THROW_EXCEPTION();
5363}
5364
5365JSValue* Interpreter::cti_op_resolve_global(CTI_ARGS)
5366{
5367 CTI_STACK_HACK();
5368
5369 CallFrame* callFrame = ARG_callFrame;
5370 JSGlobalObject* globalObject = asGlobalObject(ARG_src1);
5371 Identifier& ident = *ARG_id2;
5372 Instruction* vPC = ARG_instr3;
5373 ASSERT(globalObject->isGlobalObject());
5374
5375 PropertySlot slot(globalObject);
5376 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
5377 JSValue* result = slot.getValue(callFrame, ident);
5378 if (slot.isCacheable()) {
5379 if (vPC[4].u.structure)
5380 vPC[4].u.structure->deref();
5381 globalObject->structure()->ref();
5382 vPC[4] = globalObject->structure();
5383 vPC[5] = slot.cachedOffset();
5384 return result;
5385 }
5386
5387 CHECK_FOR_EXCEPTION_AT_END();
5388 return result;
5389 }
5390
5391 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, vPC, callFrame->codeBlock());
5392 VM_THROW_EXCEPTION();
5393}
5394
5395JSValue* Interpreter::cti_op_div(CTI_ARGS)
5396{
5397 CTI_STACK_HACK();
5398
5399 JSValue* src1 = ARG_src1;
5400 JSValue* src2 = ARG_src2;
5401
5402 double left;
5403 double right;
5404 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
5405 return jsNumber(ARG_globalData, left / right);
5406
5407 CallFrame* callFrame = ARG_callFrame;
5408 JSValue* result = jsNumber(ARG_globalData, src1->toNumber(callFrame) / src2->toNumber(callFrame));
5409 CHECK_FOR_EXCEPTION_AT_END();
5410 return result;
5411}
5412
5413JSValue* Interpreter::cti_op_pre_dec(CTI_ARGS)
5414{
5415 CTI_STACK_HACK();
5416
5417 JSValue* v = ARG_src1;
5418
5419 CallFrame* callFrame = ARG_callFrame;
5420 JSValue* result = jsNumber(ARG_globalData, v->toNumber(callFrame) - 1);
5421 CHECK_FOR_EXCEPTION_AT_END();
5422 return result;
5423}
5424
5425int Interpreter::cti_op_jless(CTI_ARGS)
5426{
5427 CTI_STACK_HACK();
5428
5429 JSValue* src1 = ARG_src1;
5430 JSValue* src2 = ARG_src2;
5431 CallFrame* callFrame = ARG_callFrame;
5432
5433 bool result = jsLess(callFrame, src1, src2);
5434 CHECK_FOR_EXCEPTION_AT_END();
5435 return result;
5436}
5437
5438JSValue* Interpreter::cti_op_not(CTI_ARGS)
5439{
5440 CTI_STACK_HACK();
5441
5442 JSValue* src = ARG_src1;
5443
5444 CallFrame* callFrame = ARG_callFrame;
5445
5446 JSValue* result = jsBoolean(!src->toBoolean(callFrame));
5447 CHECK_FOR_EXCEPTION_AT_END();
5448 return result;
5449}
5450
5451int SFX_CALL Interpreter::cti_op_jtrue(CTI_ARGS)
5452{
5453 CTI_STACK_HACK();
5454
5455 JSValue* src1 = ARG_src1;
5456
5457 CallFrame* callFrame = ARG_callFrame;
5458
5459 bool result = src1->toBoolean(callFrame);
5460 CHECK_FOR_EXCEPTION_AT_END();
5461 return result;
5462}
5463
5464VoidPtrPair Interpreter::cti_op_post_inc(CTI_ARGS)
5465{
5466 CTI_STACK_HACK();
5467
5468 JSValue* v = ARG_src1;
5469
5470 CallFrame* callFrame = ARG_callFrame;
5471
5472 JSValue* number = v->toJSNumber(callFrame);
5473 CHECK_FOR_EXCEPTION_AT_END();
5474
5475 VoidPtrPairValue pair = {{ asPointer(number), asPointer(jsNumber(ARG_globalData, number->uncheckedGetNumber() + 1)) }};
5476 return pair.i;
5477}
5478
5479JSValue* Interpreter::cti_op_eq(CTI_ARGS)
5480{
5481 CTI_STACK_HACK();
5482
5483 JSValue* src1 = ARG_src1;
5484 JSValue* src2 = ARG_src2;
5485
5486 CallFrame* callFrame = ARG_callFrame;
5487
5488 ASSERT(!JSImmediate::areBothImmediateNumbers(src1, src2));
5489 JSValue* result = jsBoolean(equalSlowCaseInline(callFrame, src1, src2));
5490 CHECK_FOR_EXCEPTION_AT_END();
5491 return result;
5492}
5493
5494JSValue* Interpreter::cti_op_lshift(CTI_ARGS)
5495{
5496 CTI_STACK_HACK();
5497
5498 JSValue* val = ARG_src1;
5499 JSValue* shift = ARG_src2;
5500
5501 int32_t left;
5502 uint32_t right;
5503 if (JSImmediate::areBothImmediateNumbers(val, shift))
5504 return jsNumber(ARG_globalData, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
5505 if (fastToInt32(val, left) && fastToUInt32(shift, right))
5506 return jsNumber(ARG_globalData, left << (right & 0x1f));
5507
5508 CallFrame* callFrame = ARG_callFrame;
5509 JSValue* result = jsNumber(ARG_globalData, (val->toInt32(callFrame)) << (shift->toUInt32(callFrame) & 0x1f));
5510 CHECK_FOR_EXCEPTION_AT_END();
5511 return result;
5512}
5513
5514JSValue* Interpreter::cti_op_bitand(CTI_ARGS)
5515{
5516 CTI_STACK_HACK();
5517
5518 JSValue* src1 = ARG_src1;
5519 JSValue* src2 = ARG_src2;
5520
5521 int32_t left;
5522 int32_t right;
5523 if (fastToInt32(src1, left) && fastToInt32(src2, right))
5524 return jsNumber(ARG_globalData, left & right);
5525
5526 CallFrame* callFrame = ARG_callFrame;
5527 JSValue* result = jsNumber(ARG_globalData, src1->toInt32(callFrame) & src2->toInt32(callFrame));
5528 CHECK_FOR_EXCEPTION_AT_END();
5529 return result;
5530}
5531
5532JSValue* Interpreter::cti_op_rshift(CTI_ARGS)
5533{
5534 CTI_STACK_HACK();
5535
5536 JSValue* val = ARG_src1;
5537 JSValue* shift = ARG_src2;
5538
5539 int32_t left;
5540 uint32_t right;
5541 if (JSImmediate::areBothImmediateNumbers(val, shift))
5542 return JSImmediate::rightShiftImmediateNumbers(val, shift);
5543 if (fastToInt32(val, left) && fastToUInt32(shift, right))
5544 return jsNumber(ARG_globalData, left >> (right & 0x1f));
5545
5546 CallFrame* callFrame = ARG_callFrame;
5547 JSValue* result = jsNumber(ARG_globalData, (val->toInt32(callFrame)) >> (shift->toUInt32(callFrame) & 0x1f));
5548 CHECK_FOR_EXCEPTION_AT_END();
5549 return result;
5550}
5551
5552JSValue* Interpreter::cti_op_bitnot(CTI_ARGS)
5553{
5554 CTI_STACK_HACK();
5555
5556 JSValue* src = ARG_src1;
5557
5558 int value;
5559 if (fastToInt32(src, value))
5560 return jsNumber(ARG_globalData, ~value);
5561
5562 CallFrame* callFrame = ARG_callFrame;
5563 JSValue* result = jsNumber(ARG_globalData, ~src->toInt32(callFrame));
5564 CHECK_FOR_EXCEPTION_AT_END();
5565 return result;
5566}
5567
5568VoidPtrPair Interpreter::cti_op_resolve_with_base(CTI_ARGS)
5569{
5570 CTI_STACK_HACK();
5571
5572 CallFrame* callFrame = ARG_callFrame;
5573 ScopeChainNode* scopeChain = callFrame->scopeChain();
5574
5575 ScopeChainIterator iter = scopeChain->begin();
5576 ScopeChainIterator end = scopeChain->end();
5577
5578 // FIXME: add scopeDepthIsZero optimization
5579
5580 ASSERT(iter != end);
5581
5582 Identifier& ident = *ARG_id1;
5583 JSObject* base;
5584 do {
5585 base = *iter;
5586 PropertySlot slot(base);
5587 if (base->getPropertySlot(callFrame, ident, slot)) {
5588 JSValue* result = slot.getValue(callFrame, ident);
5589 CHECK_FOR_EXCEPTION_AT_END();
5590
5591 VoidPtrPairValue pair = {{ base, asPointer(result) }};
5592 return pair.i;
5593 }
5594 ++iter;
5595 } while (iter != end);
5596
5597 CodeBlock* codeBlock = callFrame->codeBlock();
5598 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
5599 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
5600 ARG_globalData->exception = createUndefinedVariableError(callFrame, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock);
5601 VM_THROW_EXCEPTION_2();
5602}
5603
5604JSObject* Interpreter::cti_op_new_func_exp(CTI_ARGS)
5605{
5606 CTI_STACK_HACK();
5607
5608 return ARG_funcexp1->makeFunction(ARG_callFrame, ARG_callFrame->scopeChain());
5609}
5610
5611JSValue* Interpreter::cti_op_mod(CTI_ARGS)
5612{
5613 CTI_STACK_HACK();
5614
5615 JSValue* dividendValue = ARG_src1;
5616 JSValue* divisorValue = ARG_src2;
5617
5618 CallFrame* callFrame = ARG_callFrame;
5619 double d = dividendValue->toNumber(callFrame);
5620 JSValue* result = jsNumber(ARG_globalData, fmod(d, divisorValue->toNumber(callFrame)));
5621 CHECK_FOR_EXCEPTION_AT_END();
5622 return result;
5623}
5624
5625JSValue* Interpreter::cti_op_less(CTI_ARGS)
5626{
5627 CTI_STACK_HACK();
5628
5629 CallFrame* callFrame = ARG_callFrame;
5630 JSValue* result = jsBoolean(jsLess(callFrame, ARG_src1, ARG_src2));
5631 CHECK_FOR_EXCEPTION_AT_END();
5632 return result;
5633}
5634
5635JSValue* Interpreter::cti_op_neq(CTI_ARGS)
5636{
5637 CTI_STACK_HACK();
5638
5639 JSValue* src1 = ARG_src1;
5640 JSValue* src2 = ARG_src2;
5641
5642 ASSERT(!JSImmediate::areBothImmediateNumbers(src1, src2));
5643
5644 CallFrame* callFrame = ARG_callFrame;
5645 JSValue* result = jsBoolean(!equalSlowCaseInline(callFrame, src1, src2));
5646 CHECK_FOR_EXCEPTION_AT_END();
5647 return result;
5648}
5649
5650VoidPtrPair Interpreter::cti_op_post_dec(CTI_ARGS)
5651{
5652 CTI_STACK_HACK();
5653
5654 JSValue* v = ARG_src1;
5655
5656 CallFrame* callFrame = ARG_callFrame;
5657
5658 JSValue* number = v->toJSNumber(callFrame);
5659 CHECK_FOR_EXCEPTION_AT_END();
5660
5661 VoidPtrPairValue pair = {{ asPointer(number), asPointer(jsNumber(ARG_globalData, number->uncheckedGetNumber() - 1)) }};
5662 return pair.i;
5663}
5664
5665JSValue* Interpreter::cti_op_urshift(CTI_ARGS)
5666{
5667 CTI_STACK_HACK();
5668
5669 JSValue* val = ARG_src1;
5670 JSValue* shift = ARG_src2;
5671
5672 CallFrame* callFrame = ARG_callFrame;
5673
5674 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
5675 return JSImmediate::rightShiftImmediateNumbers(val, shift);
5676 else {
5677 JSValue* result = jsNumber(ARG_globalData, (val->toUInt32(callFrame)) >> (shift->toUInt32(callFrame) & 0x1f));
5678 CHECK_FOR_EXCEPTION_AT_END();
5679 return result;
5680 }
5681}
5682
5683JSValue* Interpreter::cti_op_bitxor(CTI_ARGS)
5684{
5685 CTI_STACK_HACK();
5686
5687 JSValue* src1 = ARG_src1;
5688 JSValue* src2 = ARG_src2;
5689
5690 CallFrame* callFrame = ARG_callFrame;
5691
5692 JSValue* result = jsNumber(ARG_globalData, src1->toInt32(callFrame) ^ src2->toInt32(callFrame));
5693 CHECK_FOR_EXCEPTION_AT_END();
5694 return result;
5695}
5696
5697JSObject* Interpreter::cti_op_new_regexp(CTI_ARGS)
5698{
5699 CTI_STACK_HACK();
5700
5701 return new (ARG_globalData) RegExpObject(ARG_callFrame->lexicalGlobalObject()->regExpStructure(), ARG_regexp1);
5702}
5703
5704JSValue* Interpreter::cti_op_bitor(CTI_ARGS)
5705{
5706 CTI_STACK_HACK();
5707
5708 JSValue* src1 = ARG_src1;
5709 JSValue* src2 = ARG_src2;
5710
5711 CallFrame* callFrame = ARG_callFrame;
5712
5713 JSValue* result = jsNumber(ARG_globalData, src1->toInt32(callFrame) | src2->toInt32(callFrame));
5714 CHECK_FOR_EXCEPTION_AT_END();
5715 return result;
5716}
5717
5718JSValue* Interpreter::cti_op_call_eval(CTI_ARGS)
5719{
5720 CTI_STACK_HACK();
5721
5722 CallFrame* callFrame = ARG_callFrame;
5723 RegisterFile* registerFile = ARG_registerFile;
5724
5725 Interpreter* interpreter = ARG_globalData->interpreter;
5726
5727 JSValue* funcVal = ARG_src1;
5728 int registerOffset = ARG_int2;
5729 int argCount = ARG_int3;
5730
5731 Register* newCallFrame = callFrame->registers() + registerOffset;
5732 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
5733 JSValue* thisValue = argv[0].jsValue(callFrame);
5734 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();
5735
5736 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
5737 JSValue* exceptionValue = noValue();
5738 JSValue* result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
5739 if (UNLIKELY(exceptionValue != noValue())) {
5740 ARG_globalData->exception = exceptionValue;
5741 VM_THROW_EXCEPTION_AT_END();
5742 }
5743 return result;
5744 }
5745
5746 return JSImmediate::impossibleValue();
5747}
5748
5749JSValue* Interpreter::cti_op_throw(CTI_ARGS)
5750{
5751 CTI_STACK_HACK();
5752
5753 CallFrame* callFrame = ARG_callFrame;
5754 CodeBlock* codeBlock = callFrame->codeBlock();
5755
5756 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
5757 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
5758
5759 JSValue* exceptionValue = ARG_src1;
5760 ASSERT(exceptionValue);
5761
5762 Instruction* handlerVPC = ARG_globalData->interpreter->throwException(callFrame, exceptionValue, codeBlock->instructions.begin() + vPCIndex, true);
5763
5764 if (!handlerVPC) {
5765 *ARG_exception = exceptionValue;
5766 return JSImmediate::nullImmediate();
5767 }
5768
5769 ARG_setCallFrame(callFrame);
5770 void* catchRoutine = callFrame->codeBlock()->nativeExceptionCodeForHandlerVPC(handlerVPC);
5771 ASSERT(catchRoutine);
5772 CTI_SET_RETURN_ADDRESS(catchRoutine);
5773 return exceptionValue;
5774}
5775
5776JSPropertyNameIterator* Interpreter::cti_op_get_pnames(CTI_ARGS)
5777{
5778 CTI_STACK_HACK();
5779
5780 return JSPropertyNameIterator::create(ARG_callFrame, ARG_src1);
5781}
5782
5783JSValue* Interpreter::cti_op_next_pname(CTI_ARGS)
5784{
5785 CTI_STACK_HACK();
5786
5787 JSPropertyNameIterator* it = ARG_pni1;
5788 JSValue* temp = it->next(ARG_callFrame);
5789 if (!temp)
5790 it->invalidate();
5791 return temp;
5792}
5793
5794void Interpreter::cti_op_push_scope(CTI_ARGS)
5795{
5796 CTI_STACK_HACK();
5797
5798 JSObject* o = ARG_src1->toObject(ARG_callFrame);
5799 CHECK_FOR_EXCEPTION_VOID();
5800 ARG_callFrame->setScopeChain(ARG_callFrame->scopeChain()->push(o));
5801}
5802
5803void Interpreter::cti_op_pop_scope(CTI_ARGS)
5804{
5805 CTI_STACK_HACK();
5806
5807 ARG_callFrame->setScopeChain(ARG_callFrame->scopeChain()->pop());
5808}
5809
5810JSValue* Interpreter::cti_op_typeof(CTI_ARGS)
5811{
5812 CTI_STACK_HACK();
5813
5814 return jsTypeStringForValue(ARG_callFrame, ARG_src1);
5815}
5816
5817JSValue* Interpreter::cti_op_is_undefined(CTI_ARGS)
5818{
5819 CTI_STACK_HACK();
5820
5821 JSValue* v = ARG_src1;
5822 return jsBoolean(JSImmediate::isImmediate(v) ? v->isUndefined() : v->asCell()->structure()->typeInfo().masqueradesAsUndefined());
5823}
5824
5825JSValue* Interpreter::cti_op_is_boolean(CTI_ARGS)
5826{
5827 CTI_STACK_HACK();
5828
5829 return jsBoolean(ARG_src1->isBoolean());
5830}
5831
5832JSValue* Interpreter::cti_op_is_number(CTI_ARGS)
5833{
5834 CTI_STACK_HACK();
5835
5836 return jsBoolean(ARG_src1->isNumber());
5837}
5838
5839JSValue* Interpreter::cti_op_is_string(CTI_ARGS)
5840{
5841 CTI_STACK_HACK();
5842
5843 return jsBoolean(ARG_globalData->interpreter->isJSString(ARG_src1));
5844}
5845
5846JSValue* Interpreter::cti_op_is_object(CTI_ARGS)
5847{
5848 CTI_STACK_HACK();
5849
5850 return jsBoolean(jsIsObjectType(ARG_src1));
5851}
5852
5853JSValue* Interpreter::cti_op_is_function(CTI_ARGS)
5854{
5855 CTI_STACK_HACK();
5856
5857 return jsBoolean(jsIsFunctionType(ARG_src1));
5858}
5859
5860JSValue* Interpreter::cti_op_stricteq(CTI_ARGS)
5861{
5862 CTI_STACK_HACK();
5863
5864 JSValue* src1 = ARG_src1;
5865 JSValue* src2 = ARG_src2;
5866
5867 // handled inline as fast cases
5868 ASSERT(!JSImmediate::areBothImmediate(src1, src2));
5869 ASSERT(!(JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate())));
5870
5871 return jsBoolean(strictEqualSlowCaseInline(src1, src2));
5872}
5873
5874JSValue* Interpreter::cti_op_nstricteq(CTI_ARGS)
5875{
5876 CTI_STACK_HACK();
5877
5878 JSValue* src1 = ARG_src1;
5879 JSValue* src2 = ARG_src2;
5880
5881 // handled inline as fast cases
5882 ASSERT(!JSImmediate::areBothImmediate(src1, src2));
5883 ASSERT(!(JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate())));
5884
5885 return jsBoolean(!strictEqualSlowCaseInline(src1, src2));
5886}
5887
5888JSValue* Interpreter::cti_op_to_jsnumber(CTI_ARGS)
5889{
5890 CTI_STACK_HACK();
5891
5892 JSValue* src = ARG_src1;
5893 CallFrame* callFrame = ARG_callFrame;
5894
5895 JSValue* result = src->toJSNumber(callFrame);
5896 CHECK_FOR_EXCEPTION_AT_END();
5897 return result;
5898}
5899
5900JSValue* Interpreter::cti_op_in(CTI_ARGS)
5901{
5902 CTI_STACK_HACK();
5903
5904 CallFrame* callFrame = ARG_callFrame;
5905 JSValue* baseVal = ARG_src2;
5906
5907 if (!baseVal->isObject()) {
5908 CallFrame* callFrame = ARG_callFrame;
5909 CodeBlock* codeBlock = callFrame->codeBlock();
5910 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
5911 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
5912 ARG_globalData->exception = createInvalidParamError(callFrame, "in", baseVal, codeBlock->instructions.begin() + vPCIndex, codeBlock);
5913 VM_THROW_EXCEPTION();
5914 }
5915
5916 JSValue* propName = ARG_src1;
5917 JSObject* baseObj = asObject(baseVal);
5918
5919 uint32_t i;
5920 if (propName->getUInt32(i))
5921 return jsBoolean(baseObj->hasProperty(callFrame, i));
5922
5923 Identifier property(callFrame, propName->toString(callFrame));
5924 CHECK_FOR_EXCEPTION();
5925 return jsBoolean(baseObj->hasProperty(callFrame, property));
5926}
5927
5928JSObject* Interpreter::cti_op_push_new_scope(CTI_ARGS)
5929{
5930 CTI_STACK_HACK();
5931
5932 JSObject* scope = new (ARG_globalData) JSStaticScopeObject(ARG_callFrame, *ARG_id1, ARG_src2, DontDelete);
5933
5934 CallFrame* callFrame = ARG_callFrame;
5935 callFrame->setScopeChain(callFrame->scopeChain()->push(scope));
5936 return scope;
5937}
5938
5939void Interpreter::cti_op_jmp_scopes(CTI_ARGS)
5940{
5941 CTI_STACK_HACK();
5942
5943 unsigned count = ARG_int1;
5944 CallFrame* callFrame = ARG_callFrame;
5945
5946 ScopeChainNode* tmp = callFrame->scopeChain();
5947 while (count--)
5948 tmp = tmp->pop();
5949 callFrame->setScopeChain(tmp);
5950}
5951
5952void Interpreter::cti_op_put_by_index(CTI_ARGS)
5953{
5954 CTI_STACK_HACK();
5955
5956 CallFrame* callFrame = ARG_callFrame;
5957 unsigned property = ARG_int2;
5958
5959 ARG_src1->put(callFrame, property, ARG_src3);
5960}
5961
5962void* Interpreter::cti_op_switch_imm(CTI_ARGS)
5963{
5964 CTI_STACK_HACK();
5965
5966 JSValue* scrutinee = ARG_src1;
5967 unsigned tableIndex = ARG_int2;
5968 CallFrame* callFrame = ARG_callFrame;
5969 CodeBlock* codeBlock = callFrame->codeBlock();
5970
5971 if (JSImmediate::isNumber(scrutinee)) {
5972 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
5973 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(value);
5974 }
5975
5976 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault;
5977}
5978
5979void* Interpreter::cti_op_switch_char(CTI_ARGS)
5980{
5981 CTI_STACK_HACK();
5982
5983 JSValue* scrutinee = ARG_src1;
5984 unsigned tableIndex = ARG_int2;
5985 CallFrame* callFrame = ARG_callFrame;
5986 CodeBlock* codeBlock = callFrame->codeBlock();
5987
5988 void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault;
5989
5990 if (scrutinee->isString()) {
5991 UString::Rep* value = asString(scrutinee)->value().rep();
5992 if (value->size() == 1)
5993 result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->data()[0]);
5994 }
5995
5996 return result;
5997}
5998
5999void* Interpreter::cti_op_switch_string(CTI_ARGS)
6000{
6001 CTI_STACK_HACK();
6002
6003 JSValue* scrutinee = ARG_src1;
6004 unsigned tableIndex = ARG_int2;
6005 CallFrame* callFrame = ARG_callFrame;
6006 CodeBlock* codeBlock = callFrame->codeBlock();
6007
6008 void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault;
6009
6010 if (scrutinee->isString()) {
6011 UString::Rep* value = asString(scrutinee)->value().rep();
6012 result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value);
6013 }
6014
6015 return result;
6016}
6017
6018JSValue* Interpreter::cti_op_del_by_val(CTI_ARGS)
6019{
6020 CTI_STACK_HACK();
6021
6022 CallFrame* callFrame = ARG_callFrame;
6023
6024 JSValue* baseValue = ARG_src1;
6025 JSObject* baseObj = baseValue->toObject(callFrame); // may throw
6026
6027 JSValue* subscript = ARG_src2;
6028 JSValue* result;
6029 uint32_t i;
6030 if (subscript->getUInt32(i))
6031 result = jsBoolean(baseObj->deleteProperty(callFrame, i));
6032 else {
6033 CHECK_FOR_EXCEPTION();
6034 Identifier property(callFrame, subscript->toString(callFrame));
6035 CHECK_FOR_EXCEPTION();
6036 result = jsBoolean(baseObj->deleteProperty(callFrame, property));
6037 }
6038
6039 CHECK_FOR_EXCEPTION_AT_END();
6040 return result;
6041}
6042
6043void Interpreter::cti_op_put_getter(CTI_ARGS)
6044{
6045 CTI_STACK_HACK();
6046
6047 CallFrame* callFrame = ARG_callFrame;
6048
6049 ASSERT(ARG_src1->isObject());
6050 JSObject* baseObj = asObject(ARG_src1);
6051 ASSERT(ARG_src3->isObject());
6052 baseObj->defineGetter(callFrame, *ARG_id2, asObject(ARG_src3));
6053}
6054
6055void Interpreter::cti_op_put_setter(CTI_ARGS)
6056{
6057 CTI_STACK_HACK();
6058
6059 CallFrame* callFrame = ARG_callFrame;
6060
6061 ASSERT(ARG_src1->isObject());
6062 JSObject* baseObj = asObject(ARG_src1);
6063 ASSERT(ARG_src3->isObject());
6064 baseObj->defineSetter(callFrame, *ARG_id2, asObject(ARG_src3));
6065}
6066
6067JSObject* Interpreter::cti_op_new_error(CTI_ARGS)
6068{
6069 CTI_STACK_HACK();
6070
6071 CallFrame* callFrame = ARG_callFrame;
6072 CodeBlock* codeBlock = callFrame->codeBlock();
6073 unsigned type = ARG_int1;
6074 JSValue* message = ARG_src2;
6075 unsigned lineNumber = ARG_int3;
6076
6077 return Error::create(callFrame, static_cast<ErrorType>(type), message->toString(callFrame), lineNumber, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->sourceURL());
6078}
6079
6080void Interpreter::cti_op_debug(CTI_ARGS)
6081{
6082 CTI_STACK_HACK();
6083
6084 CallFrame* callFrame = ARG_callFrame;
6085
6086 int debugHookID = ARG_int1;
6087 int firstLine = ARG_int2;
6088 int lastLine = ARG_int3;
6089
6090 ARG_globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
6091}
6092
6093JSValue* Interpreter::cti_vm_throw(CTI_ARGS)
6094{
6095 CTI_STACK_HACK();
6096
6097 CallFrame* callFrame = ARG_callFrame;
6098 CodeBlock* codeBlock = callFrame->codeBlock();
6099 JSGlobalData* globalData = ARG_globalData;
6100
6101 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(globalData->exceptionLocation));
6102 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(globalData->exceptionLocation);
6103
6104 JSValue* exceptionValue = globalData->exception;
6105 ASSERT(exceptionValue);
6106 globalData->exception = noValue();
6107
6108 Instruction* handlerVPC = globalData->interpreter->throwException(callFrame, exceptionValue, codeBlock->instructions.begin() + vPCIndex, false);
6109
6110 if (!handlerVPC) {
6111 *ARG_exception = exceptionValue;
6112 return JSImmediate::nullImmediate();
6113 }
6114
6115 ARG_setCallFrame(callFrame);
6116 void* catchRoutine = callFrame->codeBlock()->nativeExceptionCodeForHandlerVPC(handlerVPC);
6117 ASSERT(catchRoutine);
6118 CTI_SET_RETURN_ADDRESS(catchRoutine);
6119 return exceptionValue;
6120}
6121
6122#undef CTI_RETURN_ADDRESS
6123#undef CTI_SET_RETURN_ADDRESS
6124#undef CTI_STACK_HACK
6125#undef CHECK_FOR_EXCEPTION
6126#undef CHECK_FOR_EXCEPTION_AT_END
6127#undef CHECK_FOR_EXCEPTION_VOID
6128#undef VM_THROW_EXCEPTION
6129#undef VM_THROW_EXCEPTION_2
6130#undef VM_THROW_EXCEPTION_AT_END
6131
6132#endif // ENABLE(JIT)
6133
6134} // namespace JSC
Note: See TracBrowser for help on using the repository browser.