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

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

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

Reviewed by Darin Adler.

Bug 21123: using "arguments" in a function should not force creation of an activation object
<https://bugs.webkit.org/show_bug.cgi?id=21123>

Make the 'arguments' object not require a JSActivation. We store the
'arguments' object in the OptionalCalleeArguments call frame slot. We
need to be able to get the original 'arguments' object to tear it off
when returning from a function, but 'arguments' may be assigned to in a
number of ways.

Therefore, we use the OptionalCalleeArguments slot when we want to get
the original activation or we know that 'arguments' was not assigned a
different value. When 'arguments' may have been assigned a new value,
we use a new local variable that is initialized with 'arguments'. Since
a function parameter named 'arguments' may overwrite the value of
'arguments', we also need to be careful to look up 'arguments' in the
symbol table, so we get the parameter named 'arguments' instead of the
local variable that we have added for holding the 'arguments' object.

This is a 19.1% win on the V8 Raytrace benchmark using the SunSpider
harness, and a 20.7% win using the V8 harness. This amounts to a 6.5%
total speedup on the V8 benchmark suite using the V8 harness.

JavaScriptCore:

  • VM/CTI.cpp: (JSC::CTI::privateCompileMainPass):
  • VM/CodeBlock.h:
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::CodeGenerator):
  • VM/Machine.cpp: (JSC::Machine::unwindCallFrame): (JSC::Machine::privateExecute): (JSC::Machine::retrieveArguments): (JSC::Machine::cti_op_init_arguments): (JSC::Machine::cti_op_ret_activation_arguments):
  • VM/Machine.h:
  • VM/RegisterFile.h: (JSC::RegisterFile::):
  • kjs/Arguments.cpp: (JSC::Arguments::mark): (JSC::Arguments::fillArgList): (JSC::Arguments::getOwnPropertySlot): (JSC::Arguments::put):
  • kjs/Arguments.h: (JSC::Arguments::setRegisters): (JSC::Arguments::init): (JSC::Arguments::Arguments): (JSC::Arguments::copyRegisters): (JSC::JSActivation::copyRegisters):
  • kjs/JSActivation.cpp: (JSC::JSActivation::argumentsGetter):
  • kjs/JSActivation.h: (JSC::JSActivation::JSActivationData::JSActivationData):
  • kjs/grammar.y:
  • kjs/nodes.h: (JSC::ScopeNode::setUsesArguments):
  • masm/X86Assembler.h: (JSC::X86Assembler::): (JSC::X86Assembler::orl_mr):

LayoutTests:

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