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

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

2008-10-20 Cameron Zwarich <[email protected]>

Rubber-stamped by Sam Weinig.

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