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

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

Bug 23128: get/put_by_val need to respecialise in the face of ByteArray
<https://bugs.webkit.org/show_bug.cgi?id=23128>

Reviewed by Anders Carlsson.

Fairly simple patch, add specialised versions of cti_op_get/put_by_val
that assume ByteArray, thus avoiding a few branches in the case of bytearray
manipulation.

No effect on SunSpider. 15% win on the original testcase.

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