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

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

JavaScriptCore:

2008-10-08 Darin Adler <Darin Adler>

Reviewed by Cameron Zwarich.

Add CallFrame as a synonym for ExecState. Arguably, some day we should switch every
client over to the new name.

Use CallFrame* consistently rather than Register* or ExecState* in low-level code such
as Machine.cpp and CTI.cpp. Similarly, use callFrame rather than r as its name and use
accessor functions to get at things in the frame.

Eliminate other uses of ExecState* that aren't needed, replacing in some cases with
JSGlobalData* and in other cases eliminating them entirely.

  • API/JSObjectRef.cpp: (JSObjectMakeFunctionWithCallback): (JSObjectMakeFunction): (JSObjectHasProperty): (JSObjectGetProperty): (JSObjectSetProperty): (JSObjectDeleteProperty):
  • API/OpaqueJSString.cpp:
  • API/OpaqueJSString.h:
  • VM/CTI.cpp: (JSC::CTI::getConstant): (JSC::CTI::emitGetArg): (JSC::CTI::emitGetPutArg): (JSC::CTI::getConstantImmediateNumericArg): (JSC::CTI::printOpcodeOperandTypes): (JSC::CTI::CTI): (JSC::CTI::compileOpCall): (JSC::CTI::compileBinaryArithOp): (JSC::CTI::privateCompileMainPass): (JSC::CTI::privateCompile): (JSC::CTI::privateCompileGetByIdProto): (JSC::CTI::privateCompileGetByIdChain): (JSC::CTI::compileRegExp):
  • VM/CTI.h:
  • VM/CodeBlock.h:
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::emitEqualityOp): (JSC::CodeGenerator::emitLoad): (JSC::CodeGenerator::emitUnexpectedLoad): (JSC::CodeGenerator::emitConstruct):
  • VM/CodeGenerator.h:
  • VM/Machine.cpp: (JSC::jsLess): (JSC::jsLessEq): (JSC::jsAddSlowCase): (JSC::jsAdd): (JSC::jsTypeStringForValue): (JSC::Machine::resolve): (JSC::Machine::resolveSkip): (JSC::Machine::resolveGlobal): (JSC::inlineResolveBase): (JSC::Machine::resolveBase): (JSC::Machine::resolveBaseAndProperty): (JSC::Machine::resolveBaseAndFunc): (JSC::Machine::slideRegisterWindowForCall): (JSC::isNotObject): (JSC::Machine::callEval): (JSC::Machine::dumpCallFrame): (JSC::Machine::dumpRegisters): (JSC::Machine::unwindCallFrame): (JSC::Machine::throwException): (JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): (JSC::DynamicGlobalObjectScope::~DynamicGlobalObjectScope): (JSC::Machine::execute): (JSC::Machine::debug): (JSC::Machine::createExceptionScope): (JSC::cachePrototypeChain): (JSC::Machine::tryCachePutByID): (JSC::Machine::tryCacheGetByID): (JSC::Machine::privateExecute): (JSC::Machine::retrieveArguments): (JSC::Machine::retrieveCaller): (JSC::Machine::retrieveLastCaller): (JSC::Machine::findFunctionCallFrame): (JSC::Machine::getArgumentsData): (JSC::Machine::tryCTICachePutByID): (JSC::Machine::getCTIArrayLengthTrampoline): (JSC::Machine::getCTIStringLengthTrampoline): (JSC::Machine::tryCTICacheGetByID): (JSC::Machine::cti_op_convert_this): (JSC::Machine::cti_op_end): (JSC::Machine::cti_op_add): (JSC::Machine::cti_op_pre_inc): (JSC::Machine::cti_timeout_check): (JSC::Machine::cti_op_loop_if_less): (JSC::Machine::cti_op_loop_if_lesseq): (JSC::Machine::cti_op_new_object): (JSC::Machine::cti_op_put_by_id): (JSC::Machine::cti_op_put_by_id_second): (JSC::Machine::cti_op_put_by_id_generic): (JSC::Machine::cti_op_put_by_id_fail): (JSC::Machine::cti_op_get_by_id): (JSC::Machine::cti_op_get_by_id_second): (JSC::Machine::cti_op_get_by_id_generic): (JSC::Machine::cti_op_get_by_id_fail): (JSC::Machine::cti_op_instanceof): (JSC::Machine::cti_op_del_by_id): (JSC::Machine::cti_op_mul): (JSC::Machine::cti_op_new_func): (JSC::Machine::cti_op_call_JSFunction): (JSC::Machine::cti_vm_compile): (JSC::Machine::cti_op_push_activation): (JSC::Machine::cti_op_call_NotJSFunction): (JSC::Machine::cti_op_create_arguments): (JSC::Machine::cti_op_tear_off_activation): (JSC::Machine::cti_op_tear_off_arguments): (JSC::Machine::cti_op_ret_profiler): (JSC::Machine::cti_op_ret_scopeChain): (JSC::Machine::cti_op_new_array): (JSC::Machine::cti_op_resolve): (JSC::Machine::cti_op_construct_JSConstruct): (JSC::Machine::cti_op_construct_NotJSConstruct): (JSC::Machine::cti_op_get_by_val): (JSC::Machine::cti_op_resolve_func): (JSC::Machine::cti_op_sub): (JSC::Machine::cti_op_put_by_val): (JSC::Machine::cti_op_put_by_val_array): (JSC::Machine::cti_op_lesseq): (JSC::Machine::cti_op_loop_if_true): (JSC::Machine::cti_op_negate): (JSC::Machine::cti_op_resolve_base): (JSC::Machine::cti_op_resolve_skip): (JSC::Machine::cti_op_resolve_global): (JSC::Machine::cti_op_div): (JSC::Machine::cti_op_pre_dec): (JSC::Machine::cti_op_jless): (JSC::Machine::cti_op_not): (JSC::Machine::cti_op_jtrue): (JSC::Machine::cti_op_post_inc): (JSC::Machine::cti_op_eq): (JSC::Machine::cti_op_lshift): (JSC::Machine::cti_op_bitand): (JSC::Machine::cti_op_rshift): (JSC::Machine::cti_op_bitnot): (JSC::Machine::cti_op_resolve_with_base): (JSC::Machine::cti_op_new_func_exp): (JSC::Machine::cti_op_mod): (JSC::Machine::cti_op_less): (JSC::Machine::cti_op_neq): (JSC::Machine::cti_op_post_dec): (JSC::Machine::cti_op_urshift): (JSC::Machine::cti_op_bitxor): (JSC::Machine::cti_op_new_regexp): (JSC::Machine::cti_op_bitor): (JSC::Machine::cti_op_call_eval): (JSC::Machine::cti_op_throw): (JSC::Machine::cti_op_get_pnames): (JSC::Machine::cti_op_next_pname): (JSC::Machine::cti_op_push_scope): (JSC::Machine::cti_op_pop_scope): (JSC::Machine::cti_op_typeof): (JSC::Machine::cti_op_to_jsnumber): (JSC::Machine::cti_op_in): (JSC::Machine::cti_op_push_new_scope): (JSC::Machine::cti_op_jmp_scopes): (JSC::Machine::cti_op_put_by_index): (JSC::Machine::cti_op_switch_imm): (JSC::Machine::cti_op_switch_char): (JSC::Machine::cti_op_switch_string): (JSC::Machine::cti_op_del_by_val): (JSC::Machine::cti_op_put_getter): (JSC::Machine::cti_op_put_setter): (JSC::Machine::cti_op_new_error): (JSC::Machine::cti_op_debug): (JSC::Machine::cti_vm_throw):
  • VM/Machine.h:
  • VM/Register.h:
  • VM/RegisterFile.h:
  • kjs/Arguments.h:
  • kjs/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisObject): (JSC::DebuggerCallFrame::evaluate):
  • kjs/DebuggerCallFrame.h:
  • kjs/ExecState.cpp: (JSC::CallFrame::thisValue):
  • kjs/ExecState.h:
  • kjs/FunctionConstructor.cpp: (JSC::constructFunction):
  • kjs/JSActivation.cpp: (JSC::JSActivation::JSActivation): (JSC::JSActivation::argumentsGetter):
  • kjs/JSActivation.h:
  • kjs/JSGlobalObject.cpp: (JSC::JSGlobalObject::init):
  • kjs/JSGlobalObjectFunctions.cpp: (JSC::globalFuncEval):
  • kjs/JSVariableObject.h:
  • kjs/Parser.cpp: (JSC::Parser::parse):
  • kjs/RegExpConstructor.cpp: (JSC::constructRegExp):
  • kjs/RegExpPrototype.cpp: (JSC::regExpProtoFuncCompile):
  • kjs/Shell.cpp: (prettyPrintScript):
  • kjs/StringPrototype.cpp: (JSC::stringProtoFuncMatch): (JSC::stringProtoFuncSearch):
  • kjs/identifier.cpp: (JSC::Identifier::checkSameIdentifierTable):
  • kjs/interpreter.cpp: (JSC::Interpreter::checkSyntax): (JSC::Interpreter::evaluate):
  • kjs/nodes.cpp: (JSC::ThrowableExpressionData::emitThrowError): (JSC::RegExpNode::emitCode): (JSC::ArrayNode::emitCode): (JSC::InstanceOfNode::emitCode):
  • kjs/nodes.h:
  • kjs/regexp.cpp: (JSC::RegExp::RegExp): (JSC::RegExp::create):
  • kjs/regexp.h:
  • profiler/HeavyProfile.h:
  • profiler/Profile.h:
  • wrec/WREC.cpp:
  • wrec/WREC.h:

WebKit/mac:

2008-10-08 Darin Adler <Darin Adler>

Reviewed by Cameron Zwarich.

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