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

Last change on this file since 38249 was 38249, checked in by Darin Adler, 17 years ago

2008-11-09 Darin Adler <Darin Adler>

Reviewed by Tim Hatcher.

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