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

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

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

Reviewed by Sam Weinig.



1) Make JSValue::toBoolean nonvirtual and completely inline by
making use of the StructureID type field.


2) Make JSValue::toBoolean not take an ExecState; doesn't need it.


3) Make op_not, op_loop_if_true and op_jtrue not read the
ExecState (toBoolean doesn't need it any more) and not check
exceptions (toBoolean can't throw).

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