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

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

JavaScriptCore:

2008-09-29 Geoffrey Garen <[email protected]>

Reviewed by Cameron Zwarich.


Store the callee ScopeChain, not the caller ScopeChain, in the call frame
header. Nix the "scopeChain" local variable and ExecState::m_scopeChain, and
access the callee ScopeChain through the call frame header instead.

Profit: call + return are simpler, because they don't have to update the
"scopeChain" local variable, or ExecState::m_scopeChain.


Because CTI keeps "r" in a register, reading the callee ScopeChain relative
to "r" can be very fast, in any cases we care to optimize.

0% speedup on empty function call benchmark. (5.5% speedup in bytecode.)
0% speedup on SunSpider. (7.5% speedup on controlflow-recursive.)
2% speedup on SunSpider --v8.
2% speedup on v8 benchmark.

  • VM/CTI.cpp: Changed scope chain access to read the scope chain from the call frame header. Sped up op_ret by changing it not to fuss with the "scopeChain" local variable or ExecState::m_scopeChain.
  • VM/CTI.h: Updated CTI trampolines not to take a ScopeChainNode* argument, since that's stored in the call frame header now.
  • VM/Machine.cpp: Access "scopeChain" and "codeBlock" through new helper functions that read from the call frame header. Updated functions operating on ExecState::m_callFrame to account for / take advantage of the fact that Exec:m_callFrame is now never NULL.


Fixed a bug in op_construct, where it would use the caller's default
object prototype, rather than the callee's, when constructing a new object.

  • VM/Machine.h: Made some helper functions available. Removed ScopeChainNode* arguments to a lot of functions, since the ScopeChainNode* is now stored in the call frame header.
  • VM/RegisterFile.h: Renamed "CallerScopeChain" to "ScopeChain", since that's what it is now.
  • kjs/DebuggerCallFrame.cpp: Updated for change to ExecState signature.
  • kjs/ExecState.cpp:
  • kjs/ExecState.h: Nixed ExecState::m_callFrame, along with the unused isGlobalObject function.
  • kjs/JSGlobalObject.cpp:
  • kjs/JSGlobalObject.h: Gave the global object a fake call frame in which to store the global scope chain, since our code now assumes that it can always read the scope chain out of the ExecState's call frame.

JavaScriptGlue:

2008-09-29 Geoffrey Garen <[email protected]>

Not reviewed.


Forwarding headers to fix the build.

  • ForwardingHeaders/kjs/CTI.h: Copied from ForwardingHeaders/kjs/ExecState.h.
  • ForwardingHeaders/kjs/ustring.h: Copied from ForwardingHeaders/kjs/ExecState.h.
  • ForwardingHeaders/masm: Added.
  • ForwardingHeaders/masm/X86Assembler.h: Added.
  • ForwardingHeaders/profiler: Added.
  • ForwardingHeaders/profiler/Profiler.h: Added.

LayoutTests:

2008-09-29 Geoffrey Garen <[email protected]>

Reviewed by Cameron Zwarich.


Test case for which prototype is used when calling "new" across windows.

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