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

Last change on this file since 38514 was 38512, checked in by [email protected], 17 years ago

2008-11-17 Geoffrey Garen <[email protected]>

Reviewed by Sam Weinig.


Moved VM/Machine.cpp => interpreter/Interpreter.cpp.

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