source: webkit/trunk/JavaScriptCore/VM/Machine.cpp@ 37576

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

2008-10-13 Maciej Stachowiak <[email protected]>

Reviewed by Cameron Zwarich.


  • make Machine::getArgumentsData an Arguments method and inline it


~2% on v8 raytrace

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