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

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

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

Reviewed by Geoff Garen.

Bug 21541: Move RegisterFile growth check to callee
<https://bugs.webkit.org/show_bug.cgi?id=21541>

Move the RegisterFile growth check to the callee in the common case,
where some of the information is known statically at JIT time. There is
still a check in the caller in the case where the caller provides too
few arguments.

This is a 2.1% speedup on the V8 benchmark, including a 5.1% speedup on
the Richards benchmark, a 4.1% speedup on the DeltaBlue benchmark, and a
1.4% speedup on the Earley-Boyer benchmark. It is also a 0.5% speedup on
SunSpider.

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