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

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

2008-10-30 Alp Toker <[email protected]>

Build fix attempt for older gcc on the trunk-mac-intel build bot
(error: initializer for scalar variable requires one element).

Modify the initializer syntax slightly with an additional comma.

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