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

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

JavaScriptCore:

2008-10-03 Maciej Stachowiak <[email protected]>

Reviewed by Cameron Zwarich.


I changed things so that functions which use "this" do a fast
version of toThisObject conversion if needed. Currently we miss
the conversion entirely, at least for primitive types. Using
TypeInfo and the primitive check, I made the fast case bail out
pretty fast.


This is inexplicably an 1.007x SunSpider speedup (and a wash on V8 benchmarks).


Also renamed some opcodes for clarity:


init ==> enter
init_activation ==> enter_with_activation


  • VM/CTI.cpp: (JSC::CTI::privateCompileMainPass): (JSC::CTI::privateCompileSlowCases):
  • VM/CodeBlock.cpp: (JSC::CodeBlock::dump):
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::generate): (JSC::CodeGenerator::CodeGenerator):
  • VM/Machine.cpp: (JSC::Machine::privateExecute): (JSC::Machine::cti_op_convert_this):
  • VM/Machine.h:
  • VM/Opcode.h:
  • kjs/JSActivation.cpp: (JSC::JSActivation::JSActivation):
  • kjs/JSActivation.h: (JSC::JSActivation::createStructureID):
  • kjs/JSCell.h: (JSC::JSValue::needsThisConversion):
  • kjs/JSGlobalData.cpp: (JSC::JSGlobalData::JSGlobalData):
  • kjs/JSGlobalData.h:
  • kjs/JSNumberCell.h: (JSC::JSNumberCell::createStructureID):
  • kjs/JSStaticScopeObject.h: (JSC::JSStaticScopeObject::JSStaticScopeObject): (JSC::JSStaticScopeObject::createStructureID):
  • kjs/JSString.h: (JSC::JSString::createStructureID):
  • kjs/JSValue.h:
  • kjs/TypeInfo.h: (JSC::TypeInfo::needsThisConversion):
  • kjs/nodes.h: (JSC::ScopeNode::usesThis):

WebCore:

2008-10-03 Maciej Stachowiak <[email protected]>

Reviewed by Cameron Zwarich.

Updated so toThis conversion for the split window is handled properly.

  • bindings/scripts/CodeGeneratorJS.pm:

LayoutTests:

2008-10-03 Maciej Stachowiak <[email protected]>

Reviewed by Cameron Zwarich.


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