]> git.saurik.com Git - apple/javascriptcore.git/blame - interpreter/Interpreter.cpp
JavaScriptCore-903.5.tar.gz
[apple/javascriptcore.git] / interpreter / Interpreter.cpp
CommitLineData
9dae56ea 1/*
fb8617cd 2 * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
9dae56ea
A
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
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 "Interpreter.h"
32
33#include "Arguments.h"
34#include "BatchedTransitionOptimizer.h"
ba379fdc
A
35#include "CallFrame.h"
36#include "CallFrameClosure.h"
9dae56ea 37#include "CodeBlock.h"
14957cd0 38#include "Heap.h"
ba379fdc 39#include "Debugger.h"
9dae56ea 40#include "DebuggerCallFrame.h"
14957cd0 41#include "ErrorInstance.h"
9dae56ea
A
42#include "EvalCodeCache.h"
43#include "ExceptionHelpers.h"
4e4e5a6f 44#include "GetterSetter.h"
9dae56ea
A
45#include "JSActivation.h"
46#include "JSArray.h"
47#include "JSByteArray.h"
48#include "JSFunction.h"
49#include "JSNotAnObject.h"
50#include "JSPropertyNameIterator.h"
ba379fdc 51#include "LiteralParser.h"
9dae56ea
A
52#include "JSStaticScopeObject.h"
53#include "JSString.h"
54#include "ObjectPrototype.h"
ba379fdc 55#include "Operations.h"
9dae56ea
A
56#include "Parser.h"
57#include "Profiler.h"
58#include "RegExpObject.h"
59#include "RegExpPrototype.h"
60#include "Register.h"
9dae56ea 61#include "SamplingTool.h"
14957cd0
A
62#include "StrictEvalActivation.h"
63#include "UStringConcatenate.h"
f9bf01c6 64#include <limits.h>
9dae56ea 65#include <stdio.h>
ba379fdc 66#include <wtf/Threading.h>
9dae56ea
A
67
68#if ENABLE(JIT)
69#include "JIT.h"
70#endif
71
4e4e5a6f
A
72#define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(COMPUTED_GOTO_INTERPRETER) && !defined(__llvm__))
73
9dae56ea
A
74using namespace std;
75
76namespace JSC {
9dae56ea
A
77
78// Returns the depth of the scope chain within a given call frame.
14957cd0 79static int depth(CodeBlock* codeBlock, ScopeChainNode* sc)
9dae56ea
A
80{
81 if (!codeBlock->needsFullScopeChain())
82 return 0;
14957cd0 83 return sc->localDepth();
9dae56ea
A
84}
85
4e4e5a6f
A
86#if ENABLE(INTERPRETER)
87static NEVER_INLINE JSValue concatenateStrings(ExecState* exec, Register* strings, unsigned count)
88{
89 return jsString(exec, strings, count);
90}
91
ba379fdc 92NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
9dae56ea 93{
f9bf01c6
A
94 int dst = vPC[1].u.operand;
95 int property = vPC[2].u.operand;
9dae56ea
A
96
97 ScopeChainNode* scopeChain = callFrame->scopeChain();
98 ScopeChainIterator iter = scopeChain->begin();
99 ScopeChainIterator end = scopeChain->end();
100 ASSERT(iter != end);
101
102 CodeBlock* codeBlock = callFrame->codeBlock();
103 Identifier& ident = codeBlock->identifier(property);
104 do {
14957cd0 105 JSObject* o = iter->get();
9dae56ea
A
106 PropertySlot slot(o);
107 if (o->getPropertySlot(callFrame, ident, slot)) {
ba379fdc 108 JSValue result = slot.getValue(callFrame, ident);
9dae56ea
A
109 exceptionValue = callFrame->globalData().exception;
110 if (exceptionValue)
111 return false;
14957cd0 112 callFrame->uncheckedR(dst) = JSValue(result);
9dae56ea
A
113 return true;
114 }
115 } while (++iter != end);
14957cd0 116 exceptionValue = createUndefinedVariableError(callFrame, ident);
9dae56ea
A
117 return false;
118}
119
ba379fdc 120NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
9dae56ea
A
121{
122 CodeBlock* codeBlock = callFrame->codeBlock();
123
f9bf01c6
A
124 int dst = vPC[1].u.operand;
125 int property = vPC[2].u.operand;
14957cd0 126 int skip = vPC[3].u.operand;
9dae56ea
A
127
128 ScopeChainNode* scopeChain = callFrame->scopeChain();
129 ScopeChainIterator iter = scopeChain->begin();
130 ScopeChainIterator end = scopeChain->end();
131 ASSERT(iter != end);
14957cd0
A
132 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
133 ASSERT(skip || !checkTopLevel);
134 if (checkTopLevel && skip--) {
135 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
136 ++iter;
137 }
9dae56ea
A
138 while (skip--) {
139 ++iter;
140 ASSERT(iter != end);
141 }
142 Identifier& ident = codeBlock->identifier(property);
143 do {
14957cd0 144 JSObject* o = iter->get();
9dae56ea
A
145 PropertySlot slot(o);
146 if (o->getPropertySlot(callFrame, ident, slot)) {
ba379fdc 147 JSValue result = slot.getValue(callFrame, ident);
9dae56ea
A
148 exceptionValue = callFrame->globalData().exception;
149 if (exceptionValue)
150 return false;
14957cd0
A
151 ASSERT(result);
152 callFrame->uncheckedR(dst) = JSValue(result);
9dae56ea
A
153 return true;
154 }
155 } while (++iter != end);
14957cd0 156 exceptionValue = createUndefinedVariableError(callFrame, ident);
9dae56ea
A
157 return false;
158}
159
ba379fdc 160NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
9dae56ea 161{
f9bf01c6 162 int dst = vPC[1].u.operand;
14957cd0
A
163 CodeBlock* codeBlock = callFrame->codeBlock();
164 JSGlobalObject* globalObject = codeBlock->globalObject();
9dae56ea 165 ASSERT(globalObject->isGlobalObject());
14957cd0
A
166 int property = vPC[2].u.operand;
167 Structure* structure = vPC[3].u.structure.get();
168 int offset = vPC[4].u.operand;
9dae56ea
A
169
170 if (structure == globalObject->structure()) {
14957cd0 171 callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
9dae56ea
A
172 return true;
173 }
174
9dae56ea
A
175 Identifier& ident = codeBlock->identifier(property);
176 PropertySlot slot(globalObject);
177 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
ba379fdc 178 JSValue result = slot.getValue(callFrame, ident);
4e4e5a6f 179 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
14957cd0
A
180 vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
181 vPC[4] = slot.cachedOffset();
182 callFrame->uncheckedR(dst) = JSValue(result);
9dae56ea
A
183 return true;
184 }
185
186 exceptionValue = callFrame->globalData().exception;
187 if (exceptionValue)
188 return false;
14957cd0 189 callFrame->uncheckedR(dst) = JSValue(result);
9dae56ea
A
190 return true;
191 }
192
14957cd0 193 exceptionValue = createUndefinedVariableError(callFrame, ident);
9dae56ea
A
194 return false;
195}
196
4e4e5a6f
A
197NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
198{
199 int dst = vPC[1].u.operand;
4e4e5a6f 200 CodeBlock* codeBlock = callFrame->codeBlock();
14957cd0
A
201 JSGlobalObject* globalObject = codeBlock->globalObject();
202 ASSERT(globalObject->isGlobalObject());
203 int property = vPC[2].u.operand;
204 Structure* structure = vPC[3].u.structure.get();
205 int offset = vPC[4].u.operand;
206 int skip = vPC[5].u.operand;
4e4e5a6f
A
207
208 ScopeChainNode* scopeChain = callFrame->scopeChain();
209 ScopeChainIterator iter = scopeChain->begin();
210 ScopeChainIterator end = scopeChain->end();
211 ASSERT(iter != end);
14957cd0
A
212 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
213 ASSERT(skip || !checkTopLevel);
214 if (checkTopLevel && skip--) {
215 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
216 ++iter;
217 }
4e4e5a6f 218 while (skip--) {
14957cd0 219 JSObject* o = iter->get();
4e4e5a6f
A
220 if (o->hasCustomProperties()) {
221 Identifier& ident = codeBlock->identifier(property);
222 do {
223 PropertySlot slot(o);
224 if (o->getPropertySlot(callFrame, ident, slot)) {
225 JSValue result = slot.getValue(callFrame, ident);
226 exceptionValue = callFrame->globalData().exception;
227 if (exceptionValue)
228 return false;
14957cd0
A
229 ASSERT(result);
230 callFrame->uncheckedR(dst) = JSValue(result);
4e4e5a6f
A
231 return true;
232 }
233 if (iter == end)
234 break;
14957cd0 235 o = iter->get();
4e4e5a6f
A
236 ++iter;
237 } while (true);
14957cd0 238 exceptionValue = createUndefinedVariableError(callFrame, ident);
4e4e5a6f
A
239 return false;
240 }
241 ++iter;
242 }
243
244 if (structure == globalObject->structure()) {
14957cd0
A
245 callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
246 ASSERT(callFrame->uncheckedR(dst).jsValue());
4e4e5a6f
A
247 return true;
248 }
249
250 Identifier& ident = codeBlock->identifier(property);
251 PropertySlot slot(globalObject);
252 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
253 JSValue result = slot.getValue(callFrame, ident);
254 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
14957cd0
A
255 vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
256 vPC[4] = slot.cachedOffset();
257 ASSERT(result);
258 callFrame->uncheckedR(dst) = JSValue(result);
4e4e5a6f
A
259 return true;
260 }
261
262 exceptionValue = callFrame->globalData().exception;
263 if (exceptionValue)
264 return false;
14957cd0
A
265 ASSERT(result);
266 callFrame->uncheckedR(dst) = JSValue(result);
4e4e5a6f
A
267 return true;
268 }
269
14957cd0 270 exceptionValue = createUndefinedVariableError(callFrame, ident);
4e4e5a6f
A
271 return false;
272}
273
9dae56ea
A
274NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
275{
f9bf01c6
A
276 int dst = vPC[1].u.operand;
277 int property = vPC[2].u.operand;
14957cd0
A
278 bool isStrictPut = vPC[3].u.operand;
279 Identifier ident = callFrame->codeBlock()->identifier(property);
280 JSValue result = JSC::resolveBase(callFrame, ident, callFrame->scopeChain(), isStrictPut);
281 if (result) {
282 callFrame->uncheckedR(dst) = result;
283 ASSERT(callFrame->uncheckedR(dst).jsValue());
284 } else
285 callFrame->globalData().exception = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
9dae56ea
A
286}
287
ba379fdc 288NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
9dae56ea 289{
f9bf01c6
A
290 int baseDst = vPC[1].u.operand;
291 int propDst = vPC[2].u.operand;
292 int property = vPC[3].u.operand;
9dae56ea
A
293
294 ScopeChainNode* scopeChain = callFrame->scopeChain();
295 ScopeChainIterator iter = scopeChain->begin();
296 ScopeChainIterator end = scopeChain->end();
297
298 // FIXME: add scopeDepthIsZero optimization
299
300 ASSERT(iter != end);
301
302 CodeBlock* codeBlock = callFrame->codeBlock();
303 Identifier& ident = codeBlock->identifier(property);
304 JSObject* base;
305 do {
14957cd0 306 base = iter->get();
9dae56ea
A
307 PropertySlot slot(base);
308 if (base->getPropertySlot(callFrame, ident, slot)) {
ba379fdc 309 JSValue result = slot.getValue(callFrame, ident);
9dae56ea
A
310 exceptionValue = callFrame->globalData().exception;
311 if (exceptionValue)
312 return false;
14957cd0
A
313 callFrame->uncheckedR(propDst) = JSValue(result);
314 callFrame->uncheckedR(baseDst) = JSValue(base);
9dae56ea
A
315 return true;
316 }
317 ++iter;
318 } while (iter != end);
319
14957cd0 320 exceptionValue = createUndefinedVariableError(callFrame, ident);
9dae56ea
A
321 return false;
322}
323
4e4e5a6f 324#endif // ENABLE(INTERPRETER)
ba379fdc 325
9dae56ea
A
326ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
327{
328 Register* r = callFrame->registers();
329 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters;
330
331 if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments
332 if (UNLIKELY(!registerFile->grow(newEnd)))
333 return 0;
334 r += registerOffset;
335 } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks
336 size_t omittedArgCount = newCodeBlock->m_numParameters - argc;
337 registerOffset += omittedArgCount;
338 newEnd += omittedArgCount;
339 if (!registerFile->grow(newEnd))
340 return 0;
341 r += registerOffset;
342
343 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
344 for (size_t i = 0; i < omittedArgCount; ++i)
345 argv[i] = jsUndefined();
346 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
347 size_t numParameters = newCodeBlock->m_numParameters;
348 registerOffset += numParameters;
349 newEnd += numParameters;
350
351 if (!registerFile->grow(newEnd))
352 return 0;
353 r += registerOffset;
354
355 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
356 for (size_t i = 0; i < numParameters; ++i)
357 argv[i + argc] = argv[i];
358 }
359
360 return CallFrame::create(r);
361}
362
4e4e5a6f 363#if ENABLE(INTERPRETER)
14957cd0 364static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
9dae56ea
A
365{
366 if (value.isObject())
367 return false;
14957cd0 368 exceptionData = createInvalidParamError(callFrame, "in" , value);
9dae56ea
A
369 return true;
370}
371
14957cd0 372static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
ba379fdc
A
373{
374 if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
375 return false;
14957cd0 376 exceptionData = createInvalidParamError(callFrame, "instanceof" , value);
ba379fdc
A
377 return true;
378}
379#endif
380
14957cd0 381NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset)
9dae56ea
A
382{
383 if (argc < 2)
384 return jsUndefined();
385
ba379fdc 386 JSValue program = argv[1].jsValue();
9dae56ea
A
387
388 if (!program.isString())
389 return program;
390
f9bf01c6 391 UString programSource = asString(program)->value(callFrame);
4e4e5a6f
A
392 if (callFrame->hadException())
393 return JSValue();
14957cd0
A
394
395 CodeBlock* codeBlock = callFrame->codeBlock();
396 if (!codeBlock->isStrictMode()) {
397 // FIXME: We can use the preparser in strict mode, we just need additional logic
398 // to prevent duplicates.
399 LiteralParser preparser(callFrame, programSource.characters(), programSource.length(), LiteralParser::NonStrictJSON);
400 if (JSValue parsedObject = preparser.tryLiteralParse())
401 return parsedObject;
402 }
f9bf01c6 403
9dae56ea 404 ScopeChainNode* scopeChain = callFrame->scopeChain();
14957cd0
A
405 JSValue exceptionValue;
406 EvalExecutable* eval = codeBlock->evalCodeCache().get(callFrame, codeBlock->ownerExecutable(), codeBlock->isStrictMode(), programSource, scopeChain, exceptionValue);
9dae56ea 407
14957cd0
A
408 ASSERT(!eval == exceptionValue);
409 if (UNLIKELY(!eval))
410 return throwError(callFrame, exceptionValue);
9dae56ea 411
14957cd0 412 return callFrame->globalData().interpreter->execute(eval, callFrame, callFrame->uncheckedR(codeBlock->thisRegister()).jsValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain);
9dae56ea
A
413}
414
14957cd0 415Interpreter::Interpreter(JSGlobalData& globalData)
f9bf01c6 416 : m_sampleEntryDepth(0)
9dae56ea 417 , m_reentryDepth(0)
14957cd0 418 , m_registerFile(globalData)
9dae56ea 419{
4e4e5a6f 420#if ENABLE(COMPUTED_GOTO_INTERPRETER)
14957cd0 421 privateExecute(InitializeAndReturn, 0, 0);
9dae56ea 422
ba379fdc
A
423 for (int i = 0; i < numOpcodeIDs; ++i)
424 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
4e4e5a6f 425#endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
f9bf01c6
A
426
427#if ENABLE(OPCODE_SAMPLING)
428 enableSampler();
429#endif
9dae56ea
A
430}
431
432#ifndef NDEBUG
433
434void Interpreter::dumpCallFrame(CallFrame* callFrame)
435{
436 callFrame->codeBlock()->dump(callFrame);
437 dumpRegisters(callFrame);
438}
439
440void Interpreter::dumpRegisters(CallFrame* callFrame)
441{
442 printf("Register frame: \n\n");
ba379fdc
A
443 printf("-----------------------------------------------------------------------------\n");
444 printf(" use | address | value \n");
445 printf("-----------------------------------------------------------------------------\n");
9dae56ea
A
446
447 CodeBlock* codeBlock = callFrame->codeBlock();
14957cd0 448 RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData().interpreter->registerFile();
9dae56ea
A
449 const Register* it;
450 const Register* end;
ba379fdc 451 JSValue v;
9dae56ea
A
452
453 if (codeBlock->codeType() == GlobalCode) {
454 it = registerFile->lastGlobal();
455 end = it + registerFile->numGlobals();
456 while (it != end) {
ba379fdc
A
457 v = (*it).jsValue();
458#if USE(JSVALUE32_64)
459 printf("[global var] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
460#else
461 printf("[global var] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
462#endif
9dae56ea
A
463 ++it;
464 }
ba379fdc 465 printf("-----------------------------------------------------------------------------\n");
9dae56ea
A
466 }
467
468 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters;
ba379fdc
A
469 v = (*it).jsValue();
470#if USE(JSVALUE32_64)
471 printf("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it;
472#else
473 printf("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it;
474#endif
9dae56ea
A
475 end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this"
476 if (it != end) {
477 do {
ba379fdc
A
478 v = (*it).jsValue();
479#if USE(JSVALUE32_64)
480 printf("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
481#else
482 printf("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
483#endif
9dae56ea
A
484 ++it;
485 } while (it != end);
486 }
ba379fdc
A
487 printf("-----------------------------------------------------------------------------\n");
488 printf("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it;
489 printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
490 printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
491 printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
ba379fdc
A
492 printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
493 printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it;
ba379fdc 494 printf("-----------------------------------------------------------------------------\n");
9dae56ea
A
495
496 int registerCount = 0;
497
498 end = it + codeBlock->m_numVars;
499 if (it != end) {
500 do {
ba379fdc
A
501 v = (*it).jsValue();
502#if USE(JSVALUE32_64)
503 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
504#else
505 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
506#endif
9dae56ea
A
507 ++it;
508 ++registerCount;
509 } while (it != end);
510 }
ba379fdc 511 printf("-----------------------------------------------------------------------------\n");
9dae56ea 512
ba379fdc 513 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
9dae56ea
A
514 if (it != end) {
515 do {
ba379fdc
A
516 v = (*it).jsValue();
517#if USE(JSVALUE32_64)
518 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
519#else
520 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
521#endif
9dae56ea
A
522 ++it;
523 ++registerCount;
524 } while (it != end);
525 }
ba379fdc 526 printf("-----------------------------------------------------------------------------\n");
9dae56ea
A
527}
528
529#endif
530
531bool Interpreter::isOpcode(Opcode opcode)
532{
4e4e5a6f 533#if ENABLE(COMPUTED_GOTO_INTERPRETER)
9dae56ea
A
534 return opcode != HashTraits<Opcode>::emptyValue()
535 && !HashTraits<Opcode>::isDeletedValue(opcode)
536 && m_opcodeIDTable.contains(opcode);
537#else
538 return opcode >= 0 && opcode <= op_end;
539#endif
540}
541
ba379fdc 542NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
9dae56ea
A
543{
544 CodeBlock* oldCodeBlock = codeBlock;
545 ScopeChainNode* scopeChain = callFrame->scopeChain();
546
547 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
548 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
549 if (callFrame->callee())
f9bf01c6 550 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
9dae56ea 551 else
f9bf01c6 552 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
9dae56ea
A
553 }
554
9dae56ea
A
555 // If this call frame created an activation or an 'arguments' object, tear it off.
556 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
14957cd0
A
557 if (!callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue()) {
558 oldCodeBlock->createActivation(callFrame);
559 scopeChain = callFrame->scopeChain();
560 }
561 while (!scopeChain->object->inherits(&JSActivation::s_info))
9dae56ea 562 scopeChain = scopeChain->pop();
9dae56ea 563
14957cd0
A
564 callFrame->setScopeChain(scopeChain);
565 JSActivation* activation = asActivation(scopeChain->object.get());
566 activation->copyRegisters(*scopeChain->globalData);
567 if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) {
568 if (!oldCodeBlock->isStrictMode())
569 asArguments(arguments)->setActivation(callFrame->globalData(), activation);
570 }
571 } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) {
572 if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
573 asArguments(arguments)->copyRegisters(callFrame->globalData());
574 }
9dae56ea 575
14957cd0 576 CallFrame* callerFrame = callFrame->callerFrame();
4e4e5a6f 577 if (callerFrame->hasHostCallFrameFlag())
9dae56ea
A
578 return false;
579
4e4e5a6f 580 codeBlock = callerFrame->codeBlock();
14957cd0
A
581
582 // Because of how the JIT records call site->bytecode offset
583 // information the JIT reports the bytecodeOffset for the returnPC
584 // to be at the beginning of the opcode that has caused the call.
585 // In the interpreter we have an actual return address, which is
586 // the beginning of next instruction to execute. To get an offset
587 // inside the call instruction that triggered the exception we
588 // have to subtract 1.
589#if ENABLE(JIT) && ENABLE(INTERPRETER)
4e4e5a6f 590 if (callerFrame->globalData().canUseJIT())
14957cd0 591 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
4e4e5a6f 592 else
14957cd0
A
593 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1;
594#elif ENABLE(JIT)
595 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
4e4e5a6f 596#else
14957cd0 597 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1;
4e4e5a6f 598#endif
14957cd0 599
4e4e5a6f 600 callFrame = callerFrame;
9dae56ea
A
601 return true;
602}
603
14957cd0 604static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
9dae56ea 605{
14957cd0
A
606 exception->clearAppendSourceToMessage();
607
608 if (!callFrame->codeBlock()->hasExpressionInfo())
609 return;
610
611 int startOffset = 0;
612 int endOffset = 0;
613 int divotPoint = 0;
614
615 CodeBlock* codeBlock = callFrame->codeBlock();
616 codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset);
617
618 int expressionStart = divotPoint - startOffset;
619 int expressionStop = divotPoint + endOffset;
620
621 if (!expressionStop || expressionStart > codeBlock->source()->length())
622 return;
623
624 JSGlobalData* globalData = &callFrame->globalData();
625 JSValue jsMessage = exception->getDirect(*globalData, globalData->propertyNames->message);
626 if (!jsMessage || !jsMessage.isString())
627 return;
628
629 UString message = asString(jsMessage)->value(callFrame);
630
631 if (expressionStart < expressionStop)
632 message = makeUString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')");
633 else {
634 // No range information, so give a few characters of context
635 const UChar* data = codeBlock->source()->data();
636 int dataLength = codeBlock->source()->length();
637 int start = expressionStart;
638 int stop = expressionStart;
639 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
640 // then strip whitespace.
641 while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
642 start--;
643 while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
644 start++;
645 while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
646 stop++;
647 while (stop > expressionStart && isStrWhiteSpace(data[stop - 1]))
648 stop--;
649 message = makeUString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')");
650 }
651
652 exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message));
653}
9dae56ea 654
14957cd0
A
655NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
656{
9dae56ea 657 CodeBlock* codeBlock = callFrame->codeBlock();
14957cd0
A
658 bool isInterrupt = false;
659
660 // Set up the exception object
9dae56ea
A
661 if (exceptionValue.isObject()) {
662 JSObject* exception = asObject(exceptionValue);
4e4e5a6f 663
14957cd0
A
664 if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage())
665 appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset);
666
667 // Using hasExpressionInfo to imply we are interested in rich exception info.
668 if (codeBlock->hasExpressionInfo() && !hasErrorInfo(callFrame, exception)) {
669 ASSERT(codeBlock->hasLineInfo());
670
671 // FIXME: should only really be adding these properties to VM generated exceptions,
672 // but the inspector currently requires these for all thrown objects.
673 addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source());
9dae56ea 674 }
14957cd0
A
675
676 ComplType exceptionType = exception->exceptionType();
677 isInterrupt = exceptionType == Interrupted || exceptionType == Terminated;
9dae56ea
A
678 }
679
680 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
681 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
f9bf01c6 682 bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
14957cd0 683 debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), hasHandler);
9dae56ea
A
684 }
685
686 // Calculate an exception handler vPC, unwinding call frames as necessary.
9dae56ea 687 HandlerInfo* handler = 0;
14957cd0
A
688 while (isInterrupt || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
689 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
690 if (Profiler* profiler = *Profiler::enabledProfilerReference())
691 profiler->exceptionUnwind(callFrame);
9dae56ea 692 return 0;
14957cd0 693 }
9dae56ea
A
694 }
695
14957cd0
A
696 if (Profiler* profiler = *Profiler::enabledProfilerReference())
697 profiler->exceptionUnwind(callFrame);
9dae56ea 698
14957cd0
A
699 // Shrink the JS stack, in case stack overflow made it huge.
700 Register* highWaterMark = 0;
701 for (CallFrame* callerFrame = callFrame; callerFrame; callerFrame = callerFrame->callerFrame()->removeHostCallFrameFlag()) {
702 CodeBlock* codeBlock = callerFrame->codeBlock();
703 if (!codeBlock)
704 continue;
705 Register* callerHighWaterMark = callerFrame->registers() + codeBlock->m_numCalleeRegisters;
706 highWaterMark = max(highWaterMark, callerHighWaterMark);
707 }
708 m_registerFile.shrink(highWaterMark);
709
710 // Unwind the scope chain within the exception handler's call frame.
9dae56ea 711 ScopeChainNode* scopeChain = callFrame->scopeChain();
14957cd0
A
712 int scopeDelta = 0;
713 if (!codeBlock->needsFullScopeChain() || codeBlock->codeType() != FunctionCode
714 || callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
715 scopeDelta = depth(codeBlock, scopeChain) - handler->scopeDepth;
9dae56ea
A
716 ASSERT(scopeDelta >= 0);
717 while (scopeDelta--)
718 scopeChain = scopeChain->pop();
719 callFrame->setScopeChain(scopeChain);
720
721 return handler;
722}
723
14957cd0
A
724static inline JSValue checkedReturn(JSValue returnValue)
725{
726 ASSERT(returnValue);
727 return returnValue;
728}
729
730static inline JSObject* checkedReturn(JSObject* returnValue)
731{
732 ASSERT(returnValue);
733 return returnValue;
734}
735
736JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
9dae56ea
A
737{
738 ASSERT(!scopeChain->globalData->exception);
14957cd0
A
739 ASSERT(!callFrame->globalData().isCollectorBusy());
740 if (callFrame->globalData().isCollectorBusy())
741 return jsNull();
9dae56ea 742
14957cd0
A
743 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
744 return checkedReturn(throwStackOverflowError(callFrame));
745
746 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
747 LiteralParser literalParser(callFrame, program->source().data(), program->source().length(), LiteralParser::JSONP);
748 Vector<LiteralParser::JSONPData> JSONPData;
749 if (literalParser.tryJSONPParse(JSONPData, scopeChain->globalObject->supportsRichSourceInfo())) {
750 JSGlobalObject* globalObject = scopeChain->globalObject.get();
751 JSValue result;
752 for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
753 Vector<LiteralParser::JSONPPathEntry> JSONPPath;
754 JSONPPath.swap(JSONPData[entry].m_path);
755 JSValue JSONPValue = JSONPData[entry].m_value.get();
756 if (JSONPPath.size() == 1 && JSONPPath[0].m_type == LiteralParser::JSONPPathEntryTypeDeclare) {
757 if (globalObject->hasProperty(callFrame, JSONPPath[0].m_pathEntryName)) {
758 PutPropertySlot slot;
759 globalObject->put(callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
760 } else
761 globalObject->putWithAttributes(callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, DontEnum | DontDelete);
762 // var declarations return undefined
763 result = jsUndefined();
764 continue;
765 }
766 JSValue baseObject(globalObject);
767 for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
768 ASSERT(JSONPPath[i].m_type != LiteralParser::JSONPPathEntryTypeDeclare);
769 switch (JSONPPath[i].m_type) {
770 case LiteralParser::JSONPPathEntryTypeDot: {
771 if (i == 0) {
772 PropertySlot slot(globalObject);
773 if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) {
774 if (entry)
775 return throwError(callFrame, createUndefinedVariableError(globalObject->globalExec(), JSONPPath[i].m_pathEntryName));
776 goto failedJSONP;
777 }
778 baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);
779 } else
780 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName);
781 if (callFrame->hadException())
782 return jsUndefined();
783 continue;
784 }
785 case LiteralParser::JSONPPathEntryTypeLookup: {
786 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathIndex);
787 if (callFrame->hadException())
788 return jsUndefined();
789 continue;
790 }
791 default:
792 ASSERT_NOT_REACHED();
793 return jsUndefined();
794 }
795 }
796 PutPropertySlot slot;
797 switch (JSONPPath.last().m_type) {
798 case LiteralParser::JSONPPathEntryTypeCall: {
799 JSValue function = baseObject.get(callFrame, JSONPPath.last().m_pathEntryName);
800 if (callFrame->hadException())
801 return jsUndefined();
802 CallData callData;
803 CallType callType = getCallData(function, callData);
804 if (callType == CallTypeNone)
805 return throwError(callFrame, createNotAFunctionError(callFrame, function));
806 MarkedArgumentBuffer jsonArg;
807 jsonArg.append(JSONPValue);
808 JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined(): baseObject;
809 JSONPValue = JSC::call(callFrame, function, callType, callData, thisValue, jsonArg);
810 if (callFrame->hadException())
811 return jsUndefined();
812 break;
813 }
814 case LiteralParser::JSONPPathEntryTypeDot: {
815 baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
816 if (callFrame->hadException())
817 return jsUndefined();
818 break;
819 }
820 case LiteralParser::JSONPPathEntryTypeLookup: {
821 baseObject.put(callFrame, JSONPPath.last().m_pathIndex, JSONPValue);
822 if (callFrame->hadException())
823 return jsUndefined();
824 break;
825 }
826 default:
827 ASSERT_NOT_REACHED();
828 return jsUndefined();
829 }
830 result = JSONPValue;
ba379fdc 831 }
14957cd0 832 return result;
9dae56ea 833 }
14957cd0
A
834failedJSONP:
835 JSObject* error = program->compile(callFrame, scopeChain);
836 if (error)
837 return checkedReturn(throwError(callFrame, error));
838 CodeBlock* codeBlock = &program->generatedBytecode();
9dae56ea
A
839
840 Register* oldEnd = m_registerFile.end();
841 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
14957cd0
A
842 if (!m_registerFile.grow(newEnd))
843 return checkedReturn(throwStackOverflowError(callFrame));
9dae56ea
A
844
845 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
846 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
847 globalObject->copyGlobalsTo(m_registerFile);
848
849 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
14957cd0
A
850 ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
851 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), codeBlock->m_numParameters, 0);
852 newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
9dae56ea
A
853
854 Profiler** profiler = Profiler::enabledProfilerReference();
855 if (*profiler)
14957cd0 856 (*profiler)->willExecute(callFrame, program->sourceURL(), program->lineNo());
9dae56ea 857
ba379fdc 858 JSValue result;
9dae56ea 859 {
f9bf01c6 860 SamplingTool::CallRecord callRecord(m_sampler.get());
9dae56ea 861
4e4e5a6f 862 m_reentryDepth++;
9dae56ea 863#if ENABLE(JIT)
4e4e5a6f 864 if (callFrame->globalData().canUseJIT())
14957cd0 865 result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
4e4e5a6f
A
866 else
867#endif
14957cd0 868 result = privateExecute(Normal, &m_registerFile, newCallFrame);
4e4e5a6f 869
9dae56ea
A
870 m_reentryDepth--;
871 }
872
873 if (*profiler)
f9bf01c6 874 (*profiler)->didExecute(callFrame, program->sourceURL(), program->lineNo());
9dae56ea
A
875
876 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
877 lastGlobalObject->copyGlobalsTo(m_registerFile);
878
879 m_registerFile.shrink(oldEnd);
880
14957cd0 881 return checkedReturn(result);
9dae56ea
A
882}
883
14957cd0 884JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
9dae56ea 885{
14957cd0
A
886 ASSERT(!callFrame->hadException());
887 ASSERT(!callFrame->globalData().isCollectorBusy());
888 if (callFrame->globalData().isCollectorBusy())
889 return jsNull();
9dae56ea 890
14957cd0
A
891 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
892 return checkedReturn(throwStackOverflowError(callFrame));
9dae56ea
A
893
894 Register* oldEnd = m_registerFile.end();
14957cd0
A
895 int argCount = 1 + args.size(); // implicit "this" parameter
896 size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
9dae56ea 897
14957cd0
A
898 if (!m_registerFile.grow(oldEnd + registerOffset))
899 return checkedReturn(throwStackOverflowError(callFrame));
9dae56ea
A
900
901 CallFrame* newCallFrame = CallFrame::create(oldEnd);
902 size_t dst = 0;
14957cd0 903 newCallFrame->uncheckedR(0) = thisValue;
9dae56ea
A
904 ArgList::const_iterator end = args.end();
905 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
14957cd0
A
906 newCallFrame->uncheckedR(++dst) = *it;
907
908 if (callType == CallTypeJS) {
909 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
910
911 DynamicGlobalObjectScope globalObjectScope(*callDataScopeChain->globalData, callDataScopeChain->globalObject.get());
912
913 JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
914 if (UNLIKELY(!!compileError)) {
915 m_registerFile.shrink(oldEnd);
916 return checkedReturn(throwError(callFrame, compileError));
917 }
918
919 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
920 newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
921 if (UNLIKELY(!newCallFrame)) {
922 m_registerFile.shrink(oldEnd);
923 return checkedReturn(throwStackOverflowError(callFrame));
924 }
925
926 newCallFrame->init(newCodeBlock, 0, callDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
927
928 Profiler** profiler = Profiler::enabledProfilerReference();
929 if (*profiler)
930 (*profiler)->willExecute(callFrame, function);
931
932 JSValue result;
933 {
934 SamplingTool::CallRecord callRecord(m_sampler.get());
935
936 m_reentryDepth++;
937#if ENABLE(JIT)
938 if (callFrame->globalData().canUseJIT())
939 result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScopeChain->globalData);
940 else
941#endif
942 result = privateExecute(Normal, &m_registerFile, newCallFrame);
943 m_reentryDepth--;
944 }
945
946 if (*profiler)
947 (*profiler)->didExecute(callFrame, function);
9dae56ea 948
9dae56ea 949 m_registerFile.shrink(oldEnd);
14957cd0 950 return checkedReturn(result);
9dae56ea 951 }
14957cd0
A
952
953 ASSERT(callType == CallTypeHost);
954 ScopeChainNode* scopeChain = callFrame->scopeChain();
955 newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
956 newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
957
958 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
9dae56ea
A
959
960 Profiler** profiler = Profiler::enabledProfilerReference();
961 if (*profiler)
962 (*profiler)->willExecute(callFrame, function);
963
ba379fdc 964 JSValue result;
9dae56ea 965 {
14957cd0
A
966 SamplingTool::HostCallRecord callRecord(m_sampler.get());
967 result = JSValue::decode(callData.native.function(newCallFrame));
968 }
9dae56ea 969
14957cd0
A
970 if (*profiler)
971 (*profiler)->didExecute(callFrame, function);
972
973 m_registerFile.shrink(oldEnd);
974 return checkedReturn(result);
975}
976
977JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
978{
979 ASSERT(!callFrame->hadException());
980 ASSERT(!callFrame->globalData().isCollectorBusy());
981 // We throw in this case because we have to return something "valid" but we're
982 // already in an invalid state.
983 if (callFrame->globalData().isCollectorBusy())
984 return checkedReturn(throwStackOverflowError(callFrame));
985
986 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
987 return checkedReturn(throwStackOverflowError(callFrame));
988
989 Register* oldEnd = m_registerFile.end();
990 int argCount = 1 + args.size(); // implicit "this" parameter
991 size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
992
993 if (!m_registerFile.grow(oldEnd + registerOffset))
994 return checkedReturn(throwStackOverflowError(callFrame));
995
996 CallFrame* newCallFrame = CallFrame::create(oldEnd);
997 size_t dst = 0;
998 ArgList::const_iterator end = args.end();
999 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
1000 newCallFrame->uncheckedR(++dst) = *it;
1001
1002 if (constructType == ConstructTypeJS) {
1003 ScopeChainNode* constructDataScopeChain = constructData.js.scopeChain;
1004
1005 DynamicGlobalObjectScope globalObjectScope(*constructDataScopeChain->globalData, constructDataScopeChain->globalObject.get());
1006
1007 JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, constructDataScopeChain);
1008 if (UNLIKELY(!!compileError)) {
1009 m_registerFile.shrink(oldEnd);
1010 return checkedReturn(throwError(callFrame, compileError));
1011 }
1012
1013 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
1014 newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
1015 if (UNLIKELY(!newCallFrame)) {
1016 m_registerFile.shrink(oldEnd);
1017 return checkedReturn(throwStackOverflowError(callFrame));
1018 }
1019
1020 newCallFrame->init(newCodeBlock, 0, constructDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
1021
1022 Profiler** profiler = Profiler::enabledProfilerReference();
1023 if (*profiler)
1024 (*profiler)->willExecute(callFrame, constructor);
1025
1026 JSValue result;
1027 {
1028 SamplingTool::CallRecord callRecord(m_sampler.get());
1029
1030 m_reentryDepth++;
9dae56ea 1031#if ENABLE(JIT)
14957cd0
A
1032 if (callFrame->globalData().canUseJIT())
1033 result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScopeChain->globalData);
1034 else
9dae56ea 1035#endif
14957cd0
A
1036 result = privateExecute(Normal, &m_registerFile, newCallFrame);
1037 m_reentryDepth--;
1038 }
1039
1040 if (*profiler)
1041 (*profiler)->didExecute(callFrame, constructor);
1042
1043 m_registerFile.shrink(oldEnd);
1044 if (callFrame->hadException())
1045 return 0;
1046 ASSERT(result.isObject());
1047 return checkedReturn(asObject(result));
9dae56ea
A
1048 }
1049
14957cd0
A
1050 ASSERT(constructType == ConstructTypeHost);
1051 ScopeChainNode* scopeChain = callFrame->scopeChain();
1052 newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
1053 newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
1054
1055 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
1056
1057 Profiler** profiler = Profiler::enabledProfilerReference();
9dae56ea 1058 if (*profiler)
14957cd0
A
1059 (*profiler)->willExecute(callFrame, constructor);
1060
1061 JSValue result;
1062 {
1063 SamplingTool::HostCallRecord callRecord(m_sampler.get());
1064 result = JSValue::decode(constructData.native.function(newCallFrame));
1065 }
1066
1067 if (*profiler)
1068 (*profiler)->didExecute(callFrame, constructor);
9dae56ea
A
1069
1070 m_registerFile.shrink(oldEnd);
14957cd0
A
1071 if (callFrame->hadException())
1072 return 0;
1073 ASSERT(result.isObject());
1074 return checkedReturn(asObject(result));
9dae56ea
A
1075}
1076
14957cd0 1077CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain)
ba379fdc
A
1078{
1079 ASSERT(!scopeChain->globalData->exception);
1080
4e4e5a6f
A
1081 if (m_reentryDepth >= MaxSmallThreadReentryDepth) {
1082 if (m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
14957cd0 1083 throwStackOverflowError(callFrame);
ba379fdc
A
1084 return CallFrameClosure();
1085 }
1086 }
1087
1088 Register* oldEnd = m_registerFile.end();
1089 int argc = 1 + argCount; // implicit "this" parameter
1090
1091 if (!m_registerFile.grow(oldEnd + argc)) {
14957cd0 1092 throwStackOverflowError(callFrame);
ba379fdc
A
1093 return CallFrameClosure();
1094 }
1095
1096 CallFrame* newCallFrame = CallFrame::create(oldEnd);
14957cd0 1097 // We initialise |this| unnecessarily here for the sake of code clarity
ba379fdc
A
1098 size_t dst = 0;
1099 for (int i = 0; i < argc; ++i)
14957cd0 1100 newCallFrame->uncheckedR(dst++) = jsUndefined();
ba379fdc 1101
14957cd0
A
1102 JSObject* error = FunctionExecutable->compileForCall(callFrame, scopeChain);
1103 if (error) {
1104 throwError(callFrame, error);
1105 m_registerFile.shrink(oldEnd);
1106 return CallFrameClosure();
1107 }
1108 CodeBlock* codeBlock = &FunctionExecutable->generatedBytecodeForCall();
1109
ba379fdc
A
1110 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
1111 if (UNLIKELY(!newCallFrame)) {
14957cd0 1112 throwStackOverflowError(callFrame);
ba379fdc
A
1113 m_registerFile.shrink(oldEnd);
1114 return CallFrameClosure();
1115 }
14957cd0 1116 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), argc, function);
f9bf01c6 1117 CallFrameClosure result = { callFrame, newCallFrame, function, FunctionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc };
ba379fdc
A
1118 return result;
1119}
1120
14957cd0 1121JSValue Interpreter::execute(CallFrameClosure& closure)
ba379fdc 1122{
14957cd0
A
1123 ASSERT(!closure.oldCallFrame->globalData().isCollectorBusy());
1124 if (closure.oldCallFrame->globalData().isCollectorBusy())
1125 return jsNull();
ba379fdc
A
1126 closure.resetCallFrame();
1127 Profiler** profiler = Profiler::enabledProfilerReference();
1128 if (*profiler)
1129 (*profiler)->willExecute(closure.oldCallFrame, closure.function);
1130
1131 JSValue result;
1132 {
f9bf01c6 1133 SamplingTool::CallRecord callRecord(m_sampler.get());
ba379fdc 1134
4e4e5a6f 1135 m_reentryDepth++;
ba379fdc 1136#if ENABLE(JIT)
4e4e5a6f
A
1137#if ENABLE(INTERPRETER)
1138 if (closure.newCallFrame->globalData().canUseJIT())
1139#endif
14957cd0 1140 result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, closure.newCallFrame, closure.globalData);
4e4e5a6f
A
1141#if ENABLE(INTERPRETER)
1142 else
1143#endif
1144#endif
1145#if ENABLE(INTERPRETER)
14957cd0 1146 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame);
ba379fdc
A
1147#endif
1148 m_reentryDepth--;
1149 }
1150
1151 if (*profiler)
1152 (*profiler)->didExecute(closure.oldCallFrame, closure.function);
14957cd0 1153 return checkedReturn(result);
ba379fdc
A
1154}
1155
1156void Interpreter::endRepeatCall(CallFrameClosure& closure)
1157{
1158 m_registerFile.shrink(closure.oldEnd);
1159}
1160
14957cd0 1161JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain)
9dae56ea 1162{
14957cd0
A
1163 JSObject* compileError = eval->compile(callFrame, scopeChain);
1164 if (UNLIKELY(!!compileError))
1165 return checkedReturn(throwError(callFrame, compileError));
1166 return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->generatedBytecode().m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain);
9dae56ea
A
1167}
1168
14957cd0 1169JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain)
9dae56ea
A
1170{
1171 ASSERT(!scopeChain->globalData->exception);
14957cd0
A
1172 ASSERT(!callFrame->globalData().isCollectorBusy());
1173 if (callFrame->globalData().isCollectorBusy())
1174 return jsNull();
9dae56ea 1175
14957cd0 1176 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
9dae56ea 1177
14957cd0
A
1178 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
1179 return checkedReturn(throwStackOverflowError(callFrame));
9dae56ea 1180
14957cd0
A
1181 JSObject* compileError = eval->compile(callFrame, scopeChain);
1182 if (UNLIKELY(!!compileError))
1183 return checkedReturn(throwError(callFrame, compileError));
1184 EvalCodeBlock* codeBlock = &eval->generatedBytecode();
9dae56ea 1185
14957cd0
A
1186 JSObject* variableObject;
1187 for (ScopeChainNode* node = scopeChain; ; node = node->next.get()) {
9dae56ea
A
1188 ASSERT(node);
1189 if (node->object->isVariableObject()) {
14957cd0 1190 variableObject = static_cast<JSVariableObject*>(node->object.get());
9dae56ea
A
1191 break;
1192 }
1193 }
1194
4e4e5a6f
A
1195 unsigned numVariables = codeBlock->numVariables();
1196 int numFunctions = codeBlock->numberOfFunctionDecls();
14957cd0 1197 bool pushedScope = false;
4e4e5a6f 1198 if (numVariables || numFunctions) {
14957cd0
A
1199 if (codeBlock->isStrictMode()) {
1200 variableObject = new (callFrame) StrictEvalActivation(callFrame);
1201 scopeChain = scopeChain->push(variableObject);
1202 pushedScope = true;
1203 }
4e4e5a6f 1204 // Scope for BatchedTransitionOptimizer
14957cd0 1205 BatchedTransitionOptimizer optimizer(callFrame->globalData(), variableObject);
9dae56ea 1206
f9bf01c6
A
1207 for (unsigned i = 0; i < numVariables; ++i) {
1208 const Identifier& ident = codeBlock->variable(i);
9dae56ea
A
1209 if (!variableObject->hasProperty(callFrame, ident)) {
1210 PutPropertySlot slot;
1211 variableObject->put(callFrame, ident, jsUndefined(), slot);
1212 }
1213 }
1214
f9bf01c6
A
1215 for (int i = 0; i < numFunctions; ++i) {
1216 FunctionExecutable* function = codeBlock->functionDecl(i);
9dae56ea 1217 PutPropertySlot slot;
f9bf01c6 1218 variableObject->put(callFrame, function->name(), function->make(callFrame, scopeChain), slot);
9dae56ea 1219 }
9dae56ea
A
1220 }
1221
1222 Register* oldEnd = m_registerFile.end();
1223 Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
1224 if (!m_registerFile.grow(newEnd)) {
14957cd0
A
1225 if (pushedScope)
1226 scopeChain->pop();
1227 return checkedReturn(throwStackOverflowError(callFrame));
9dae56ea
A
1228 }
1229
1230 CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
1231
14957cd0
A
1232 ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
1233 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->m_numParameters, 0);
1234 newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
9dae56ea
A
1235
1236 Profiler** profiler = Profiler::enabledProfilerReference();
1237 if (*profiler)
14957cd0 1238 (*profiler)->willExecute(callFrame, eval->sourceURL(), eval->lineNo());
9dae56ea 1239
ba379fdc 1240 JSValue result;
9dae56ea 1241 {
f9bf01c6 1242 SamplingTool::CallRecord callRecord(m_sampler.get());
9dae56ea
A
1243
1244 m_reentryDepth++;
4e4e5a6f 1245
9dae56ea 1246#if ENABLE(JIT)
4e4e5a6f
A
1247#if ENABLE(INTERPRETER)
1248 if (callFrame->globalData().canUseJIT())
1249#endif
14957cd0 1250 result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
4e4e5a6f
A
1251#if ENABLE(INTERPRETER)
1252 else
1253#endif
1254#endif
1255#if ENABLE(INTERPRETER)
14957cd0 1256 result = privateExecute(Normal, &m_registerFile, newCallFrame);
9dae56ea
A
1257#endif
1258 m_reentryDepth--;
1259 }
1260
1261 if (*profiler)
f9bf01c6 1262 (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
9dae56ea
A
1263
1264 m_registerFile.shrink(oldEnd);
14957cd0
A
1265 if (pushedScope)
1266 scopeChain->pop();
1267 return checkedReturn(result);
9dae56ea
A
1268}
1269
1270NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
1271{
1272 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
1273 if (!debugger)
1274 return;
1275
1276 switch (debugHookID) {
1277 case DidEnterCallFrame:
f9bf01c6 1278 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
9dae56ea
A
1279 return;
1280 case WillLeaveCallFrame:
f9bf01c6 1281 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
9dae56ea
A
1282 return;
1283 case WillExecuteStatement:
f9bf01c6 1284 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
9dae56ea
A
1285 return;
1286 case WillExecuteProgram:
f9bf01c6 1287 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
9dae56ea
A
1288 return;
1289 case DidExecuteProgram:
f9bf01c6 1290 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
9dae56ea
A
1291 return;
1292 case DidReachBreakpoint:
f9bf01c6 1293 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
9dae56ea
A
1294 return;
1295 }
1296}
9dae56ea 1297
4e4e5a6f 1298#if ENABLE(INTERPRETER)
9dae56ea
A
1299NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
1300{
f9bf01c6 1301 int dst = vPC[1].u.operand;
9dae56ea 1302 CodeBlock* codeBlock = callFrame->codeBlock();
f9bf01c6
A
1303 Identifier& property = codeBlock->identifier(vPC[2].u.operand);
1304 JSValue value = callFrame->r(vPC[3].u.operand).jsValue();
9dae56ea 1305 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
14957cd0 1306 callFrame->uncheckedR(dst) = JSValue(scope);
9dae56ea
A
1307
1308 return callFrame->scopeChain()->push(scope);
1309}
1310
ba379fdc 1311NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot)
9dae56ea
A
1312{
1313 // Recursive invocation may already have specialized this instruction.
1314 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1315 return;
1316
1317 if (!baseValue.isCell())
1318 return;
1319
1320 // Uncacheable: give up.
1321 if (!slot.isCacheable()) {
1322 vPC[0] = getOpcode(op_put_by_id_generic);
1323 return;
1324 }
1325
14957cd0 1326 JSCell* baseCell = baseValue.asCell();
9dae56ea
A
1327 Structure* structure = baseCell->structure();
1328
14957cd0 1329 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
9dae56ea
A
1330 vPC[0] = getOpcode(op_put_by_id_generic);
1331 return;
1332 }
1333
1334 // Cache miss: record Structure to compare against next time.
14957cd0 1335 Structure* lastStructure = vPC[4].u.structure.get();
9dae56ea
A
1336 if (structure != lastStructure) {
1337 // First miss: record Structure to compare against next time.
1338 if (!lastStructure) {
14957cd0 1339 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
9dae56ea
A
1340 return;
1341 }
1342
1343 // Second miss: give up.
1344 vPC[0] = getOpcode(op_put_by_id_generic);
1345 return;
1346 }
1347
1348 // Cache hit: Specialize instruction and ref Structures.
1349
1350 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1351 if (baseCell != slot.base()) {
1352 vPC[0] = getOpcode(op_put_by_id_generic);
1353 return;
1354 }
1355
1356 // Structure transition, cache transition info
1357 if (slot.type() == PutPropertySlot::NewProperty) {
ba379fdc
A
1358 if (structure->isDictionary()) {
1359 vPC[0] = getOpcode(op_put_by_id_generic);
1360 return;
1361 }
f9bf01c6
A
1362
1363 // put_by_id_transition checks the prototype chain for setters.
1364 normalizePrototypeChain(callFrame, baseCell);
14957cd0
A
1365 JSCell* owner = codeBlock->ownerExecutable();
1366 JSGlobalData& globalData = callFrame->globalData();
1367 // Get the prototype here because the call to prototypeChain could cause a
1368 // GC allocation, which we don't want to happen while we're in the middle of
1369 // initializing the union.
1370 StructureChain* prototypeChain = structure->prototypeChain(callFrame);
9dae56ea 1371 vPC[0] = getOpcode(op_put_by_id_transition);
14957cd0
A
1372 vPC[4].u.structure.set(globalData, owner, structure->previousID());
1373 vPC[5].u.structure.set(globalData, owner, structure);
1374 vPC[6].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), prototypeChain);
1375 ASSERT(vPC[6].u.structureChain);
9dae56ea 1376 vPC[7] = slot.cachedOffset();
9dae56ea
A
1377 return;
1378 }
1379
1380 vPC[0] = getOpcode(op_put_by_id_replace);
1381 vPC[5] = slot.cachedOffset();
9dae56ea
A
1382}
1383
14957cd0 1384NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock*, Instruction* vPC)
9dae56ea 1385{
9dae56ea
A
1386 vPC[0] = getOpcode(op_put_by_id);
1387 vPC[4] = 0;
1388}
1389
ba379fdc 1390NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)
9dae56ea
A
1391{
1392 // Recursive invocation may already have specialized this instruction.
1393 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1394 return;
1395
1396 // FIXME: Cache property access for immediates.
1397 if (!baseValue.isCell()) {
1398 vPC[0] = getOpcode(op_get_by_id_generic);
1399 return;
1400 }
1401
ba379fdc
A
1402 JSGlobalData* globalData = &callFrame->globalData();
1403 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
9dae56ea
A
1404 vPC[0] = getOpcode(op_get_array_length);
1405 return;
1406 }
1407
ba379fdc 1408 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
9dae56ea
A
1409 vPC[0] = getOpcode(op_get_string_length);
1410 return;
1411 }
1412
1413 // Uncacheable: give up.
1414 if (!slot.isCacheable()) {
1415 vPC[0] = getOpcode(op_get_by_id_generic);
1416 return;
1417 }
1418
14957cd0 1419 Structure* structure = baseValue.asCell()->structure();
9dae56ea 1420
14957cd0 1421 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
9dae56ea
A
1422 vPC[0] = getOpcode(op_get_by_id_generic);
1423 return;
1424 }
1425
1426 // Cache miss
14957cd0 1427 Structure* lastStructure = vPC[4].u.structure.get();
9dae56ea
A
1428 if (structure != lastStructure) {
1429 // First miss: record Structure to compare against next time.
1430 if (!lastStructure) {
14957cd0 1431 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
9dae56ea
A
1432 return;
1433 }
1434
1435 // Second miss: give up.
1436 vPC[0] = getOpcode(op_get_by_id_generic);
1437 return;
1438 }
1439
1440 // Cache hit: Specialize instruction and ref Structures.
1441
1442 if (slot.slotBase() == baseValue) {
4e4e5a6f
A
1443 switch (slot.cachedPropertyType()) {
1444 case PropertySlot::Getter:
1445 vPC[0] = getOpcode(op_get_by_id_getter_self);
1446 vPC[5] = slot.cachedOffset();
1447 break;
1448 case PropertySlot::Custom:
1449 vPC[0] = getOpcode(op_get_by_id_custom_self);
1450 vPC[5] = slot.customGetter();
1451 break;
1452 default:
1453 vPC[0] = getOpcode(op_get_by_id_self);
1454 vPC[5] = slot.cachedOffset();
1455 break;
1456 }
9dae56ea
A
1457 return;
1458 }
1459
ba379fdc
A
1460 if (structure->isDictionary()) {
1461 vPC[0] = getOpcode(op_get_by_id_generic);
1462 return;
1463 }
1464
9dae56ea
A
1465 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
1466 ASSERT(slot.slotBase().isObject());
1467
1468 JSObject* baseObject = asObject(slot.slotBase());
ba379fdc 1469 size_t offset = slot.cachedOffset();
9dae56ea
A
1470
1471 // Since we're accessing a prototype in a loop, it's a good bet that it
1472 // should not be treated as a dictionary.
ba379fdc 1473 if (baseObject->structure()->isDictionary()) {
14957cd0
A
1474 baseObject->flattenDictionaryObject(callFrame->globalData());
1475 offset = baseObject->structure()->get(callFrame->globalData(), propertyName);
ba379fdc
A
1476 }
1477
1478 ASSERT(!baseObject->structure()->isUncacheableDictionary());
4e4e5a6f
A
1479
1480 switch (slot.cachedPropertyType()) {
1481 case PropertySlot::Getter:
1482 vPC[0] = getOpcode(op_get_by_id_getter_proto);
1483 vPC[6] = offset;
1484 break;
1485 case PropertySlot::Custom:
1486 vPC[0] = getOpcode(op_get_by_id_custom_proto);
1487 vPC[6] = slot.customGetter();
1488 break;
1489 default:
1490 vPC[0] = getOpcode(op_get_by_id_proto);
1491 vPC[6] = offset;
1492 break;
1493 }
14957cd0 1494 vPC[5].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), baseObject->structure());
9dae56ea
A
1495 return;
1496 }
1497
ba379fdc
A
1498 size_t offset = slot.cachedOffset();
1499 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
9dae56ea
A
1500 if (!count) {
1501 vPC[0] = getOpcode(op_get_by_id_generic);
1502 return;
1503 }
1504
4e4e5a6f
A
1505
1506 switch (slot.cachedPropertyType()) {
1507 case PropertySlot::Getter:
1508 vPC[0] = getOpcode(op_get_by_id_getter_chain);
1509 vPC[7] = offset;
1510 break;
1511 case PropertySlot::Custom:
1512 vPC[0] = getOpcode(op_get_by_id_custom_chain);
1513 vPC[7] = slot.customGetter();
1514 break;
1515 default:
1516 vPC[0] = getOpcode(op_get_by_id_chain);
1517 vPC[7] = offset;
1518 break;
1519 }
14957cd0
A
1520 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1521 vPC[5].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure->prototypeChain(callFrame));
9dae56ea 1522 vPC[6] = count;
9dae56ea
A
1523}
1524
14957cd0 1525NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock*, Instruction* vPC)
9dae56ea 1526{
9dae56ea
A
1527 vPC[0] = getOpcode(op_get_by_id);
1528 vPC[4] = 0;
1529}
1530
4e4e5a6f 1531#endif // ENABLE(INTERPRETER)
ba379fdc 1532
14957cd0 1533JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame)
9dae56ea
A
1534{
1535 // One-time initialization of our address tables. We have to put this code
1536 // here because our labels are only in scope inside this function.
ba379fdc 1537 if (UNLIKELY(flag == InitializeAndReturn)) {
4e4e5a6f 1538 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
ba379fdc
A
1539 #define LIST_OPCODE_LABEL(id, length) &&id,
1540 static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) };
14957cd0 1541 for (size_t i = 0; i < WTF_ARRAY_LENGTH(labels); ++i)
ba379fdc
A
1542 m_opcodeTable[i] = labels[i];
1543 #undef LIST_OPCODE_LABEL
4e4e5a6f 1544 #endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
ba379fdc 1545 return JSValue();
9dae56ea 1546 }
4e4e5a6f 1547
9dae56ea 1548#if ENABLE(JIT)
4e4e5a6f 1549#if ENABLE(INTERPRETER)
ba379fdc 1550 // Mixing Interpreter + JIT is not supported.
4e4e5a6f
A
1551 if (callFrame->globalData().canUseJIT())
1552#endif
1553 ASSERT_NOT_REACHED();
9dae56ea 1554#endif
4e4e5a6f
A
1555
1556#if !ENABLE(INTERPRETER)
ba379fdc
A
1557 UNUSED_PARAM(registerFile);
1558 UNUSED_PARAM(callFrame);
ba379fdc
A
1559 return JSValue();
1560#else
9dae56ea
A
1561
1562 JSGlobalData* globalData = &callFrame->globalData();
ba379fdc 1563 JSValue exceptionValue;
9dae56ea
A
1564 HandlerInfo* handler = 0;
1565
14957cd0
A
1566 CodeBlock* codeBlock = callFrame->codeBlock();
1567 Instruction* vPC = codeBlock->instructions().begin();
9dae56ea 1568 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
ba379fdc 1569 unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();
14957cd0 1570 JSValue functionReturnValue;
9dae56ea
A
1571
1572#define CHECK_FOR_EXCEPTION() \
1573 do { \
ba379fdc 1574 if (UNLIKELY(globalData->exception != JSValue())) { \
9dae56ea
A
1575 exceptionValue = globalData->exception; \
1576 goto vm_throw; \
1577 } \
1578 } while (0)
1579
1580#if ENABLE(OPCODE_STATS)
1581 OpcodeStats::resetLastInstruction();
1582#endif
1583
1584#define CHECK_FOR_TIMEOUT() \
1585 if (!--tickCount) { \
4e4e5a6f 1586 if (globalData->terminator.shouldTerminate() || globalData->timeoutChecker.didTimeOut(callFrame)) { \
9dae56ea
A
1587 exceptionValue = jsNull(); \
1588 goto vm_throw; \
1589 } \
ba379fdc 1590 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
9dae56ea
A
1591 }
1592
1593#if ENABLE(OPCODE_SAMPLING)
1594 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
9dae56ea
A
1595#else
1596 #define SAMPLE(codeBlock, vPC)
9dae56ea
A
1597#endif
1598
4e4e5a6f 1599#if ENABLE(COMPUTED_GOTO_INTERPRETER)
14957cd0 1600 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode
9dae56ea
A
1601#if ENABLE(OPCODE_STATS)
1602 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1603#else
1604 #define DEFINE_OPCODE(opcode) opcode:
1605#endif
1606 NEXT_INSTRUCTION();
1607#else
14957cd0 1608 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart
9dae56ea
A
1609#if ENABLE(OPCODE_STATS)
1610 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1611#else
1612 #define DEFINE_OPCODE(opcode) case opcode:
1613#endif
1614 while (1) { // iterator loop begins
1615 interpreterLoopStart:;
1616 switch (vPC->u.opcode)
1617#endif
1618 {
1619 DEFINE_OPCODE(op_new_object) {
1620 /* new_object dst(r)
1621
1622 Constructs a new empty Object instance using the original
1623 constructor, and puts the result in register dst.
1624 */
f9bf01c6 1625 int dst = vPC[1].u.operand;
14957cd0 1626 callFrame->uncheckedR(dst) = JSValue(constructEmptyObject(callFrame));
9dae56ea 1627
f9bf01c6 1628 vPC += OPCODE_LENGTH(op_new_object);
9dae56ea
A
1629 NEXT_INSTRUCTION();
1630 }
1631 DEFINE_OPCODE(op_new_array) {
1632 /* new_array dst(r) firstArg(r) argCount(n)
1633
1634 Constructs a new Array instance using the original
1635 constructor, and puts the result in register dst.
1636 The array will contain argCount elements with values
1637 taken from registers starting at register firstArg.
1638 */
f9bf01c6
A
1639 int dst = vPC[1].u.operand;
1640 int firstArg = vPC[2].u.operand;
1641 int argCount = vPC[3].u.operand;
9dae56ea 1642 ArgList args(callFrame->registers() + firstArg, argCount);
14957cd0 1643 callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, args));
9dae56ea 1644
f9bf01c6 1645 vPC += OPCODE_LENGTH(op_new_array);
9dae56ea
A
1646 NEXT_INSTRUCTION();
1647 }
14957cd0
A
1648 DEFINE_OPCODE(op_new_array_buffer) {
1649 /* new_array_buffer dst(r) index(n) argCount(n)
1650
1651 Constructs a new Array instance using the original
1652 constructor, and puts the result in register dst.
1653 The array be initialized with the values from constantBuffer[index]
1654 */
1655 int dst = vPC[1].u.operand;
1656 int firstArg = vPC[2].u.operand;
1657 int argCount = vPC[3].u.operand;
1658 ArgList args(codeBlock->constantBuffer(firstArg), argCount);
1659 callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, args));
1660
1661 vPC += OPCODE_LENGTH(op_new_array);
1662 NEXT_INSTRUCTION();
1663 }
9dae56ea
A
1664 DEFINE_OPCODE(op_new_regexp) {
1665 /* new_regexp dst(r) regExp(re)
1666
1667 Constructs a new RegExp instance using the original
1668 constructor from regexp regExp, and puts the result in
1669 register dst.
1670 */
f9bf01c6 1671 int dst = vPC[1].u.operand;
14957cd0
A
1672 RegExp* regExp = codeBlock->regexp(vPC[2].u.operand);
1673 if (!regExp->isValid()) {
1674 exceptionValue = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor.");
1675 goto vm_throw;
1676 }
1677 callFrame->uncheckedR(dst) = JSValue(new (globalData) RegExpObject(callFrame->lexicalGlobalObject(), callFrame->scopeChain()->globalObject->regExpStructure(), regExp));
9dae56ea 1678
f9bf01c6 1679 vPC += OPCODE_LENGTH(op_new_regexp);
9dae56ea
A
1680 NEXT_INSTRUCTION();
1681 }
1682 DEFINE_OPCODE(op_mov) {
1683 /* mov dst(r) src(r)
1684
1685 Copies register src to register dst.
1686 */
f9bf01c6
A
1687 int dst = vPC[1].u.operand;
1688 int src = vPC[2].u.operand;
14957cd0
A
1689
1690 callFrame->uncheckedR(dst) = callFrame->r(src);
9dae56ea 1691
f9bf01c6 1692 vPC += OPCODE_LENGTH(op_mov);
9dae56ea
A
1693 NEXT_INSTRUCTION();
1694 }
1695 DEFINE_OPCODE(op_eq) {
1696 /* eq dst(r) src1(r) src2(r)
1697
1698 Checks whether register src1 and register src2 are equal,
1699 as with the ECMAScript '==' operator, and puts the result
1700 as a boolean in register dst.
1701 */
f9bf01c6
A
1702 int dst = vPC[1].u.operand;
1703 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1704 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 1705 if (src1.isInt32() && src2.isInt32())
14957cd0 1706 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
9dae56ea 1707 else {
ba379fdc 1708 JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));
9dae56ea 1709 CHECK_FOR_EXCEPTION();
14957cd0 1710 callFrame->uncheckedR(dst) = result;
9dae56ea
A
1711 }
1712
f9bf01c6 1713 vPC += OPCODE_LENGTH(op_eq);
9dae56ea
A
1714 NEXT_INSTRUCTION();
1715 }
1716 DEFINE_OPCODE(op_eq_null) {
1717 /* eq_null dst(r) src(r)
1718
1719 Checks whether register src is null, as with the ECMAScript '!='
1720 operator, and puts the result as a boolean in register dst.
1721 */
f9bf01c6
A
1722 int dst = vPC[1].u.operand;
1723 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
9dae56ea
A
1724
1725 if (src.isUndefinedOrNull()) {
14957cd0 1726 callFrame->uncheckedR(dst) = jsBoolean(true);
f9bf01c6 1727 vPC += OPCODE_LENGTH(op_eq_null);
9dae56ea
A
1728 NEXT_INSTRUCTION();
1729 }
1730
14957cd0 1731 callFrame->uncheckedR(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
f9bf01c6 1732 vPC += OPCODE_LENGTH(op_eq_null);
9dae56ea
A
1733 NEXT_INSTRUCTION();
1734 }
1735 DEFINE_OPCODE(op_neq) {
1736 /* neq dst(r) src1(r) src2(r)
1737
1738 Checks whether register src1 and register src2 are not
1739 equal, as with the ECMAScript '!=' operator, and puts the
1740 result as a boolean in register dst.
1741 */
f9bf01c6
A
1742 int dst = vPC[1].u.operand;
1743 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1744 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 1745 if (src1.isInt32() && src2.isInt32())
14957cd0 1746 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
9dae56ea 1747 else {
ba379fdc 1748 JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));
9dae56ea 1749 CHECK_FOR_EXCEPTION();
14957cd0 1750 callFrame->uncheckedR(dst) = result;
9dae56ea
A
1751 }
1752
f9bf01c6 1753 vPC += OPCODE_LENGTH(op_neq);
9dae56ea
A
1754 NEXT_INSTRUCTION();
1755 }
1756 DEFINE_OPCODE(op_neq_null) {
1757 /* neq_null dst(r) src(r)
1758
1759 Checks whether register src is not null, as with the ECMAScript '!='
1760 operator, and puts the result as a boolean in register dst.
1761 */
f9bf01c6
A
1762 int dst = vPC[1].u.operand;
1763 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
9dae56ea
A
1764
1765 if (src.isUndefinedOrNull()) {
14957cd0 1766 callFrame->uncheckedR(dst) = jsBoolean(false);
f9bf01c6 1767 vPC += OPCODE_LENGTH(op_neq_null);
9dae56ea
A
1768 NEXT_INSTRUCTION();
1769 }
1770
14957cd0 1771 callFrame->uncheckedR(dst) = jsBoolean(!src.isCell() || !src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
f9bf01c6 1772 vPC += OPCODE_LENGTH(op_neq_null);
9dae56ea
A
1773 NEXT_INSTRUCTION();
1774 }
1775 DEFINE_OPCODE(op_stricteq) {
1776 /* stricteq dst(r) src1(r) src2(r)
1777
1778 Checks whether register src1 and register src2 are strictly
1779 equal, as with the ECMAScript '===' operator, and puts the
1780 result as a boolean in register dst.
1781 */
f9bf01c6
A
1782 int dst = vPC[1].u.operand;
1783 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1784 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
4e4e5a6f
A
1785 bool result = JSValue::strictEqual(callFrame, src1, src2);
1786 CHECK_FOR_EXCEPTION();
14957cd0 1787 callFrame->uncheckedR(dst) = jsBoolean(result);
9dae56ea 1788
f9bf01c6 1789 vPC += OPCODE_LENGTH(op_stricteq);
9dae56ea
A
1790 NEXT_INSTRUCTION();
1791 }
1792 DEFINE_OPCODE(op_nstricteq) {
1793 /* nstricteq dst(r) src1(r) src2(r)
1794
1795 Checks whether register src1 and register src2 are not
1796 strictly equal, as with the ECMAScript '!==' operator, and
1797 puts the result as a boolean in register dst.
1798 */
f9bf01c6
A
1799 int dst = vPC[1].u.operand;
1800 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1801 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
4e4e5a6f
A
1802 bool result = !JSValue::strictEqual(callFrame, src1, src2);
1803 CHECK_FOR_EXCEPTION();
14957cd0 1804 callFrame->uncheckedR(dst) = jsBoolean(result);
9dae56ea 1805
f9bf01c6 1806 vPC += OPCODE_LENGTH(op_nstricteq);
9dae56ea
A
1807 NEXT_INSTRUCTION();
1808 }
1809 DEFINE_OPCODE(op_less) {
1810 /* less dst(r) src1(r) src2(r)
1811
1812 Checks whether register src1 is less than register src2, as
1813 with the ECMAScript '<' operator, and puts the result as
1814 a boolean in register dst.
1815 */
f9bf01c6
A
1816 int dst = vPC[1].u.operand;
1817 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1818 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 1819 JSValue result = jsBoolean(jsLess(callFrame, src1, src2));
9dae56ea 1820 CHECK_FOR_EXCEPTION();
14957cd0 1821 callFrame->uncheckedR(dst) = result;
9dae56ea 1822
f9bf01c6 1823 vPC += OPCODE_LENGTH(op_less);
9dae56ea
A
1824 NEXT_INSTRUCTION();
1825 }
1826 DEFINE_OPCODE(op_lesseq) {
1827 /* lesseq dst(r) src1(r) src2(r)
1828
1829 Checks whether register src1 is less than or equal to
1830 register src2, as with the ECMAScript '<=' operator, and
1831 puts the result as a boolean in register dst.
1832 */
f9bf01c6
A
1833 int dst = vPC[1].u.operand;
1834 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1835 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 1836 JSValue result = jsBoolean(jsLessEq(callFrame, src1, src2));
9dae56ea 1837 CHECK_FOR_EXCEPTION();
14957cd0 1838 callFrame->uncheckedR(dst) = result;
9dae56ea 1839
f9bf01c6 1840 vPC += OPCODE_LENGTH(op_lesseq);
9dae56ea
A
1841 NEXT_INSTRUCTION();
1842 }
1843 DEFINE_OPCODE(op_pre_inc) {
1844 /* pre_inc srcDst(r)
1845
1846 Converts register srcDst to number, adds one, and puts the result
1847 back in register srcDst.
1848 */
f9bf01c6 1849 int srcDst = vPC[1].u.operand;
ba379fdc
A
1850 JSValue v = callFrame->r(srcDst).jsValue();
1851 if (v.isInt32() && v.asInt32() < INT_MAX)
14957cd0 1852 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
9dae56ea 1853 else {
14957cd0 1854 JSValue result = jsNumber(v.toNumber(callFrame) + 1);
9dae56ea 1855 CHECK_FOR_EXCEPTION();
14957cd0 1856 callFrame->uncheckedR(srcDst) = result;
9dae56ea
A
1857 }
1858
f9bf01c6 1859 vPC += OPCODE_LENGTH(op_pre_inc);
9dae56ea
A
1860 NEXT_INSTRUCTION();
1861 }
1862 DEFINE_OPCODE(op_pre_dec) {
1863 /* pre_dec srcDst(r)
1864
1865 Converts register srcDst to number, subtracts one, and puts the result
1866 back in register srcDst.
1867 */
f9bf01c6 1868 int srcDst = vPC[1].u.operand;
ba379fdc
A
1869 JSValue v = callFrame->r(srcDst).jsValue();
1870 if (v.isInt32() && v.asInt32() > INT_MIN)
14957cd0 1871 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
9dae56ea 1872 else {
14957cd0 1873 JSValue result = jsNumber(v.toNumber(callFrame) - 1);
9dae56ea 1874 CHECK_FOR_EXCEPTION();
14957cd0 1875 callFrame->uncheckedR(srcDst) = result;
9dae56ea
A
1876 }
1877
f9bf01c6 1878 vPC += OPCODE_LENGTH(op_pre_dec);
9dae56ea
A
1879 NEXT_INSTRUCTION();
1880 }
1881 DEFINE_OPCODE(op_post_inc) {
1882 /* post_inc dst(r) srcDst(r)
1883
1884 Converts register srcDst to number. The number itself is
1885 written to register dst, and the number plus one is written
1886 back to register srcDst.
1887 */
f9bf01c6
A
1888 int dst = vPC[1].u.operand;
1889 int srcDst = vPC[2].u.operand;
ba379fdc
A
1890 JSValue v = callFrame->r(srcDst).jsValue();
1891 if (v.isInt32() && v.asInt32() < INT_MAX) {
14957cd0
A
1892 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
1893 callFrame->uncheckedR(dst) = v;
9dae56ea 1894 } else {
ba379fdc 1895 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
9dae56ea 1896 CHECK_FOR_EXCEPTION();
14957cd0
A
1897 callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() + 1);
1898 callFrame->uncheckedR(dst) = number;
9dae56ea
A
1899 }
1900
f9bf01c6 1901 vPC += OPCODE_LENGTH(op_post_inc);
9dae56ea
A
1902 NEXT_INSTRUCTION();
1903 }
1904 DEFINE_OPCODE(op_post_dec) {
1905 /* post_dec dst(r) srcDst(r)
1906
1907 Converts register srcDst to number. The number itself is
1908 written to register dst, and the number minus one is written
1909 back to register srcDst.
1910 */
f9bf01c6
A
1911 int dst = vPC[1].u.operand;
1912 int srcDst = vPC[2].u.operand;
ba379fdc
A
1913 JSValue v = callFrame->r(srcDst).jsValue();
1914 if (v.isInt32() && v.asInt32() > INT_MIN) {
14957cd0
A
1915 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
1916 callFrame->uncheckedR(dst) = v;
9dae56ea 1917 } else {
ba379fdc 1918 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
9dae56ea 1919 CHECK_FOR_EXCEPTION();
14957cd0
A
1920 callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() - 1);
1921 callFrame->uncheckedR(dst) = number;
9dae56ea
A
1922 }
1923
f9bf01c6 1924 vPC += OPCODE_LENGTH(op_post_dec);
9dae56ea
A
1925 NEXT_INSTRUCTION();
1926 }
1927 DEFINE_OPCODE(op_to_jsnumber) {
1928 /* to_jsnumber dst(r) src(r)
1929
1930 Converts register src to number, and puts the result
1931 in register dst.
1932 */
f9bf01c6
A
1933 int dst = vPC[1].u.operand;
1934 int src = vPC[2].u.operand;
9dae56ea 1935
ba379fdc 1936 JSValue srcVal = callFrame->r(src).jsValue();
9dae56ea
A
1937
1938 if (LIKELY(srcVal.isNumber()))
14957cd0 1939 callFrame->uncheckedR(dst) = callFrame->r(src);
9dae56ea 1940 else {
ba379fdc 1941 JSValue result = srcVal.toJSNumber(callFrame);
9dae56ea 1942 CHECK_FOR_EXCEPTION();
14957cd0 1943 callFrame->uncheckedR(dst) = result;
9dae56ea
A
1944 }
1945
f9bf01c6 1946 vPC += OPCODE_LENGTH(op_to_jsnumber);
9dae56ea
A
1947 NEXT_INSTRUCTION();
1948 }
1949 DEFINE_OPCODE(op_negate) {
1950 /* negate dst(r) src(r)
1951
1952 Converts register src to number, negates it, and puts the
1953 result in register dst.
1954 */
f9bf01c6
A
1955 int dst = vPC[1].u.operand;
1956 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
4e4e5a6f 1957 if (src.isInt32() && (src.asInt32() & 0x7fffffff)) // non-zero and no overflow
14957cd0 1958 callFrame->uncheckedR(dst) = jsNumber(-src.asInt32());
9dae56ea 1959 else {
14957cd0 1960 JSValue result = jsNumber(-src.toNumber(callFrame));
9dae56ea 1961 CHECK_FOR_EXCEPTION();
14957cd0 1962 callFrame->uncheckedR(dst) = result;
9dae56ea
A
1963 }
1964
f9bf01c6 1965 vPC += OPCODE_LENGTH(op_negate);
9dae56ea
A
1966 NEXT_INSTRUCTION();
1967 }
1968 DEFINE_OPCODE(op_add) {
1969 /* add dst(r) src1(r) src2(r)
1970
1971 Adds register src1 and register src2, and puts the result
1972 in register dst. (JS add may be string concatenation or
1973 numeric add, depending on the types of the operands.)
1974 */
f9bf01c6
A
1975 int dst = vPC[1].u.operand;
1976 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1977 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1978 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
14957cd0 1979 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() + src2.asInt32());
9dae56ea 1980 else {
ba379fdc 1981 JSValue result = jsAdd(callFrame, src1, src2);
9dae56ea 1982 CHECK_FOR_EXCEPTION();
14957cd0 1983 callFrame->uncheckedR(dst) = result;
9dae56ea 1984 }
f9bf01c6 1985 vPC += OPCODE_LENGTH(op_add);
9dae56ea
A
1986 NEXT_INSTRUCTION();
1987 }
1988 DEFINE_OPCODE(op_mul) {
1989 /* mul dst(r) src1(r) src2(r)
1990
1991 Multiplies register src1 and register src2 (converted to
1992 numbers), and puts the product in register dst.
1993 */
f9bf01c6
A
1994 int dst = vPC[1].u.operand;
1995 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1996 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 1997 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
14957cd0 1998 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() * src2.asInt32());
9dae56ea 1999 else {
14957cd0 2000 JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame));
9dae56ea 2001 CHECK_FOR_EXCEPTION();
14957cd0 2002 callFrame->uncheckedR(dst) = result;
9dae56ea
A
2003 }
2004
f9bf01c6 2005 vPC += OPCODE_LENGTH(op_mul);
9dae56ea
A
2006 NEXT_INSTRUCTION();
2007 }
2008 DEFINE_OPCODE(op_div) {
2009 /* div dst(r) dividend(r) divisor(r)
2010
2011 Divides register dividend (converted to number) by the
2012 register divisor (converted to number), and puts the
2013 quotient in register dst.
2014 */
f9bf01c6
A
2015 int dst = vPC[1].u.operand;
2016 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
2017 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 2018
14957cd0 2019 JSValue result = jsNumber(dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
ba379fdc 2020 CHECK_FOR_EXCEPTION();
14957cd0 2021 callFrame->uncheckedR(dst) = result;
ba379fdc 2022
f9bf01c6 2023 vPC += OPCODE_LENGTH(op_div);
9dae56ea
A
2024 NEXT_INSTRUCTION();
2025 }
2026 DEFINE_OPCODE(op_mod) {
2027 /* mod dst(r) dividend(r) divisor(r)
2028
2029 Divides register dividend (converted to number) by
2030 register divisor (converted to number), and puts the
2031 remainder in register dst.
2032 */
f9bf01c6
A
2033 int dst = vPC[1].u.operand;
2034 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
2035 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
9dae56ea 2036
ba379fdc 2037 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
14957cd0 2038 JSValue result = jsNumber(dividend.asInt32() % divisor.asInt32());
9dae56ea 2039 ASSERT(result);
14957cd0 2040 callFrame->uncheckedR(dst) = result;
f9bf01c6 2041 vPC += OPCODE_LENGTH(op_mod);
9dae56ea
A
2042 NEXT_INSTRUCTION();
2043 }
2044
ba379fdc
A
2045 // Conversion to double must happen outside the call to fmod since the
2046 // order of argument evaluation is not guaranteed.
2047 double d1 = dividend.toNumber(callFrame);
2048 double d2 = divisor.toNumber(callFrame);
14957cd0 2049 JSValue result = jsNumber(fmod(d1, d2));
9dae56ea 2050 CHECK_FOR_EXCEPTION();
14957cd0 2051 callFrame->uncheckedR(dst) = result;
f9bf01c6 2052 vPC += OPCODE_LENGTH(op_mod);
9dae56ea
A
2053 NEXT_INSTRUCTION();
2054 }
2055 DEFINE_OPCODE(op_sub) {
2056 /* sub dst(r) src1(r) src2(r)
2057
2058 Subtracts register src2 (converted to number) from register
2059 src1 (converted to number), and puts the difference in
2060 register dst.
2061 */
f9bf01c6
A
2062 int dst = vPC[1].u.operand;
2063 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2064 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2065 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
14957cd0 2066 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() - src2.asInt32());
9dae56ea 2067 else {
14957cd0 2068 JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame));
9dae56ea 2069 CHECK_FOR_EXCEPTION();
14957cd0 2070 callFrame->uncheckedR(dst) = result;
9dae56ea 2071 }
f9bf01c6 2072 vPC += OPCODE_LENGTH(op_sub);
9dae56ea
A
2073 NEXT_INSTRUCTION();
2074 }
2075 DEFINE_OPCODE(op_lshift) {
2076 /* lshift dst(r) val(r) shift(r)
2077
2078 Performs left shift of register val (converted to int32) by
2079 register shift (converted to uint32), and puts the result
2080 in register dst.
2081 */
f9bf01c6
A
2082 int dst = vPC[1].u.operand;
2083 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
2084 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc
A
2085
2086 if (val.isInt32() && shift.isInt32())
14957cd0 2087 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() << (shift.asInt32() & 0x1f));
9dae56ea 2088 else {
14957cd0 2089 JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
9dae56ea 2090 CHECK_FOR_EXCEPTION();
14957cd0 2091 callFrame->uncheckedR(dst) = result;
9dae56ea
A
2092 }
2093
f9bf01c6 2094 vPC += OPCODE_LENGTH(op_lshift);
9dae56ea
A
2095 NEXT_INSTRUCTION();
2096 }
2097 DEFINE_OPCODE(op_rshift) {
2098 /* rshift dst(r) val(r) shift(r)
2099
2100 Performs arithmetic right shift of register val (converted
2101 to int32) by register shift (converted to
2102 uint32), and puts the result in register dst.
2103 */
f9bf01c6
A
2104 int dst = vPC[1].u.operand;
2105 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
2106 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc
A
2107
2108 if (val.isInt32() && shift.isInt32())
14957cd0 2109 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
9dae56ea 2110 else {
14957cd0 2111 JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
9dae56ea 2112 CHECK_FOR_EXCEPTION();
14957cd0 2113 callFrame->uncheckedR(dst) = result;
9dae56ea
A
2114 }
2115
f9bf01c6 2116 vPC += OPCODE_LENGTH(op_rshift);
9dae56ea
A
2117 NEXT_INSTRUCTION();
2118 }
2119 DEFINE_OPCODE(op_urshift) {
2120 /* rshift dst(r) val(r) shift(r)
2121
2122 Performs logical right shift of register val (converted
2123 to uint32) by register shift (converted to
2124 uint32), and puts the result in register dst.
2125 */
f9bf01c6
A
2126 int dst = vPC[1].u.operand;
2127 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
2128 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 2129 if (val.isUInt32() && shift.isInt32())
14957cd0 2130 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
9dae56ea 2131 else {
14957cd0 2132 JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
9dae56ea 2133 CHECK_FOR_EXCEPTION();
14957cd0 2134 callFrame->uncheckedR(dst) = result;
9dae56ea
A
2135 }
2136
f9bf01c6 2137 vPC += OPCODE_LENGTH(op_urshift);
9dae56ea
A
2138 NEXT_INSTRUCTION();
2139 }
2140 DEFINE_OPCODE(op_bitand) {
2141 /* bitand dst(r) src1(r) src2(r)
2142
2143 Computes bitwise AND of register src1 (converted to int32)
2144 and register src2 (converted to int32), and puts the result
2145 in register dst.
2146 */
f9bf01c6
A
2147 int dst = vPC[1].u.operand;
2148 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2149 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 2150 if (src1.isInt32() && src2.isInt32())
14957cd0 2151 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() & src2.asInt32());
9dae56ea 2152 else {
14957cd0 2153 JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame));
9dae56ea 2154 CHECK_FOR_EXCEPTION();
14957cd0 2155 callFrame->uncheckedR(dst) = result;
9dae56ea
A
2156 }
2157
f9bf01c6 2158 vPC += OPCODE_LENGTH(op_bitand);
9dae56ea
A
2159 NEXT_INSTRUCTION();
2160 }
2161 DEFINE_OPCODE(op_bitxor) {
2162 /* bitxor dst(r) src1(r) src2(r)
2163
2164 Computes bitwise XOR of register src1 (converted to int32)
2165 and register src2 (converted to int32), and puts the result
2166 in register dst.
2167 */
f9bf01c6
A
2168 int dst = vPC[1].u.operand;
2169 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2170 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 2171 if (src1.isInt32() && src2.isInt32())
14957cd0 2172 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() ^ src2.asInt32());
9dae56ea 2173 else {
14957cd0 2174 JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
9dae56ea 2175 CHECK_FOR_EXCEPTION();
14957cd0 2176 callFrame->uncheckedR(dst) = result;
9dae56ea
A
2177 }
2178
f9bf01c6 2179 vPC += OPCODE_LENGTH(op_bitxor);
9dae56ea
A
2180 NEXT_INSTRUCTION();
2181 }
2182 DEFINE_OPCODE(op_bitor) {
2183 /* bitor dst(r) src1(r) src2(r)
2184
2185 Computes bitwise OR of register src1 (converted to int32)
2186 and register src2 (converted to int32), and puts the
2187 result in register dst.
2188 */
f9bf01c6
A
2189 int dst = vPC[1].u.operand;
2190 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2191 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 2192 if (src1.isInt32() && src2.isInt32())
14957cd0 2193 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() | src2.asInt32());
9dae56ea 2194 else {
14957cd0 2195 JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));
9dae56ea 2196 CHECK_FOR_EXCEPTION();
14957cd0 2197 callFrame->uncheckedR(dst) = result;
9dae56ea
A
2198 }
2199
f9bf01c6 2200 vPC += OPCODE_LENGTH(op_bitor);
9dae56ea
A
2201 NEXT_INSTRUCTION();
2202 }
2203 DEFINE_OPCODE(op_bitnot) {
2204 /* bitnot dst(r) src(r)
2205
2206 Computes bitwise NOT of register src1 (converted to int32),
2207 and puts the result in register dst.
2208 */
f9bf01c6
A
2209 int dst = vPC[1].u.operand;
2210 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
ba379fdc 2211 if (src.isInt32())
14957cd0 2212 callFrame->uncheckedR(dst) = jsNumber(~src.asInt32());
9dae56ea 2213 else {
14957cd0 2214 JSValue result = jsNumber(~src.toInt32(callFrame));
9dae56ea 2215 CHECK_FOR_EXCEPTION();
14957cd0 2216 callFrame->uncheckedR(dst) = result;
9dae56ea 2217 }
f9bf01c6 2218 vPC += OPCODE_LENGTH(op_bitnot);
9dae56ea
A
2219 NEXT_INSTRUCTION();
2220 }
2221 DEFINE_OPCODE(op_not) {
2222 /* not dst(r) src(r)
2223
2224 Computes logical NOT of register src (converted to
2225 boolean), and puts the result in register dst.
2226 */
f9bf01c6
A
2227 int dst = vPC[1].u.operand;
2228 int src = vPC[2].u.operand;
ba379fdc 2229 JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));
9dae56ea 2230 CHECK_FOR_EXCEPTION();
14957cd0 2231 callFrame->uncheckedR(dst) = result;
9dae56ea 2232
f9bf01c6 2233 vPC += OPCODE_LENGTH(op_not);
9dae56ea
A
2234 NEXT_INSTRUCTION();
2235 }
14957cd0
A
2236 DEFINE_OPCODE(op_check_has_instance) {
2237 /* check_has_instance constructor(r)
2238
2239 Check 'constructor' is an object with the internal property
2240 [HasInstance] (i.e. is a function ... *shakes head sadly at
2241 JSC API*). Raises an exception if register constructor is not
2242 an valid parameter for instanceof.
2243 */
2244 int base = vPC[1].u.operand;
2245 JSValue baseVal = callFrame->r(base).jsValue();
2246
2247 if (isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue))
2248 goto vm_throw;
2249
2250 vPC += OPCODE_LENGTH(op_check_has_instance);
2251 NEXT_INSTRUCTION();
2252 }
9dae56ea
A
2253 DEFINE_OPCODE(op_instanceof) {
2254 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2255
2256 Tests whether register value is an instance of register
2257 constructor, and puts the boolean result in register
2258 dst. Register constructorProto must contain the "prototype"
2259 property (not the actual prototype) of the object in
2260 register constructor. This lookup is separated so that
2261 polymorphic inline caching can apply.
2262
2263 Raises an exception if register constructor is not an
2264 object.
2265 */
2266 int dst = vPC[1].u.operand;
2267 int value = vPC[2].u.operand;
2268 int base = vPC[3].u.operand;
2269 int baseProto = vPC[4].u.operand;
2270
ba379fdc 2271 JSValue baseVal = callFrame->r(base).jsValue();
9dae56ea 2272
14957cd0 2273 ASSERT(!isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue));
9dae56ea 2274
ba379fdc
A
2275 bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
2276 CHECK_FOR_EXCEPTION();
14957cd0 2277 callFrame->uncheckedR(dst) = jsBoolean(result);
9dae56ea 2278
f9bf01c6 2279 vPC += OPCODE_LENGTH(op_instanceof);
9dae56ea
A
2280 NEXT_INSTRUCTION();
2281 }
2282 DEFINE_OPCODE(op_typeof) {
2283 /* typeof dst(r) src(r)
2284
2285 Determines the type string for src according to ECMAScript
2286 rules, and puts the result in register dst.
2287 */
f9bf01c6
A
2288 int dst = vPC[1].u.operand;
2289 int src = vPC[2].u.operand;
14957cd0 2290 callFrame->uncheckedR(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
9dae56ea 2291
f9bf01c6 2292 vPC += OPCODE_LENGTH(op_typeof);
9dae56ea
A
2293 NEXT_INSTRUCTION();
2294 }
2295 DEFINE_OPCODE(op_is_undefined) {
2296 /* is_undefined dst(r) src(r)
2297
2298 Determines whether the type string for src according to
2299 the ECMAScript rules is "undefined", and puts the result
2300 in register dst.
2301 */
f9bf01c6
A
2302 int dst = vPC[1].u.operand;
2303 int src = vPC[2].u.operand;
ba379fdc 2304 JSValue v = callFrame->r(src).jsValue();
14957cd0 2305 callFrame->uncheckedR(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
9dae56ea 2306
f9bf01c6 2307 vPC += OPCODE_LENGTH(op_is_undefined);
9dae56ea
A
2308 NEXT_INSTRUCTION();
2309 }
2310 DEFINE_OPCODE(op_is_boolean) {
2311 /* is_boolean dst(r) src(r)
2312
2313 Determines whether the type string for src according to
2314 the ECMAScript rules is "boolean", and puts the result
2315 in register dst.
2316 */
f9bf01c6
A
2317 int dst = vPC[1].u.operand;
2318 int src = vPC[2].u.operand;
14957cd0 2319 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
9dae56ea 2320
f9bf01c6 2321 vPC += OPCODE_LENGTH(op_is_boolean);
9dae56ea
A
2322 NEXT_INSTRUCTION();
2323 }
2324 DEFINE_OPCODE(op_is_number) {
2325 /* is_number dst(r) src(r)
2326
2327 Determines whether the type string for src according to
2328 the ECMAScript rules is "number", and puts the result
2329 in register dst.
2330 */
f9bf01c6
A
2331 int dst = vPC[1].u.operand;
2332 int src = vPC[2].u.operand;
14957cd0 2333 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
9dae56ea 2334
f9bf01c6 2335 vPC += OPCODE_LENGTH(op_is_number);
9dae56ea
A
2336 NEXT_INSTRUCTION();
2337 }
2338 DEFINE_OPCODE(op_is_string) {
2339 /* is_string dst(r) src(r)
2340
2341 Determines whether the type string for src according to
2342 the ECMAScript rules is "string", and puts the result
2343 in register dst.
2344 */
f9bf01c6
A
2345 int dst = vPC[1].u.operand;
2346 int src = vPC[2].u.operand;
14957cd0 2347 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
9dae56ea 2348
f9bf01c6 2349 vPC += OPCODE_LENGTH(op_is_string);
9dae56ea
A
2350 NEXT_INSTRUCTION();
2351 }
2352 DEFINE_OPCODE(op_is_object) {
2353 /* is_object dst(r) src(r)
2354
2355 Determines whether the type string for src according to
2356 the ECMAScript rules is "object", and puts the result
2357 in register dst.
2358 */
f9bf01c6
A
2359 int dst = vPC[1].u.operand;
2360 int src = vPC[2].u.operand;
14957cd0 2361 callFrame->uncheckedR(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
9dae56ea 2362
f9bf01c6 2363 vPC += OPCODE_LENGTH(op_is_object);
9dae56ea
A
2364 NEXT_INSTRUCTION();
2365 }
2366 DEFINE_OPCODE(op_is_function) {
2367 /* is_function dst(r) src(r)
2368
2369 Determines whether the type string for src according to
2370 the ECMAScript rules is "function", and puts the result
2371 in register dst.
2372 */
f9bf01c6
A
2373 int dst = vPC[1].u.operand;
2374 int src = vPC[2].u.operand;
14957cd0 2375 callFrame->uncheckedR(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
9dae56ea 2376
f9bf01c6 2377 vPC += OPCODE_LENGTH(op_is_function);
9dae56ea
A
2378 NEXT_INSTRUCTION();
2379 }
2380 DEFINE_OPCODE(op_in) {
2381 /* in dst(r) property(r) base(r)
2382
2383 Tests whether register base has a property named register
2384 property, and puts the boolean result in register dst.
2385
2386 Raises an exception if register constructor is not an
2387 object.
2388 */
f9bf01c6
A
2389 int dst = vPC[1].u.operand;
2390 int property = vPC[2].u.operand;
2391 int base = vPC[3].u.operand;
9dae56ea 2392
ba379fdc 2393 JSValue baseVal = callFrame->r(base).jsValue();
14957cd0 2394 if (isInvalidParamForIn(callFrame, baseVal, exceptionValue))
9dae56ea
A
2395 goto vm_throw;
2396
2397 JSObject* baseObj = asObject(baseVal);
2398
ba379fdc 2399 JSValue propName = callFrame->r(property).jsValue();
9dae56ea
A
2400
2401 uint32_t i;
2402 if (propName.getUInt32(i))
14957cd0 2403 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
9dae56ea
A
2404 else {
2405 Identifier property(callFrame, propName.toString(callFrame));
2406 CHECK_FOR_EXCEPTION();
14957cd0 2407 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
9dae56ea
A
2408 }
2409
f9bf01c6 2410 vPC += OPCODE_LENGTH(op_in);
9dae56ea
A
2411 NEXT_INSTRUCTION();
2412 }
2413 DEFINE_OPCODE(op_resolve) {
2414 /* resolve dst(r) property(id)
2415
2416 Looks up the property named by identifier property in the
2417 scope chain, and writes the resulting value to register
2418 dst. If the property is not found, raises an exception.
2419 */
2420 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
2421 goto vm_throw;
2422
f9bf01c6 2423 vPC += OPCODE_LENGTH(op_resolve);
9dae56ea
A
2424 NEXT_INSTRUCTION();
2425 }
2426 DEFINE_OPCODE(op_resolve_skip) {
2427 /* resolve_skip dst(r) property(id) skip(n)
2428
2429 Looks up the property named by identifier property in the
2430 scope chain skipping the top 'skip' levels, and writes the resulting
2431 value to register dst. If the property is not found, raises an exception.
2432 */
2433 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
2434 goto vm_throw;
2435
f9bf01c6 2436 vPC += OPCODE_LENGTH(op_resolve_skip);
9dae56ea
A
2437
2438 NEXT_INSTRUCTION();
2439 }
2440 DEFINE_OPCODE(op_resolve_global) {
2441 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
2442
2443 Performs a dynamic property lookup for the given property, on the provided
2444 global object. If structure matches the Structure of the global then perform
2445 a fast lookup using the case offset, otherwise fall back to a full resolve and
2446 cache the new structure and offset
2447 */
2448 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
2449 goto vm_throw;
2450
f9bf01c6 2451 vPC += OPCODE_LENGTH(op_resolve_global);
9dae56ea
A
2452
2453 NEXT_INSTRUCTION();
2454 }
4e4e5a6f
A
2455 DEFINE_OPCODE(op_resolve_global_dynamic) {
2456 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n), depth(n)
2457
2458 Performs a dynamic property lookup for the given property, on the provided
2459 global object. If structure matches the Structure of the global then perform
2460 a fast lookup using the case offset, otherwise fall back to a full resolve and
2461 cache the new structure and offset.
2462
2463 This walks through n levels of the scope chain to verify that none of those levels
2464 in the scope chain include dynamically added properties.
2465 */
2466 if (UNLIKELY(!resolveGlobalDynamic(callFrame, vPC, exceptionValue)))
2467 goto vm_throw;
2468
2469 vPC += OPCODE_LENGTH(op_resolve_global_dynamic);
2470
2471 NEXT_INSTRUCTION();
2472 }
9dae56ea
A
2473 DEFINE_OPCODE(op_get_global_var) {
2474 /* get_global_var dst(r) globalObject(c) index(n)
2475
2476 Gets the global var at global slot index and places it in register dst.
2477 */
f9bf01c6 2478 int dst = vPC[1].u.operand;
14957cd0 2479 JSGlobalObject* scope = codeBlock->globalObject();
9dae56ea 2480 ASSERT(scope->isGlobalObject());
14957cd0 2481 int index = vPC[2].u.operand;
9dae56ea 2482
14957cd0 2483 callFrame->uncheckedR(dst) = scope->registerAt(index).get();
f9bf01c6 2484 vPC += OPCODE_LENGTH(op_get_global_var);
9dae56ea
A
2485 NEXT_INSTRUCTION();
2486 }
2487 DEFINE_OPCODE(op_put_global_var) {
2488 /* put_global_var globalObject(c) index(n) value(r)
2489
2490 Puts value into global slot index.
2491 */
14957cd0 2492 JSGlobalObject* scope = codeBlock->globalObject();
9dae56ea 2493 ASSERT(scope->isGlobalObject());
14957cd0
A
2494 int index = vPC[1].u.operand;
2495 int value = vPC[2].u.operand;
9dae56ea 2496
14957cd0 2497 scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
f9bf01c6 2498 vPC += OPCODE_LENGTH(op_put_global_var);
9dae56ea 2499 NEXT_INSTRUCTION();
4e4e5a6f 2500 }
9dae56ea
A
2501 DEFINE_OPCODE(op_get_scoped_var) {
2502 /* get_scoped_var dst(r) index(n) skip(n)
2503
2504 Loads the contents of the index-th local from the scope skip nodes from
14957cd0 2505 the top of the scope chain, and places it in register dst.
9dae56ea 2506 */
f9bf01c6
A
2507 int dst = vPC[1].u.operand;
2508 int index = vPC[2].u.operand;
14957cd0 2509 int skip = vPC[3].u.operand;
9dae56ea
A
2510
2511 ScopeChainNode* scopeChain = callFrame->scopeChain();
2512 ScopeChainIterator iter = scopeChain->begin();
2513 ScopeChainIterator end = scopeChain->end();
2514 ASSERT(iter != end);
14957cd0
A
2515 ASSERT(codeBlock == callFrame->codeBlock());
2516 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
2517 ASSERT(skip || !checkTopLevel);
2518 if (checkTopLevel && skip--) {
2519 if (callFrame->r(codeBlock->activationRegister()).jsValue())
2520 ++iter;
2521 }
9dae56ea
A
2522 while (skip--) {
2523 ++iter;
2524 ASSERT(iter != end);
2525 }
9dae56ea 2526 ASSERT((*iter)->isVariableObject());
14957cd0
A
2527 JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
2528 callFrame->uncheckedR(dst) = scope->registerAt(index).get();
2529 ASSERT(callFrame->r(dst).jsValue());
f9bf01c6 2530 vPC += OPCODE_LENGTH(op_get_scoped_var);
9dae56ea
A
2531 NEXT_INSTRUCTION();
2532 }
2533 DEFINE_OPCODE(op_put_scoped_var) {
2534 /* put_scoped_var index(n) skip(n) value(r)
2535
2536 */
f9bf01c6 2537 int index = vPC[1].u.operand;
14957cd0 2538 int skip = vPC[2].u.operand;
f9bf01c6 2539 int value = vPC[3].u.operand;
9dae56ea
A
2540
2541 ScopeChainNode* scopeChain = callFrame->scopeChain();
2542 ScopeChainIterator iter = scopeChain->begin();
2543 ScopeChainIterator end = scopeChain->end();
14957cd0 2544 ASSERT(codeBlock == callFrame->codeBlock());
9dae56ea 2545 ASSERT(iter != end);
14957cd0
A
2546 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
2547 ASSERT(skip || !checkTopLevel);
2548 if (checkTopLevel && skip--) {
2549 if (callFrame->r(codeBlock->activationRegister()).jsValue())
2550 ++iter;
2551 }
9dae56ea
A
2552 while (skip--) {
2553 ++iter;
2554 ASSERT(iter != end);
2555 }
2556
2557 ASSERT((*iter)->isVariableObject());
14957cd0
A
2558 JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
2559 ASSERT(callFrame->r(value).jsValue());
2560 scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
f9bf01c6 2561 vPC += OPCODE_LENGTH(op_put_scoped_var);
9dae56ea
A
2562 NEXT_INSTRUCTION();
2563 }
2564 DEFINE_OPCODE(op_resolve_base) {
14957cd0 2565 /* resolve_base dst(r) property(id) isStrict(bool)
9dae56ea
A
2566
2567 Searches the scope chain for an object containing
2568 identifier property, and if one is found, writes it to
14957cd0
A
2569 register dst. If none is found and isStrict is false, the
2570 outermost scope (which will be the global object) is
2571 stored in register dst.
9dae56ea
A
2572 */
2573 resolveBase(callFrame, vPC);
14957cd0 2574 CHECK_FOR_EXCEPTION();
9dae56ea 2575
f9bf01c6 2576 vPC += OPCODE_LENGTH(op_resolve_base);
9dae56ea
A
2577 NEXT_INSTRUCTION();
2578 }
14957cd0
A
2579 DEFINE_OPCODE(op_ensure_property_exists) {
2580 /* ensure_property_exists base(r) property(id)
2581
2582 Throws an exception if property does not exist on base
2583 */
2584 int base = vPC[1].u.operand;
2585 int property = vPC[2].u.operand;
2586 Identifier& ident = codeBlock->identifier(property);
2587
2588 JSValue baseVal = callFrame->r(base).jsValue();
2589 JSObject* baseObject = asObject(baseVal);
2590 PropertySlot slot(baseVal);
2591 if (!baseObject->getPropertySlot(callFrame, ident, slot)) {
2592 exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
2593 goto vm_throw;
2594 }
2595
2596 vPC += OPCODE_LENGTH(op_ensure_property_exists);
2597 NEXT_INSTRUCTION();
2598 }
9dae56ea
A
2599 DEFINE_OPCODE(op_resolve_with_base) {
2600 /* resolve_with_base baseDst(r) propDst(r) property(id)
2601
2602 Searches the scope chain for an object containing
2603 identifier property, and if one is found, writes it to
2604 register srcDst, and the retrieved property value to register
2605 propDst. If the property is not found, raises an exception.
2606
2607 This is more efficient than doing resolve_base followed by
2608 resolve, or resolve_base followed by get_by_id, as it
2609 avoids duplicate hash lookups.
2610 */
2611 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
2612 goto vm_throw;
2613
f9bf01c6 2614 vPC += OPCODE_LENGTH(op_resolve_with_base);
9dae56ea
A
2615 NEXT_INSTRUCTION();
2616 }
9dae56ea
A
2617 DEFINE_OPCODE(op_get_by_id) {
2618 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2619
2620 Generic property access: Gets the property named by identifier
2621 property from the value base, and puts the result in register dst.
2622 */
2623 int dst = vPC[1].u.operand;
2624 int base = vPC[2].u.operand;
2625 int property = vPC[3].u.operand;
2626
9dae56ea 2627 Identifier& ident = codeBlock->identifier(property);
ba379fdc 2628 JSValue baseValue = callFrame->r(base).jsValue();
9dae56ea 2629 PropertySlot slot(baseValue);
ba379fdc 2630 JSValue result = baseValue.get(callFrame, ident, slot);
9dae56ea
A
2631 CHECK_FOR_EXCEPTION();
2632
2633 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
2634
14957cd0 2635 callFrame->uncheckedR(dst) = result;
f9bf01c6 2636 vPC += OPCODE_LENGTH(op_get_by_id);
9dae56ea
A
2637 NEXT_INSTRUCTION();
2638 }
2639 DEFINE_OPCODE(op_get_by_id_self) {
2640 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2641
2642 Cached property access: Attempts to get a cached property from the
2643 value base. If the cache misses, op_get_by_id_self reverts to
2644 op_get_by_id.
2645 */
2646 int base = vPC[2].u.operand;
ba379fdc 2647 JSValue baseValue = callFrame->r(base).jsValue();
9dae56ea
A
2648
2649 if (LIKELY(baseValue.isCell())) {
14957cd0
A
2650 JSCell* baseCell = baseValue.asCell();
2651 Structure* structure = vPC[4].u.structure.get();
9dae56ea
A
2652
2653 if (LIKELY(baseCell->structure() == structure)) {
2654 ASSERT(baseCell->isObject());
2655 JSObject* baseObject = asObject(baseCell);
2656 int dst = vPC[1].u.operand;
2657 int offset = vPC[5].u.operand;
2658
14957cd0
A
2659 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2660 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
9dae56ea 2661
f9bf01c6 2662 vPC += OPCODE_LENGTH(op_get_by_id_self);
9dae56ea
A
2663 NEXT_INSTRUCTION();
2664 }
2665 }
2666
14957cd0 2667 uncacheGetByID(codeBlock, vPC);
9dae56ea
A
2668 NEXT_INSTRUCTION();
2669 }
2670 DEFINE_OPCODE(op_get_by_id_proto) {
2671 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2672
2673 Cached property access: Attempts to get a cached property from the
2674 value base's prototype. If the cache misses, op_get_by_id_proto
2675 reverts to op_get_by_id.
2676 */
2677 int base = vPC[2].u.operand;
ba379fdc 2678 JSValue baseValue = callFrame->r(base).jsValue();
9dae56ea
A
2679
2680 if (LIKELY(baseValue.isCell())) {
14957cd0
A
2681 JSCell* baseCell = baseValue.asCell();
2682 Structure* structure = vPC[4].u.structure.get();
9dae56ea
A
2683
2684 if (LIKELY(baseCell->structure() == structure)) {
2685 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2686 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
14957cd0 2687 Structure* prototypeStructure = vPC[5].u.structure.get();
9dae56ea
A
2688
2689 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2690 int dst = vPC[1].u.operand;
2691 int offset = vPC[6].u.operand;
2692
14957cd0
A
2693 ASSERT(protoObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2694 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2695 callFrame->uncheckedR(dst) = JSValue(protoObject->getDirectOffset(offset));
9dae56ea 2696
f9bf01c6 2697 vPC += OPCODE_LENGTH(op_get_by_id_proto);
9dae56ea
A
2698 NEXT_INSTRUCTION();
2699 }
2700 }
2701 }
2702
14957cd0 2703 uncacheGetByID(codeBlock, vPC);
9dae56ea
A
2704 NEXT_INSTRUCTION();
2705 }
4e4e5a6f
A
2706#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2707 goto *(&&skip_id_getter_proto);
2708#endif
2709 DEFINE_OPCODE(op_get_by_id_getter_proto) {
2710 /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2711
2712 Cached property access: Attempts to get a cached getter property from the
2713 value base's prototype. If the cache misses, op_get_by_id_getter_proto
2714 reverts to op_get_by_id.
2715 */
2716 int base = vPC[2].u.operand;
2717 JSValue baseValue = callFrame->r(base).jsValue();
2718
2719 if (LIKELY(baseValue.isCell())) {
14957cd0
A
2720 JSCell* baseCell = baseValue.asCell();
2721 Structure* structure = vPC[4].u.structure.get();
4e4e5a6f
A
2722
2723 if (LIKELY(baseCell->structure() == structure)) {
2724 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2725 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
14957cd0 2726 Structure* prototypeStructure = vPC[5].u.structure.get();
4e4e5a6f
A
2727
2728 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2729 int dst = vPC[1].u.operand;
2730 int offset = vPC[6].u.operand;
2731 if (GetterSetter* getterSetter = asGetterSetter(protoObject->getDirectOffset(offset).asCell())) {
2732 JSObject* getter = getterSetter->getter();
2733 CallData callData;
2734 CallType callType = getter->getCallData(callData);
2735 JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
2736 CHECK_FOR_EXCEPTION();
14957cd0 2737 callFrame->uncheckedR(dst) = result;
4e4e5a6f 2738 } else
14957cd0 2739 callFrame->uncheckedR(dst) = jsUndefined();
4e4e5a6f
A
2740 vPC += OPCODE_LENGTH(op_get_by_id_getter_proto);
2741 NEXT_INSTRUCTION();
2742 }
2743 }
2744 }
14957cd0 2745 uncacheGetByID(codeBlock, vPC);
4e4e5a6f
A
2746 NEXT_INSTRUCTION();
2747 }
2748#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2749 skip_id_getter_proto:
2750#endif
2751#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2752 goto *(&&skip_id_custom_proto);
2753#endif
2754 DEFINE_OPCODE(op_get_by_id_custom_proto) {
2755 /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2756
2757 Cached property access: Attempts to use a cached named property getter
2758 from the value base's prototype. If the cache misses, op_get_by_id_custom_proto
2759 reverts to op_get_by_id.
2760 */
2761 int base = vPC[2].u.operand;
2762 JSValue baseValue = callFrame->r(base).jsValue();
2763
2764 if (LIKELY(baseValue.isCell())) {
14957cd0
A
2765 JSCell* baseCell = baseValue.asCell();
2766 Structure* structure = vPC[4].u.structure.get();
4e4e5a6f
A
2767
2768 if (LIKELY(baseCell->structure() == structure)) {
2769 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2770 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
14957cd0 2771 Structure* prototypeStructure = vPC[5].u.structure.get();
4e4e5a6f
A
2772
2773 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2774 int dst = vPC[1].u.operand;
2775 int property = vPC[3].u.operand;
14957cd0 2776 Identifier& ident = codeBlock->identifier(property);
4e4e5a6f
A
2777
2778 PropertySlot::GetValueFunc getter = vPC[6].u.getterFunc;
2779 JSValue result = getter(callFrame, protoObject, ident);
2780 CHECK_FOR_EXCEPTION();
14957cd0 2781 callFrame->uncheckedR(dst) = result;
4e4e5a6f
A
2782 vPC += OPCODE_LENGTH(op_get_by_id_custom_proto);
2783 NEXT_INSTRUCTION();
2784 }
2785 }
2786 }
14957cd0 2787 uncacheGetByID(codeBlock, vPC);
4e4e5a6f
A
2788 NEXT_INSTRUCTION();
2789 }
2790#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2791 skip_id_custom_proto:
2792#endif
9dae56ea
A
2793 DEFINE_OPCODE(op_get_by_id_self_list) {
2794 // Polymorphic self access caching currently only supported when JITting.
2795 ASSERT_NOT_REACHED();
2796 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
f9bf01c6 2797 vPC += OPCODE_LENGTH(op_get_by_id_self_list);
9dae56ea
A
2798 NEXT_INSTRUCTION();
2799 }
2800 DEFINE_OPCODE(op_get_by_id_proto_list) {
2801 // Polymorphic prototype access caching currently only supported when JITting.
2802 ASSERT_NOT_REACHED();
2803 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
f9bf01c6 2804 vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
9dae56ea
A
2805 NEXT_INSTRUCTION();
2806 }
4e4e5a6f
A
2807 DEFINE_OPCODE(op_get_by_id_getter_self_list) {
2808 // Polymorphic self access caching currently only supported when JITting.
2809 ASSERT_NOT_REACHED();
2810 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2811 vPC += OPCODE_LENGTH(op_get_by_id_self_list);
2812 NEXT_INSTRUCTION();
2813 }
2814 DEFINE_OPCODE(op_get_by_id_getter_proto_list) {
2815 // Polymorphic prototype access caching currently only supported when JITting.
2816 ASSERT_NOT_REACHED();
2817 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2818 vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
2819 NEXT_INSTRUCTION();
2820 }
2821 DEFINE_OPCODE(op_get_by_id_custom_self_list) {
2822 // Polymorphic self access caching currently only supported when JITting.
2823 ASSERT_NOT_REACHED();
2824 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2825 vPC += OPCODE_LENGTH(op_get_by_id_custom_self_list);
2826 NEXT_INSTRUCTION();
2827 }
2828 DEFINE_OPCODE(op_get_by_id_custom_proto_list) {
2829 // Polymorphic prototype access caching currently only supported when JITting.
2830 ASSERT_NOT_REACHED();
2831 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2832 vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
2833 NEXT_INSTRUCTION();
2834 }
14957cd0
A
2835#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2836 goto *(&&skip_get_by_id_chain);
2837#endif
9dae56ea
A
2838 DEFINE_OPCODE(op_get_by_id_chain) {
2839 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2840
2841 Cached property access: Attempts to get a cached property from the
2842 value base's prototype chain. If the cache misses, op_get_by_id_chain
2843 reverts to op_get_by_id.
2844 */
2845 int base = vPC[2].u.operand;
ba379fdc 2846 JSValue baseValue = callFrame->r(base).jsValue();
9dae56ea
A
2847
2848 if (LIKELY(baseValue.isCell())) {
14957cd0
A
2849 JSCell* baseCell = baseValue.asCell();
2850 Structure* structure = vPC[4].u.structure.get();
9dae56ea
A
2851
2852 if (LIKELY(baseCell->structure() == structure)) {
14957cd0 2853 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
9dae56ea 2854 size_t count = vPC[6].u.operand;
14957cd0 2855 WriteBarrier<Structure>* end = it + count;
9dae56ea
A
2856
2857 while (true) {
2858 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
2859
2860 if (UNLIKELY(baseObject->structure() != (*it).get()))
2861 break;
2862
2863 if (++it == end) {
2864 int dst = vPC[1].u.operand;
2865 int offset = vPC[7].u.operand;
2866
14957cd0
A
2867 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2868 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2869 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
9dae56ea 2870
f9bf01c6 2871 vPC += OPCODE_LENGTH(op_get_by_id_chain);
9dae56ea
A
2872 NEXT_INSTRUCTION();
2873 }
2874
2875 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2876 baseCell = baseObject;
2877 }
2878 }
2879 }
2880
14957cd0 2881 uncacheGetByID(codeBlock, vPC);
9dae56ea
A
2882 NEXT_INSTRUCTION();
2883 }
4e4e5a6f 2884#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
14957cd0 2885 skip_get_by_id_chain:
4e4e5a6f
A
2886 goto *(&&skip_id_getter_self);
2887#endif
2888 DEFINE_OPCODE(op_get_by_id_getter_self) {
2889 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2890
2891 Cached property access: Attempts to get a cached property from the
2892 value base. If the cache misses, op_get_by_id_getter_self reverts to
2893 op_get_by_id.
2894 */
2895 int base = vPC[2].u.operand;
2896 JSValue baseValue = callFrame->r(base).jsValue();
2897
2898 if (LIKELY(baseValue.isCell())) {
14957cd0
A
2899 JSCell* baseCell = baseValue.asCell();
2900 Structure* structure = vPC[4].u.structure.get();
4e4e5a6f
A
2901
2902 if (LIKELY(baseCell->structure() == structure)) {
2903 ASSERT(baseCell->isObject());
2904 JSObject* baseObject = asObject(baseCell);
2905 int dst = vPC[1].u.operand;
2906 int offset = vPC[5].u.operand;
2907
2908 if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
2909 JSObject* getter = getterSetter->getter();
2910 CallData callData;
2911 CallType callType = getter->getCallData(callData);
2912 JSValue result = call(callFrame, getter, callType, callData, baseObject, ArgList());
2913 CHECK_FOR_EXCEPTION();
14957cd0 2914 callFrame->uncheckedR(dst) = result;
4e4e5a6f 2915 } else
14957cd0 2916 callFrame->uncheckedR(dst) = jsUndefined();
4e4e5a6f
A
2917
2918 vPC += OPCODE_LENGTH(op_get_by_id_getter_self);
2919 NEXT_INSTRUCTION();
2920 }
2921 }
14957cd0 2922 uncacheGetByID(codeBlock, vPC);
4e4e5a6f
A
2923 NEXT_INSTRUCTION();
2924 }
2925#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2926 skip_id_getter_self:
2927#endif
2928#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2929 goto *(&&skip_id_custom_self);
2930#endif
2931 DEFINE_OPCODE(op_get_by_id_custom_self) {
2932 /* op_get_by_id_custom_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2933
2934 Cached property access: Attempts to use a cached named property getter
2935 from the value base. If the cache misses, op_get_by_id_custom_self reverts to
2936 op_get_by_id.
2937 */
2938 int base = vPC[2].u.operand;
2939 JSValue baseValue = callFrame->r(base).jsValue();
2940
2941 if (LIKELY(baseValue.isCell())) {
14957cd0
A
2942 JSCell* baseCell = baseValue.asCell();
2943 Structure* structure = vPC[4].u.structure.get();
4e4e5a6f
A
2944
2945 if (LIKELY(baseCell->structure() == structure)) {
2946 ASSERT(baseCell->isObject());
2947 int dst = vPC[1].u.operand;
2948 int property = vPC[3].u.operand;
14957cd0 2949 Identifier& ident = codeBlock->identifier(property);
4e4e5a6f
A
2950
2951 PropertySlot::GetValueFunc getter = vPC[5].u.getterFunc;
2952 JSValue result = getter(callFrame, baseValue, ident);
2953 CHECK_FOR_EXCEPTION();
14957cd0 2954 callFrame->uncheckedR(dst) = result;
4e4e5a6f
A
2955 vPC += OPCODE_LENGTH(op_get_by_id_custom_self);
2956 NEXT_INSTRUCTION();
2957 }
2958 }
14957cd0 2959 uncacheGetByID(codeBlock, vPC);
4e4e5a6f
A
2960 NEXT_INSTRUCTION();
2961 }
2962#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2963skip_id_custom_self:
2964#endif
9dae56ea
A
2965 DEFINE_OPCODE(op_get_by_id_generic) {
2966 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2967
2968 Generic property access: Gets the property named by identifier
2969 property from the value base, and puts the result in register dst.
2970 */
2971 int dst = vPC[1].u.operand;
2972 int base = vPC[2].u.operand;
2973 int property = vPC[3].u.operand;
2974
14957cd0 2975 Identifier& ident = codeBlock->identifier(property);
ba379fdc 2976 JSValue baseValue = callFrame->r(base).jsValue();
9dae56ea 2977 PropertySlot slot(baseValue);
ba379fdc 2978 JSValue result = baseValue.get(callFrame, ident, slot);
9dae56ea
A
2979 CHECK_FOR_EXCEPTION();
2980
14957cd0 2981 callFrame->uncheckedR(dst) = result;
f9bf01c6 2982 vPC += OPCODE_LENGTH(op_get_by_id_generic);
9dae56ea
A
2983 NEXT_INSTRUCTION();
2984 }
4e4e5a6f
A
2985#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2986 goto *(&&skip_id_getter_chain);
2987#endif
2988 DEFINE_OPCODE(op_get_by_id_getter_chain) {
2989 /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2990
2991 Cached property access: Attempts to get a cached property from the
2992 value base's prototype chain. If the cache misses, op_get_by_id_getter_chain
2993 reverts to op_get_by_id.
2994 */
2995 int base = vPC[2].u.operand;
2996 JSValue baseValue = callFrame->r(base).jsValue();
2997
2998 if (LIKELY(baseValue.isCell())) {
14957cd0
A
2999 JSCell* baseCell = baseValue.asCell();
3000 Structure* structure = vPC[4].u.structure.get();
4e4e5a6f
A
3001
3002 if (LIKELY(baseCell->structure() == structure)) {
14957cd0 3003 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
4e4e5a6f 3004 size_t count = vPC[6].u.operand;
14957cd0 3005 WriteBarrier<Structure>* end = it + count;
4e4e5a6f
A
3006
3007 while (true) {
3008 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
3009
3010 if (UNLIKELY(baseObject->structure() != (*it).get()))
3011 break;
3012
3013 if (++it == end) {
3014 int dst = vPC[1].u.operand;
3015 int offset = vPC[7].u.operand;
3016 if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
3017 JSObject* getter = getterSetter->getter();
3018 CallData callData;
3019 CallType callType = getter->getCallData(callData);
3020 JSValue result = call(callFrame, getter, callType, callData, baseValue, ArgList());
3021 CHECK_FOR_EXCEPTION();
14957cd0 3022 callFrame->uncheckedR(dst) = result;
4e4e5a6f 3023 } else
14957cd0 3024 callFrame->uncheckedR(dst) = jsUndefined();
4e4e5a6f
A
3025 vPC += OPCODE_LENGTH(op_get_by_id_getter_chain);
3026 NEXT_INSTRUCTION();
3027 }
3028
3029 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
3030 baseCell = baseObject;
3031 }
3032 }
3033 }
14957cd0 3034 uncacheGetByID(codeBlock, vPC);
4e4e5a6f
A
3035 NEXT_INSTRUCTION();
3036 }
3037#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3038 skip_id_getter_chain:
3039#endif
3040#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3041 goto *(&&skip_id_custom_chain);
3042#endif
3043 DEFINE_OPCODE(op_get_by_id_custom_chain) {
3044 /* op_get_by_id_custom_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
3045
3046 Cached property access: Attempts to use a cached named property getter on the
3047 value base's prototype chain. If the cache misses, op_get_by_id_custom_chain
3048 reverts to op_get_by_id.
3049 */
3050 int base = vPC[2].u.operand;
3051 JSValue baseValue = callFrame->r(base).jsValue();
3052
3053 if (LIKELY(baseValue.isCell())) {
14957cd0
A
3054 JSCell* baseCell = baseValue.asCell();
3055 Structure* structure = vPC[4].u.structure.get();
4e4e5a6f
A
3056
3057 if (LIKELY(baseCell->structure() == structure)) {
14957cd0 3058 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
4e4e5a6f 3059 size_t count = vPC[6].u.operand;
14957cd0 3060 WriteBarrier<Structure>* end = it + count;
4e4e5a6f
A
3061
3062 while (true) {
3063 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
3064
3065 if (UNLIKELY(baseObject->structure() != (*it).get()))
3066 break;
3067
3068 if (++it == end) {
3069 int dst = vPC[1].u.operand;
3070 int property = vPC[3].u.operand;
14957cd0 3071 Identifier& ident = codeBlock->identifier(property);
4e4e5a6f
A
3072
3073 PropertySlot::GetValueFunc getter = vPC[7].u.getterFunc;
3074 JSValue result = getter(callFrame, baseObject, ident);
3075 CHECK_FOR_EXCEPTION();
14957cd0 3076 callFrame->uncheckedR(dst) = result;
4e4e5a6f
A
3077 vPC += OPCODE_LENGTH(op_get_by_id_custom_chain);
3078 NEXT_INSTRUCTION();
3079 }
3080
3081 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
3082 baseCell = baseObject;
3083 }
3084 }
3085 }
14957cd0 3086 uncacheGetByID(codeBlock, vPC);
4e4e5a6f
A
3087 NEXT_INSTRUCTION();
3088 }
3089#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3090 skip_id_custom_chain:
14957cd0 3091 goto *(&&skip_get_array_length);
4e4e5a6f 3092#endif
9dae56ea
A
3093 DEFINE_OPCODE(op_get_array_length) {
3094 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3095
3096 Cached property access: Gets the length of the array in register base,
3097 and puts the result in register dst. If register base does not hold
3098 an array, op_get_array_length reverts to op_get_by_id.
3099 */
3100
3101 int base = vPC[2].u.operand;
ba379fdc
A
3102 JSValue baseValue = callFrame->r(base).jsValue();
3103 if (LIKELY(isJSArray(globalData, baseValue))) {
9dae56ea 3104 int dst = vPC[1].u.operand;
14957cd0 3105 callFrame->uncheckedR(dst) = jsNumber(asArray(baseValue)->length());
f9bf01c6 3106 vPC += OPCODE_LENGTH(op_get_array_length);
9dae56ea
A
3107 NEXT_INSTRUCTION();
3108 }
3109
14957cd0 3110 uncacheGetByID(codeBlock, vPC);
9dae56ea
A
3111 NEXT_INSTRUCTION();
3112 }
14957cd0
A
3113#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3114 skip_get_array_length:
3115 goto *(&&skip_get_string_length);
3116#endif
9dae56ea
A
3117 DEFINE_OPCODE(op_get_string_length) {
3118 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3119
3120 Cached property access: Gets the length of the string in register base,
3121 and puts the result in register dst. If register base does not hold
3122 a string, op_get_string_length reverts to op_get_by_id.
3123 */
3124
3125 int base = vPC[2].u.operand;
ba379fdc
A
3126 JSValue baseValue = callFrame->r(base).jsValue();
3127 if (LIKELY(isJSString(globalData, baseValue))) {
9dae56ea 3128 int dst = vPC[1].u.operand;
14957cd0 3129 callFrame->uncheckedR(dst) = jsNumber(asString(baseValue)->length());
f9bf01c6 3130 vPC += OPCODE_LENGTH(op_get_string_length);
9dae56ea
A
3131 NEXT_INSTRUCTION();
3132 }
3133
14957cd0 3134 uncacheGetByID(codeBlock, vPC);
9dae56ea
A
3135 NEXT_INSTRUCTION();
3136 }
14957cd0
A
3137#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3138 skip_get_string_length:
3139 goto *(&&skip_put_by_id);
3140#endif
9dae56ea 3141 DEFINE_OPCODE(op_put_by_id) {
4e4e5a6f 3142 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
9dae56ea
A
3143
3144 Generic property access: Sets the property named by identifier
3145 property, belonging to register base, to register value.
3146
3147 Unlike many opcodes, this one does not write any output to
3148 the register file.
14957cd0 3149
4e4e5a6f
A
3150 The "direct" flag should only be set this put_by_id is to initialize
3151 an object literal.
9dae56ea
A
3152 */
3153
3154 int base = vPC[1].u.operand;
3155 int property = vPC[2].u.operand;
3156 int value = vPC[3].u.operand;
4e4e5a6f 3157 int direct = vPC[8].u.operand;
9dae56ea 3158
ba379fdc 3159 JSValue baseValue = callFrame->r(base).jsValue();
9dae56ea 3160 Identifier& ident = codeBlock->identifier(property);
14957cd0 3161 PutPropertySlot slot(codeBlock->isStrictMode());
4e4e5a6f
A
3162 if (direct) {
3163 baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
3164 ASSERT(slot.base() == baseValue);
3165 } else
3166 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
9dae56ea
A
3167 CHECK_FOR_EXCEPTION();
3168
3169 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
3170
f9bf01c6 3171 vPC += OPCODE_LENGTH(op_put_by_id);
9dae56ea
A
3172 NEXT_INSTRUCTION();
3173 }
14957cd0
A
3174#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3175 skip_put_by_id:
3176#endif
9dae56ea 3177 DEFINE_OPCODE(op_put_by_id_transition) {
4e4e5a6f 3178 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b)
9dae56ea
A
3179
3180 Cached property access: Attempts to set a new property with a cached transition
3181 property named by identifier property, belonging to register base,
3182 to register value. If the cache misses, op_put_by_id_transition
3183 reverts to op_put_by_id_generic.
3184
3185 Unlike many opcodes, this one does not write any output to
3186 the register file.
3187 */
3188 int base = vPC[1].u.operand;
ba379fdc 3189 JSValue baseValue = callFrame->r(base).jsValue();
9dae56ea
A
3190
3191 if (LIKELY(baseValue.isCell())) {
14957cd0
A
3192 JSCell* baseCell = baseValue.asCell();
3193 Structure* oldStructure = vPC[4].u.structure.get();
3194 Structure* newStructure = vPC[5].u.structure.get();
9dae56ea
A
3195
3196 if (LIKELY(baseCell->structure() == oldStructure)) {
3197 ASSERT(baseCell->isObject());
3198 JSObject* baseObject = asObject(baseCell);
4e4e5a6f 3199 int direct = vPC[8].u.operand;
14957cd0 3200
4e4e5a6f 3201 if (!direct) {
14957cd0 3202 WriteBarrier<Structure>* it = vPC[6].u.structureChain->head();
4e4e5a6f
A
3203
3204 JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);
3205 while (!proto.isNull()) {
3206 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
14957cd0 3207 uncachePutByID(codeBlock, vPC);
4e4e5a6f
A
3208 NEXT_INSTRUCTION();
3209 }
3210 ++it;
3211 proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
9dae56ea 3212 }
9dae56ea 3213 }
14957cd0 3214 baseObject->transitionTo(*globalData, newStructure);
9dae56ea
A
3215
3216 int value = vPC[3].u.operand;
3217 unsigned offset = vPC[7].u.operand;
14957cd0
A
3218 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
3219 baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
9dae56ea 3220
f9bf01c6 3221 vPC += OPCODE_LENGTH(op_put_by_id_transition);
9dae56ea
A
3222 NEXT_INSTRUCTION();
3223 }
3224 }
3225
14957cd0 3226 uncachePutByID(codeBlock, vPC);
9dae56ea
A
3227 NEXT_INSTRUCTION();
3228 }
3229 DEFINE_OPCODE(op_put_by_id_replace) {
4e4e5a6f 3230 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n) direct(b)
9dae56ea
A
3231
3232 Cached property access: Attempts to set a pre-existing, cached
3233 property named by identifier property, belonging to register base,
3234 to register value. If the cache misses, op_put_by_id_replace
3235 reverts to op_put_by_id.
3236
3237 Unlike many opcodes, this one does not write any output to
3238 the register file.
3239 */
3240 int base = vPC[1].u.operand;
ba379fdc 3241 JSValue baseValue = callFrame->r(base).jsValue();
9dae56ea
A
3242
3243 if (LIKELY(baseValue.isCell())) {
14957cd0
A
3244 JSCell* baseCell = baseValue.asCell();
3245 Structure* structure = vPC[4].u.structure.get();
9dae56ea
A
3246
3247 if (LIKELY(baseCell->structure() == structure)) {
3248 ASSERT(baseCell->isObject());
3249 JSObject* baseObject = asObject(baseCell);
3250 int value = vPC[3].u.operand;
3251 unsigned offset = vPC[5].u.operand;
3252
14957cd0
A
3253 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
3254 baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
9dae56ea 3255
f9bf01c6 3256 vPC += OPCODE_LENGTH(op_put_by_id_replace);
9dae56ea
A
3257 NEXT_INSTRUCTION();
3258 }
3259 }
3260
14957cd0 3261 uncachePutByID(codeBlock, vPC);
9dae56ea
A
3262 NEXT_INSTRUCTION();
3263 }
3264 DEFINE_OPCODE(op_put_by_id_generic) {
4e4e5a6f 3265 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
9dae56ea
A
3266
3267 Generic property access: Sets the property named by identifier
3268 property, belonging to register base, to register value.
3269
3270 Unlike many opcodes, this one does not write any output to
3271 the register file.
3272 */
3273 int base = vPC[1].u.operand;
3274 int property = vPC[2].u.operand;
3275 int value = vPC[3].u.operand;
4e4e5a6f 3276 int direct = vPC[8].u.operand;
9dae56ea 3277
ba379fdc 3278 JSValue baseValue = callFrame->r(base).jsValue();
14957cd0
A
3279 Identifier& ident = codeBlock->identifier(property);
3280 PutPropertySlot slot(codeBlock->isStrictMode());
4e4e5a6f
A
3281 if (direct) {
3282 baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
3283 ASSERT(slot.base() == baseValue);
3284 } else
3285 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
9dae56ea
A
3286 CHECK_FOR_EXCEPTION();
3287
f9bf01c6 3288 vPC += OPCODE_LENGTH(op_put_by_id_generic);
9dae56ea
A
3289 NEXT_INSTRUCTION();
3290 }
3291 DEFINE_OPCODE(op_del_by_id) {
3292 /* del_by_id dst(r) base(r) property(id)
3293
3294 Converts register base to Object, deletes the property
3295 named by identifier property from the object, and writes a
3296 boolean indicating success (if true) or failure (if false)
3297 to register dst.
3298 */
f9bf01c6
A
3299 int dst = vPC[1].u.operand;
3300 int base = vPC[2].u.operand;
3301 int property = vPC[3].u.operand;
9dae56ea 3302
ba379fdc 3303 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);
14957cd0
A
3304 Identifier& ident = codeBlock->identifier(property);
3305 bool result = baseObj->deleteProperty(callFrame, ident);
3306 if (!result && codeBlock->isStrictMode()) {
3307 exceptionValue = createTypeError(callFrame, "Unable to delete property.");
3308 goto vm_throw;
3309 }
9dae56ea 3310 CHECK_FOR_EXCEPTION();
14957cd0 3311 callFrame->uncheckedR(dst) = jsBoolean(result);
f9bf01c6
A
3312 vPC += OPCODE_LENGTH(op_del_by_id);
3313 NEXT_INSTRUCTION();
3314 }
3315 DEFINE_OPCODE(op_get_by_pname) {
3316 int dst = vPC[1].u.operand;
3317 int base = vPC[2].u.operand;
3318 int property = vPC[3].u.operand;
3319 int expected = vPC[4].u.operand;
3320 int iter = vPC[5].u.operand;
3321 int i = vPC[6].u.operand;
3322
3323 JSValue baseValue = callFrame->r(base).jsValue();
3324 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
3325 JSValue subscript = callFrame->r(property).jsValue();
3326 JSValue expectedSubscript = callFrame->r(expected).jsValue();
3327 int index = callFrame->r(i).i() - 1;
3328 JSValue result;
3329 int offset = 0;
3330 if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {
14957cd0 3331 callFrame->uncheckedR(dst) = JSValue(asObject(baseValue)->getDirectOffset(offset));
f9bf01c6
A
3332 vPC += OPCODE_LENGTH(op_get_by_pname);
3333 NEXT_INSTRUCTION();
3334 }
14957cd0
A
3335 {
3336 Identifier propertyName(callFrame, subscript.toString(callFrame));
3337 result = baseValue.get(callFrame, propertyName);
3338 }
f9bf01c6 3339 CHECK_FOR_EXCEPTION();
14957cd0 3340 callFrame->uncheckedR(dst) = result;
f9bf01c6 3341 vPC += OPCODE_LENGTH(op_get_by_pname);
9dae56ea
A
3342 NEXT_INSTRUCTION();
3343 }
14957cd0
A
3344 DEFINE_OPCODE(op_get_arguments_length) {
3345 int dst = vPC[1].u.operand;
3346 int argumentsRegister = vPC[2].u.operand;
3347 int property = vPC[3].u.operand;
3348 JSValue arguments = callFrame->r(argumentsRegister).jsValue();
3349 if (arguments) {
3350 Identifier& ident = codeBlock->identifier(property);
3351 PropertySlot slot(arguments);
3352 JSValue result = arguments.get(callFrame, ident, slot);
3353 CHECK_FOR_EXCEPTION();
3354 callFrame->uncheckedR(dst) = result;
3355 } else
3356 callFrame->uncheckedR(dst) = jsNumber(callFrame->argumentCount());
3357
3358 vPC += OPCODE_LENGTH(op_get_arguments_length);
3359 NEXT_INSTRUCTION();
3360 }
3361 DEFINE_OPCODE(op_get_argument_by_val) {
3362 int dst = vPC[1].u.operand;
3363 int argumentsRegister = vPC[2].u.operand;
3364 int property = vPC[3].u.operand;
3365 JSValue arguments = callFrame->r(argumentsRegister).jsValue();
3366 JSValue subscript = callFrame->r(property).jsValue();
3367 if (!arguments && subscript.isUInt32() && subscript.asUInt32() < callFrame->argumentCount()) {
3368 unsigned arg = subscript.asUInt32() + 1;
3369 unsigned numParameters = callFrame->codeBlock()->m_numParameters;
3370 if (arg < numParameters)
3371 callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters);
3372 else
3373 callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters - callFrame->argumentCount() - 1);
3374 vPC += OPCODE_LENGTH(op_get_argument_by_val);
3375 NEXT_INSTRUCTION();
3376 }
3377 if (!arguments) {
3378 Arguments* arguments = new (globalData) Arguments(callFrame);
3379 callFrame->uncheckedR(argumentsRegister) = JSValue(arguments);
3380 callFrame->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister)) = JSValue(arguments);
3381 }
3382 // fallthrough
3383 }
9dae56ea
A
3384 DEFINE_OPCODE(op_get_by_val) {
3385 /* get_by_val dst(r) base(r) property(r)
3386
3387 Converts register base to Object, gets the property named
3388 by register property from the object, and puts the result
3389 in register dst. property is nominally converted to string
3390 but numbers are treated more efficiently.
3391 */
f9bf01c6
A
3392 int dst = vPC[1].u.operand;
3393 int base = vPC[2].u.operand;
3394 int property = vPC[3].u.operand;
9dae56ea 3395
ba379fdc
A
3396 JSValue baseValue = callFrame->r(base).jsValue();
3397 JSValue subscript = callFrame->r(property).jsValue();
9dae56ea 3398
ba379fdc 3399 JSValue result;
9dae56ea 3400
ba379fdc
A
3401 if (LIKELY(subscript.isUInt32())) {
3402 uint32_t i = subscript.asUInt32();
3403 if (isJSArray(globalData, baseValue)) {
9dae56ea
A
3404 JSArray* jsArray = asArray(baseValue);
3405 if (jsArray->canGetIndex(i))
3406 result = jsArray->getIndex(i);
3407 else
3408 result = jsArray->JSArray::get(callFrame, i);
ba379fdc 3409 } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
f9bf01c6 3410 result = asString(baseValue)->getIndex(callFrame, i);
ba379fdc 3411 else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i))
9dae56ea
A
3412 result = asByteArray(baseValue)->getIndex(callFrame, i);
3413 else
3414 result = baseValue.get(callFrame, i);
3415 } else {
3416 Identifier property(callFrame, subscript.toString(callFrame));
3417 result = baseValue.get(callFrame, property);
3418 }
3419
3420 CHECK_FOR_EXCEPTION();
14957cd0 3421 callFrame->uncheckedR(dst) = result;
f9bf01c6 3422 vPC += OPCODE_LENGTH(op_get_by_val);
9dae56ea
A
3423 NEXT_INSTRUCTION();
3424 }
3425 DEFINE_OPCODE(op_put_by_val) {
3426 /* put_by_val base(r) property(r) value(r)
3427
3428 Sets register value on register base as the property named
3429 by register property. Base is converted to object
3430 first. register property is nominally converted to string
3431 but numbers are treated more efficiently.
3432
3433 Unlike many opcodes, this one does not write any output to
3434 the register file.
3435 */
f9bf01c6
A
3436 int base = vPC[1].u.operand;
3437 int property = vPC[2].u.operand;
3438 int value = vPC[3].u.operand;
9dae56ea 3439
ba379fdc
A
3440 JSValue baseValue = callFrame->r(base).jsValue();
3441 JSValue subscript = callFrame->r(property).jsValue();
9dae56ea 3442
ba379fdc
A
3443 if (LIKELY(subscript.isUInt32())) {
3444 uint32_t i = subscript.asUInt32();
3445 if (isJSArray(globalData, baseValue)) {
9dae56ea
A
3446 JSArray* jsArray = asArray(baseValue);
3447 if (jsArray->canSetIndex(i))
14957cd0 3448 jsArray->setIndex(*globalData, i, callFrame->r(value).jsValue());
9dae56ea 3449 else
ba379fdc
A
3450 jsArray->JSArray::put(callFrame, i, callFrame->r(value).jsValue());
3451 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
9dae56ea
A
3452 JSByteArray* jsByteArray = asByteArray(baseValue);
3453 double dValue = 0;
ba379fdc
A
3454 JSValue jsValue = callFrame->r(value).jsValue();
3455 if (jsValue.isInt32())
3456 jsByteArray->setIndex(i, jsValue.asInt32());
9dae56ea
A
3457 else if (jsValue.getNumber(dValue))
3458 jsByteArray->setIndex(i, dValue);
3459 else
3460 baseValue.put(callFrame, i, jsValue);
3461 } else
ba379fdc 3462 baseValue.put(callFrame, i, callFrame->r(value).jsValue());
9dae56ea
A
3463 } else {
3464 Identifier property(callFrame, subscript.toString(callFrame));
3465 if (!globalData->exception) { // Don't put to an object if toString threw an exception.
14957cd0 3466 PutPropertySlot slot(codeBlock->isStrictMode());
ba379fdc 3467 baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot);
9dae56ea
A
3468 }
3469 }
3470
3471 CHECK_FOR_EXCEPTION();
f9bf01c6 3472 vPC += OPCODE_LENGTH(op_put_by_val);
9dae56ea
A
3473 NEXT_INSTRUCTION();
3474 }
3475 DEFINE_OPCODE(op_del_by_val) {
3476 /* del_by_val dst(r) base(r) property(r)
3477
3478 Converts register base to Object, deletes the property
3479 named by register property from the object, and writes a
3480 boolean indicating success (if true) or failure (if false)
3481 to register dst.
3482 */
f9bf01c6
A
3483 int dst = vPC[1].u.operand;
3484 int base = vPC[2].u.operand;
3485 int property = vPC[3].u.operand;
9dae56ea 3486
ba379fdc 3487 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw
9dae56ea 3488
ba379fdc 3489 JSValue subscript = callFrame->r(property).jsValue();
14957cd0 3490 bool result;
9dae56ea
A
3491 uint32_t i;
3492 if (subscript.getUInt32(i))
14957cd0 3493 result = baseObj->deleteProperty(callFrame, i);
9dae56ea
A
3494 else {
3495 CHECK_FOR_EXCEPTION();
3496 Identifier property(callFrame, subscript.toString(callFrame));
3497 CHECK_FOR_EXCEPTION();
14957cd0
A
3498 result = baseObj->deleteProperty(callFrame, property);
3499 }
3500 if (!result && codeBlock->isStrictMode()) {
3501 exceptionValue = createTypeError(callFrame, "Unable to delete property.");
3502 goto vm_throw;
9dae56ea 3503 }
9dae56ea 3504 CHECK_FOR_EXCEPTION();
14957cd0 3505 callFrame->uncheckedR(dst) = jsBoolean(result);
f9bf01c6 3506 vPC += OPCODE_LENGTH(op_del_by_val);
9dae56ea
A
3507 NEXT_INSTRUCTION();
3508 }
3509 DEFINE_OPCODE(op_put_by_index) {
3510 /* put_by_index base(r) property(n) value(r)
3511
3512 Sets register value on register base as the property named
3513 by the immediate number property. Base is converted to
3514 object first.
3515
3516 Unlike many opcodes, this one does not write any output to
3517 the register file.
3518
3519 This opcode is mainly used to initialize array literals.
3520 */
f9bf01c6
A
3521 int base = vPC[1].u.operand;
3522 unsigned property = vPC[2].u.operand;
3523 int value = vPC[3].u.operand;
9dae56ea 3524
ba379fdc 3525 callFrame->r(base).jsValue().put(callFrame, property, callFrame->r(value).jsValue());
9dae56ea 3526
f9bf01c6 3527 vPC += OPCODE_LENGTH(op_put_by_index);
9dae56ea
A
3528 NEXT_INSTRUCTION();
3529 }
3530 DEFINE_OPCODE(op_loop) {
3531 /* loop target(offset)
3532
3533 Jumps unconditionally to offset target from the current
3534 instruction.
3535
3536 Additionally this loop instruction may terminate JS execution is
3537 the JS timeout is reached.
3538 */
3539#if ENABLE(OPCODE_STATS)
3540 OpcodeStats::resetLastInstruction();
3541#endif
f9bf01c6 3542 int target = vPC[1].u.operand;
9dae56ea
A
3543 CHECK_FOR_TIMEOUT();
3544 vPC += target;
3545 NEXT_INSTRUCTION();
3546 }
3547 DEFINE_OPCODE(op_jmp) {
3548 /* jmp target(offset)
3549
3550 Jumps unconditionally to offset target from the current
3551 instruction.
3552 */
3553#if ENABLE(OPCODE_STATS)
3554 OpcodeStats::resetLastInstruction();
3555#endif
f9bf01c6 3556 int target = vPC[1].u.operand;
9dae56ea
A
3557
3558 vPC += target;
3559 NEXT_INSTRUCTION();
3560 }
3561 DEFINE_OPCODE(op_loop_if_true) {
3562 /* loop_if_true cond(r) target(offset)
3563
3564 Jumps to offset target from the current instruction, if and
3565 only if register cond converts to boolean as true.
3566
3567 Additionally this loop instruction may terminate JS execution is
3568 the JS timeout is reached.
3569 */
f9bf01c6
A
3570 int cond = vPC[1].u.operand;
3571 int target = vPC[2].u.operand;
ba379fdc 3572 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
9dae56ea
A
3573 vPC += target;
3574 CHECK_FOR_TIMEOUT();
3575 NEXT_INSTRUCTION();
3576 }
3577
f9bf01c6
A
3578 vPC += OPCODE_LENGTH(op_loop_if_true);
3579 NEXT_INSTRUCTION();
3580 }
3581 DEFINE_OPCODE(op_loop_if_false) {
3582 /* loop_if_true cond(r) target(offset)
3583
3584 Jumps to offset target from the current instruction, if and
3585 only if register cond converts to boolean as false.
3586
3587 Additionally this loop instruction may terminate JS execution is
3588 the JS timeout is reached.
3589 */
3590 int cond = vPC[1].u.operand;
3591 int target = vPC[2].u.operand;
3592 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
3593 vPC += target;
3594 CHECK_FOR_TIMEOUT();
3595 NEXT_INSTRUCTION();
3596 }
3597
3598 vPC += OPCODE_LENGTH(op_loop_if_true);
9dae56ea
A
3599 NEXT_INSTRUCTION();
3600 }
3601 DEFINE_OPCODE(op_jtrue) {
3602 /* jtrue cond(r) target(offset)
3603
3604 Jumps to offset target from the current instruction, if and
3605 only if register cond converts to boolean as true.
3606 */
f9bf01c6
A
3607 int cond = vPC[1].u.operand;
3608 int target = vPC[2].u.operand;
ba379fdc 3609 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
9dae56ea
A
3610 vPC += target;
3611 NEXT_INSTRUCTION();
3612 }
3613
f9bf01c6 3614 vPC += OPCODE_LENGTH(op_jtrue);
9dae56ea
A
3615 NEXT_INSTRUCTION();
3616 }
3617 DEFINE_OPCODE(op_jfalse) {
3618 /* jfalse cond(r) target(offset)
3619
3620 Jumps to offset target from the current instruction, if and
3621 only if register cond converts to boolean as false.
3622 */
f9bf01c6
A
3623 int cond = vPC[1].u.operand;
3624 int target = vPC[2].u.operand;
ba379fdc 3625 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
9dae56ea
A
3626 vPC += target;
3627 NEXT_INSTRUCTION();
3628 }
3629
f9bf01c6 3630 vPC += OPCODE_LENGTH(op_jfalse);
9dae56ea
A
3631 NEXT_INSTRUCTION();
3632 }
3633 DEFINE_OPCODE(op_jeq_null) {
3634 /* jeq_null src(r) target(offset)
3635
3636 Jumps to offset target from the current instruction, if and
3637 only if register src is null.
3638 */
f9bf01c6
A
3639 int src = vPC[1].u.operand;
3640 int target = vPC[2].u.operand;
ba379fdc 3641 JSValue srcValue = callFrame->r(src).jsValue();
9dae56ea
A
3642
3643 if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
3644 vPC += target;
3645 NEXT_INSTRUCTION();
3646 }
3647
f9bf01c6 3648 vPC += OPCODE_LENGTH(op_jeq_null);
9dae56ea
A
3649 NEXT_INSTRUCTION();
3650 }
3651 DEFINE_OPCODE(op_jneq_null) {
3652 /* jneq_null src(r) target(offset)
3653
3654 Jumps to offset target from the current instruction, if and
3655 only if register src is not null.
3656 */
f9bf01c6
A
3657 int src = vPC[1].u.operand;
3658 int target = vPC[2].u.operand;
ba379fdc 3659 JSValue srcValue = callFrame->r(src).jsValue();
9dae56ea 3660
f9bf01c6 3661 if (!srcValue.isUndefinedOrNull() && (!srcValue.isCell() || !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
9dae56ea
A
3662 vPC += target;
3663 NEXT_INSTRUCTION();
3664 }
3665
f9bf01c6 3666 vPC += OPCODE_LENGTH(op_jneq_null);
9dae56ea
A
3667 NEXT_INSTRUCTION();
3668 }
ba379fdc
A
3669 DEFINE_OPCODE(op_jneq_ptr) {
3670 /* jneq_ptr src(r) ptr(jsCell) target(offset)
3671
3672 Jumps to offset target from the current instruction, if the value r is equal
3673 to ptr, using pointer equality.
3674 */
f9bf01c6 3675 int src = vPC[1].u.operand;
f9bf01c6 3676 int target = vPC[3].u.operand;
ba379fdc 3677 JSValue srcValue = callFrame->r(src).jsValue();
14957cd0 3678 if (srcValue != vPC[2].u.jsCell.get()) {
ba379fdc
A
3679 vPC += target;
3680 NEXT_INSTRUCTION();
3681 }
3682
f9bf01c6 3683 vPC += OPCODE_LENGTH(op_jneq_ptr);
ba379fdc
A
3684 NEXT_INSTRUCTION();
3685 }
9dae56ea
A
3686 DEFINE_OPCODE(op_loop_if_less) {
3687 /* loop_if_less src1(r) src2(r) target(offset)
3688
3689 Checks whether register src1 is less than register src2, as
3690 with the ECMAScript '<' operator, and then jumps to offset
3691 target from the current instruction, if and only if the
3692 result of the comparison is true.
3693
3694 Additionally this loop instruction may terminate JS execution is
3695 the JS timeout is reached.
3696 */
f9bf01c6
A
3697 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3698 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3699 int target = vPC[3].u.operand;
9dae56ea
A
3700
3701 bool result = jsLess(callFrame, src1, src2);
3702 CHECK_FOR_EXCEPTION();
3703
3704 if (result) {
3705 vPC += target;
3706 CHECK_FOR_TIMEOUT();
3707 NEXT_INSTRUCTION();
3708 }
3709
f9bf01c6 3710 vPC += OPCODE_LENGTH(op_loop_if_less);
9dae56ea
A
3711 NEXT_INSTRUCTION();
3712 }
3713 DEFINE_OPCODE(op_loop_if_lesseq) {
3714 /* loop_if_lesseq src1(r) src2(r) target(offset)
3715
3716 Checks whether register src1 is less than or equal to register
3717 src2, as with the ECMAScript '<=' operator, and then jumps to
3718 offset target from the current instruction, if and only if the
3719 result of the comparison is true.
3720
3721 Additionally this loop instruction may terminate JS execution is
3722 the JS timeout is reached.
3723 */
f9bf01c6
A
3724 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3725 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3726 int target = vPC[3].u.operand;
9dae56ea
A
3727
3728 bool result = jsLessEq(callFrame, src1, src2);
3729 CHECK_FOR_EXCEPTION();
3730
3731 if (result) {
3732 vPC += target;
3733 CHECK_FOR_TIMEOUT();
3734 NEXT_INSTRUCTION();
3735 }
3736
f9bf01c6 3737 vPC += OPCODE_LENGTH(op_loop_if_lesseq);
9dae56ea
A
3738 NEXT_INSTRUCTION();
3739 }
3740 DEFINE_OPCODE(op_jnless) {
3741 /* jnless src1(r) src2(r) target(offset)
3742
3743 Checks whether register src1 is less than register src2, as
3744 with the ECMAScript '<' operator, and then jumps to offset
3745 target from the current instruction, if and only if the
3746 result of the comparison is false.
3747 */
f9bf01c6
A
3748 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3749 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3750 int target = vPC[3].u.operand;
9dae56ea
A
3751
3752 bool result = jsLess(callFrame, src1, src2);
3753 CHECK_FOR_EXCEPTION();
3754
3755 if (!result) {
3756 vPC += target;
3757 NEXT_INSTRUCTION();
3758 }
3759
f9bf01c6
A
3760 vPC += OPCODE_LENGTH(op_jnless);
3761 NEXT_INSTRUCTION();
3762 }
3763 DEFINE_OPCODE(op_jless) {
3764 /* jless src1(r) src2(r) target(offset)
3765
3766 Checks whether register src1 is less than register src2, as
3767 with the ECMAScript '<' operator, and then jumps to offset
3768 target from the current instruction, if and only if the
3769 result of the comparison is true.
3770 */
3771 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3772 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3773 int target = vPC[3].u.operand;
3774
3775 bool result = jsLess(callFrame, src1, src2);
3776 CHECK_FOR_EXCEPTION();
3777
3778 if (result) {
3779 vPC += target;
3780 NEXT_INSTRUCTION();
3781 }
3782
3783 vPC += OPCODE_LENGTH(op_jless);
9dae56ea
A
3784 NEXT_INSTRUCTION();
3785 }
ba379fdc
A
3786 DEFINE_OPCODE(op_jnlesseq) {
3787 /* jnlesseq src1(r) src2(r) target(offset)
3788
3789 Checks whether register src1 is less than or equal to
3790 register src2, as with the ECMAScript '<=' operator,
3791 and then jumps to offset target from the current instruction,
3792 if and only if theresult of the comparison is false.
3793 */
f9bf01c6
A
3794 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3795 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3796 int target = vPC[3].u.operand;
ba379fdc
A
3797
3798 bool result = jsLessEq(callFrame, src1, src2);
3799 CHECK_FOR_EXCEPTION();
3800
3801 if (!result) {
3802 vPC += target;
3803 NEXT_INSTRUCTION();
3804 }
3805
f9bf01c6 3806 vPC += OPCODE_LENGTH(op_jnlesseq);
ba379fdc
A
3807 NEXT_INSTRUCTION();
3808 }
4e4e5a6f
A
3809 DEFINE_OPCODE(op_jlesseq) {
3810 /* jlesseq src1(r) src2(r) target(offset)
3811
3812 Checks whether register src1 is less than or equal to
3813 register src2, as with the ECMAScript '<=' operator,
3814 and then jumps to offset target from the current instruction,
3815 if and only if the result of the comparison is true.
3816 */
3817 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3818 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3819 int target = vPC[3].u.operand;
3820
3821 bool result = jsLessEq(callFrame, src1, src2);
3822 CHECK_FOR_EXCEPTION();
3823
3824 if (result) {
3825 vPC += target;
3826 NEXT_INSTRUCTION();
3827 }
3828
3829 vPC += OPCODE_LENGTH(op_jlesseq);
3830 NEXT_INSTRUCTION();
3831 }
9dae56ea
A
3832 DEFINE_OPCODE(op_switch_imm) {
3833 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3834
3835 Performs a range checked switch on the scrutinee value, using
3836 the tableIndex-th immediate switch jump table. If the scrutinee value
3837 is an immediate number in the range covered by the referenced jump
3838 table, and the value at jumpTable[scrutinee value] is non-zero, then
3839 that value is used as the jump offset, otherwise defaultOffset is used.
3840 */
f9bf01c6
A
3841 int tableIndex = vPC[1].u.operand;
3842 int defaultOffset = vPC[2].u.operand;
3843 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
ba379fdc 3844 if (scrutinee.isInt32())
14957cd0 3845 vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
9dae56ea 3846 else {
ba379fdc
A
3847 double value;
3848 int32_t intValue;
3849 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
14957cd0 3850 vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
9dae56ea
A
3851 else
3852 vPC += defaultOffset;
3853 }
3854 NEXT_INSTRUCTION();
3855 }
3856 DEFINE_OPCODE(op_switch_char) {
3857 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3858
3859 Performs a range checked switch on the scrutinee value, using
3860 the tableIndex-th character switch jump table. If the scrutinee value
3861 is a single character string in the range covered by the referenced jump
3862 table, and the value at jumpTable[scrutinee value] is non-zero, then
3863 that value is used as the jump offset, otherwise defaultOffset is used.
3864 */
f9bf01c6
A
3865 int tableIndex = vPC[1].u.operand;
3866 int defaultOffset = vPC[2].u.operand;
3867 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
9dae56ea
A
3868 if (!scrutinee.isString())
3869 vPC += defaultOffset;
3870 else {
14957cd0 3871 StringImpl* value = asString(scrutinee)->value(callFrame).impl();
4e4e5a6f 3872 if (value->length() != 1)
9dae56ea
A
3873 vPC += defaultOffset;
3874 else
14957cd0 3875 vPC += codeBlock->characterSwitchJumpTable(tableIndex).offsetForValue(value->characters()[0], defaultOffset);
9dae56ea
A
3876 }
3877 NEXT_INSTRUCTION();
3878 }
3879 DEFINE_OPCODE(op_switch_string) {
3880 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3881
3882 Performs a sparse hashmap based switch on the value in the scrutinee
3883 register, using the tableIndex-th string switch jump table. If the
3884 scrutinee value is a string that exists as a key in the referenced
3885 jump table, then the value associated with the string is used as the
3886 jump offset, otherwise defaultOffset is used.
3887 */
f9bf01c6
A
3888 int tableIndex = vPC[1].u.operand;
3889 int defaultOffset = vPC[2].u.operand;
3890 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
9dae56ea
A
3891 if (!scrutinee.isString())
3892 vPC += defaultOffset;
3893 else
14957cd0 3894 vPC += codeBlock->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).impl(), defaultOffset);
9dae56ea
A
3895 NEXT_INSTRUCTION();
3896 }
3897 DEFINE_OPCODE(op_new_func) {
3898 /* new_func dst(r) func(f)
3899
3900 Constructs a new Function instance from function func and
3901 the current scope chain using the original Function
3902 constructor, using the rules for function declarations, and
3903 puts the result in register dst.
3904 */
f9bf01c6
A
3905 int dst = vPC[1].u.operand;
3906 int func = vPC[2].u.operand;
14957cd0
A
3907 int shouldCheck = vPC[3].u.operand;
3908 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
3909 if (!shouldCheck || !callFrame->r(dst).jsValue())
3910 callFrame->uncheckedR(dst) = JSValue(codeBlock->functionDecl(func)->make(callFrame, callFrame->scopeChain()));
9dae56ea 3911
f9bf01c6 3912 vPC += OPCODE_LENGTH(op_new_func);
9dae56ea
A
3913 NEXT_INSTRUCTION();
3914 }
3915 DEFINE_OPCODE(op_new_func_exp) {
3916 /* new_func_exp dst(r) func(f)
3917
3918 Constructs a new Function instance from function func and
3919 the current scope chain using the original Function
3920 constructor, using the rules for function expressions, and
3921 puts the result in register dst.
3922 */
f9bf01c6
A
3923 int dst = vPC[1].u.operand;
3924 int funcIndex = vPC[2].u.operand;
14957cd0
A
3925
3926 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
3927 FunctionExecutable* function = codeBlock->functionExpr(funcIndex);
f9bf01c6
A
3928 JSFunction* func = function->make(callFrame, callFrame->scopeChain());
3929
3930 /*
3931 The Identifier in a FunctionExpression can be referenced from inside
3932 the FunctionExpression's FunctionBody to allow the function to call
3933 itself recursively. However, unlike in a FunctionDeclaration, the
3934 Identifier in a FunctionExpression cannot be referenced from and
3935 does not affect the scope enclosing the FunctionExpression.
3936 */
3937 if (!function->name().isNull()) {
3938 JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete);
14957cd0 3939 func->setScope(*globalData, func->scope()->push(functionScopeObject));
f9bf01c6 3940 }
9dae56ea 3941
14957cd0 3942 callFrame->uncheckedR(dst) = JSValue(func);
f9bf01c6
A
3943
3944 vPC += OPCODE_LENGTH(op_new_func_exp);
9dae56ea
A
3945 NEXT_INSTRUCTION();
3946 }
3947 DEFINE_OPCODE(op_call_eval) {
14957cd0 3948 /* call_eval func(r) argCount(n) registerOffset(n)
9dae56ea
A
3949
3950 Call a function named "eval" with no explicit "this" value
3951 (which may therefore be the eval operator). If register
3952 thisVal is the global object, and register func contains
3953 that global object's original global eval function, then
3954 perform the eval operator in local scope (interpreting
3955 the argument registers as for the "call"
3956 opcode). Otherwise, act exactly as the "call" opcode would.
3957 */
3958
14957cd0
A
3959 int func = vPC[1].u.operand;
3960 int argCount = vPC[2].u.operand;
3961 int registerOffset = vPC[3].u.operand;
3962
3963 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
ba379fdc 3964 JSValue funcVal = callFrame->r(func).jsValue();
9dae56ea
A
3965
3966 Register* newCallFrame = callFrame->registers() + registerOffset;
3967 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
ba379fdc 3968 JSValue thisValue = argv[0].jsValue();
14957cd0 3969 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject.get();
9dae56ea
A
3970
3971 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
14957cd0
A
3972 JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset);
3973 if ((exceptionValue = globalData->exception))
9dae56ea 3974 goto vm_throw;
14957cd0 3975 functionReturnValue = result;
9dae56ea 3976
f9bf01c6 3977 vPC += OPCODE_LENGTH(op_call_eval);
9dae56ea
A
3978 NEXT_INSTRUCTION();
3979 }
3980
3981 // We didn't find the blessed version of eval, so process this
3982 // instruction as a normal function call.
3983 // fall through to op_call
3984 }
3985 DEFINE_OPCODE(op_call) {
14957cd0 3986 /* call func(r) argCount(n) registerOffset(n)
9dae56ea
A
3987
3988 Perform a function call.
3989
3990 registerOffset is the distance the callFrame pointer should move
3991 before the VM initializes the new call frame's header.
3992
3993 dst is where op_ret should store its result.
3994 */
3995
14957cd0
A
3996 int func = vPC[1].u.operand;
3997 int argCount = vPC[2].u.operand;
3998 int registerOffset = vPC[3].u.operand;
9dae56ea 3999
ba379fdc 4000 JSValue v = callFrame->r(func).jsValue();
9dae56ea
A
4001
4002 CallData callData;
14957cd0 4003 CallType callType = getCallData(v, callData);
9dae56ea
A
4004
4005 if (callType == CallTypeJS) {
4006 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
9dae56ea 4007
14957cd0
A
4008 JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
4009 if (UNLIKELY(!!error)) {
4010 exceptionValue = error;
4011 goto vm_throw;
4012 }
9dae56ea 4013
14957cd0
A
4014 CallFrame* previousCallFrame = callFrame;
4015 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
9dae56ea
A
4016 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
4017 if (UNLIKELY(!callFrame)) {
4018 callFrame = previousCallFrame;
4019 exceptionValue = createStackOverflowError(callFrame);
4020 goto vm_throw;
4021 }
4022
14957cd0
A
4023 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
4024 codeBlock = newCodeBlock;
4025 ASSERT(codeBlock == callFrame->codeBlock());
9dae56ea
A
4026 vPC = newCodeBlock->instructions().begin();
4027
4028#if ENABLE(OPCODE_STATS)
4029 OpcodeStats::resetLastInstruction();
4030#endif
4031
4032 NEXT_INSTRUCTION();
4033 }
4034
4035 if (callType == CallTypeHost) {
4036 ScopeChainNode* scopeChain = callFrame->scopeChain();
4037 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
14957cd0
A
4038 if (!registerFile->grow(newCallFrame->registers())) {
4039 exceptionValue = createStackOverflowError(callFrame);
4040 goto vm_throw;
4041 }
9dae56ea 4042
14957cd0 4043 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call), scopeChain, callFrame, argCount, asObject(v));
9dae56ea 4044
ba379fdc 4045 JSValue returnValue;
9dae56ea 4046 {
f9bf01c6 4047 SamplingTool::HostCallRecord callRecord(m_sampler.get());
14957cd0 4048 returnValue = JSValue::decode(callData.native.function(newCallFrame));
9dae56ea
A
4049 }
4050 CHECK_FOR_EXCEPTION();
4051
14957cd0 4052 functionReturnValue = returnValue;
9dae56ea 4053
f9bf01c6 4054 vPC += OPCODE_LENGTH(op_call);
9dae56ea
A
4055 NEXT_INSTRUCTION();
4056 }
4057
4058 ASSERT(callType == CallTypeNone);
4059
14957cd0 4060 exceptionValue = createNotAFunctionError(callFrame, v);
9dae56ea
A
4061 goto vm_throw;
4062 }
ba379fdc 4063 DEFINE_OPCODE(op_load_varargs) {
f9bf01c6
A
4064 int argCountDst = vPC[1].u.operand;
4065 int argsOffset = vPC[2].u.operand;
ba379fdc
A
4066
4067 JSValue arguments = callFrame->r(argsOffset).jsValue();
fb8617cd 4068 uint32_t argCount = 0;
ba379fdc 4069 if (!arguments) {
14957cd0 4070 argCount = (uint32_t)(callFrame->argumentCount());
fb8617cd 4071 argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
ba379fdc
A
4072 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
4073 Register* newEnd = callFrame->registers() + sizeDelta;
4074 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
4075 exceptionValue = createStackOverflowError(callFrame);
4076 goto vm_throw;
4077 }
14957cd0
A
4078 ASSERT(!asFunction(callFrame->callee())->isHostFunction());
4079 int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount();
4080 int32_t inplaceArgs = min(static_cast<int32_t>(argCount), expectedParams);
4081 int32_t i = 0;
ba379fdc
A
4082 Register* argStore = callFrame->registers() + argsOffset;
4083
4084 // First step is to copy the "expected" parameters from their normal location relative to the callframe
4085 for (; i < inplaceArgs; i++)
4086 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
4087 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
14957cd0
A
4088 for (; i < static_cast<int32_t>(argCount); i++)
4089 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - static_cast<int32_t>(argCount) - 1];
ba379fdc
A
4090 } else if (!arguments.isUndefinedOrNull()) {
4091 if (!arguments.isObject()) {
14957cd0 4092 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
ba379fdc
A
4093 goto vm_throw;
4094 }
14957cd0 4095 if (asObject(arguments)->classInfo() == &Arguments::s_info) {
ba379fdc
A
4096 Arguments* args = asArguments(arguments);
4097 argCount = args->numProvidedArguments(callFrame);
fb8617cd 4098 argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
ba379fdc
A
4099 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
4100 Register* newEnd = callFrame->registers() + sizeDelta;
4101 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
4102 exceptionValue = createStackOverflowError(callFrame);
4103 goto vm_throw;
4104 }
4105 args->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
4106 } else if (isJSArray(&callFrame->globalData(), arguments)) {
4107 JSArray* array = asArray(arguments);
4108 argCount = array->length();
fb8617cd 4109 argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
ba379fdc
A
4110 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
4111 Register* newEnd = callFrame->registers() + sizeDelta;
4112 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
4113 exceptionValue = createStackOverflowError(callFrame);
4114 goto vm_throw;
4115 }
4116 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
14957cd0 4117 } else if (asObject(arguments)->inherits(&JSArray::s_info)) {
ba379fdc
A
4118 JSObject* argObject = asObject(arguments);
4119 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
fb8617cd 4120 argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
ba379fdc
A
4121 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
4122 Register* newEnd = callFrame->registers() + sizeDelta;
4123 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
4124 exceptionValue = createStackOverflowError(callFrame);
4125 goto vm_throw;
4126 }
4127 Register* argsBuffer = callFrame->registers() + argsOffset;
fb8617cd 4128 for (uint32_t i = 0; i < argCount; ++i) {
ba379fdc
A
4129 argsBuffer[i] = asObject(arguments)->get(callFrame, i);
4130 CHECK_FOR_EXCEPTION();
4131 }
4132 } else {
14957cd0 4133 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
4e4e5a6f 4134 goto vm_throw;
ba379fdc
A
4135 }
4136 }
4137 CHECK_FOR_EXCEPTION();
14957cd0 4138 callFrame->uncheckedR(argCountDst) = Register::withInt(argCount + 1);
f9bf01c6 4139 vPC += OPCODE_LENGTH(op_load_varargs);
ba379fdc
A
4140 NEXT_INSTRUCTION();
4141 }
4142 DEFINE_OPCODE(op_call_varargs) {
14957cd0 4143 /* call_varargs func(r) argCountReg(r) baseRegisterOffset(n)
ba379fdc
A
4144
4145 Perform a function call with a dynamic set of arguments.
4146
4147 registerOffset is the distance the callFrame pointer should move
4148 before the VM initializes the new call frame's header, excluding
4149 space for arguments.
4150
4151 dst is where op_ret should store its result.
4152 */
4153
14957cd0
A
4154 int func = vPC[1].u.operand;
4155 int argCountReg = vPC[2].u.operand;
4156 int registerOffset = vPC[3].u.operand;
ba379fdc
A
4157
4158 JSValue v = callFrame->r(func).jsValue();
4159 int argCount = callFrame->r(argCountReg).i();
4160 registerOffset += argCount;
4161 CallData callData;
14957cd0 4162 CallType callType = getCallData(v, callData);
ba379fdc
A
4163
4164 if (callType == CallTypeJS) {
4165 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
14957cd0
A
4166
4167 JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
4168 if (UNLIKELY(!!error)) {
4169 exceptionValue = error;
4170 goto vm_throw;
4171 }
4172
ba379fdc 4173 CallFrame* previousCallFrame = callFrame;
14957cd0 4174 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
ba379fdc
A
4175 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
4176 if (UNLIKELY(!callFrame)) {
4177 callFrame = previousCallFrame;
4178 exceptionValue = createStackOverflowError(callFrame);
4179 goto vm_throw;
4180 }
14957cd0
A
4181
4182 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call_varargs), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
4183 codeBlock = newCodeBlock;
4184 ASSERT(codeBlock == callFrame->codeBlock());
ba379fdc
A
4185 vPC = newCodeBlock->instructions().begin();
4186
4187#if ENABLE(OPCODE_STATS)
4188 OpcodeStats::resetLastInstruction();
4189#endif
4190
4191 NEXT_INSTRUCTION();
4192 }
4193
4194 if (callType == CallTypeHost) {
4195 ScopeChainNode* scopeChain = callFrame->scopeChain();
4196 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
14957cd0
A
4197 if (!registerFile->grow(newCallFrame->registers())) {
4198 exceptionValue = createStackOverflowError(callFrame);
4199 goto vm_throw;
4200 }
4201 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_varargs), scopeChain, callFrame, argCount, asObject(v));
ba379fdc
A
4202
4203 JSValue returnValue;
4204 {
f9bf01c6 4205 SamplingTool::HostCallRecord callRecord(m_sampler.get());
14957cd0 4206 returnValue = JSValue::decode(callData.native.function(newCallFrame));
ba379fdc
A
4207 }
4208 CHECK_FOR_EXCEPTION();
4209
14957cd0 4210 functionReturnValue = returnValue;
ba379fdc 4211
f9bf01c6 4212 vPC += OPCODE_LENGTH(op_call_varargs);
ba379fdc
A
4213 NEXT_INSTRUCTION();
4214 }
4215
4216 ASSERT(callType == CallTypeNone);
4217
14957cd0 4218 exceptionValue = createNotAFunctionError(callFrame, v);
ba379fdc
A
4219 goto vm_throw;
4220 }
9dae56ea 4221 DEFINE_OPCODE(op_tear_off_activation) {
14957cd0 4222 /* tear_off_activation activation(r) arguments(r)
9dae56ea 4223
14957cd0
A
4224 Copy locals and named parameters from the register file to the heap.
4225 Point the bindings in 'activation' and 'arguments' to this new backing
4226 store. (Note that 'arguments' may not have been created. If created,
4227 'arguments' already holds a copy of any extra / unnamed parameters.)
9dae56ea 4228
14957cd0 4229 This opcode appears before op_ret in functions that require full scope chains.
9dae56ea
A
4230 */
4231
14957cd0
A
4232 int activation = vPC[1].u.operand;
4233 int arguments = vPC[2].u.operand;
4234 ASSERT(codeBlock->needsFullScopeChain());
4235 JSValue activationValue = callFrame->r(activation).jsValue();
4236 if (activationValue) {
4237 asActivation(activationValue)->copyRegisters(*globalData);
9dae56ea 4238
14957cd0
A
4239 if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
4240 if (!codeBlock->isStrictMode())
4241 asArguments(argumentsValue)->setActivation(*globalData, asActivation(activationValue));
4242 }
4243 } else if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
4244 if (!codeBlock->isStrictMode())
4245 asArguments(argumentsValue)->copyRegisters(*globalData);
4246 }
9dae56ea 4247
f9bf01c6 4248 vPC += OPCODE_LENGTH(op_tear_off_activation);
9dae56ea
A
4249 NEXT_INSTRUCTION();
4250 }
4251 DEFINE_OPCODE(op_tear_off_arguments) {
14957cd0 4252 /* tear_off_arguments arguments(r)
9dae56ea 4253
14957cd0
A
4254 Copy named parameters from the register file to the heap. Point the
4255 bindings in 'arguments' to this new backing store. (Note that
4256 'arguments' may not have been created. If created, 'arguments' already
4257 holds a copy of any extra / unnamed parameters.)
9dae56ea 4258
14957cd0
A
4259 This opcode appears before op_ret in functions that don't require full
4260 scope chains, but do use 'arguments'.
9dae56ea
A
4261 */
4262
14957cd0
A
4263 int src1 = vPC[1].u.operand;
4264 ASSERT(!codeBlock->needsFullScopeChain() && codeBlock->ownerExecutable()->usesArguments());
9dae56ea 4265
14957cd0
A
4266 if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(src1)).jsValue())
4267 asArguments(arguments)->copyRegisters(*globalData);
9dae56ea 4268
f9bf01c6 4269 vPC += OPCODE_LENGTH(op_tear_off_arguments);
9dae56ea
A
4270 NEXT_INSTRUCTION();
4271 }
4272 DEFINE_OPCODE(op_ret) {
14957cd0
A
4273 /* ret result(r)
4274
4275 Return register result as the return value of the current
4276 function call, writing it into functionReturnValue.
4277 In addition, unwind one call frame and restore the scope
4278 chain, code block instruction pointer and register base
4279 to those of the calling function.
4280 */
4281
4282 int result = vPC[1].u.operand;
4283
4284 JSValue returnValue = callFrame->r(result).jsValue();
4285
4286 vPC = callFrame->returnVPC();
4287 callFrame = callFrame->callerFrame();
4288
4289 if (callFrame->hasHostCallFrameFlag())
4290 return returnValue;
4291
4292 functionReturnValue = returnValue;
4293 codeBlock = callFrame->codeBlock();
4294 ASSERT(codeBlock == callFrame->codeBlock());
4295
4296 NEXT_INSTRUCTION();
4297 }
4298 DEFINE_OPCODE(op_call_put_result) {
4299 /* op_call_put_result result(r)
4300
4301 Move call result from functionReturnValue to caller's
4302 expected return value register.
4303 */
4304
4305 callFrame->uncheckedR(vPC[1].u.operand) = functionReturnValue;
4306
4307 vPC += OPCODE_LENGTH(op_call_put_result);
4308 NEXT_INSTRUCTION();
4309 }
4310 DEFINE_OPCODE(op_ret_object_or_this) {
9dae56ea
A
4311 /* ret result(r)
4312
4313 Return register result as the return value of the current
4314 function call, writing it into the caller's expected return
4315 value register. In addition, unwind one call frame and
4316 restore the scope chain, code block instruction pointer and
4317 register base to those of the calling function.
4318 */
4319
f9bf01c6 4320 int result = vPC[1].u.operand;
9dae56ea 4321
ba379fdc 4322 JSValue returnValue = callFrame->r(result).jsValue();
9dae56ea 4323
14957cd0
A
4324 if (UNLIKELY(!returnValue.isObject()))
4325 returnValue = callFrame->r(vPC[2].u.operand).jsValue();
4326
4e4e5a6f 4327 vPC = callFrame->returnVPC();
9dae56ea 4328 callFrame = callFrame->callerFrame();
14957cd0 4329
9dae56ea
A
4330 if (callFrame->hasHostCallFrameFlag())
4331 return returnValue;
4332
14957cd0
A
4333 functionReturnValue = returnValue;
4334 codeBlock = callFrame->codeBlock();
4335 ASSERT(codeBlock == callFrame->codeBlock());
9dae56ea
A
4336
4337 NEXT_INSTRUCTION();
4338 }
4339 DEFINE_OPCODE(op_enter) {
4340 /* enter
4341
14957cd0
A
4342 Initializes local variables to undefined. If the code block requires
4343 an activation, enter_with_activation is used instead.
9dae56ea 4344
14957cd0 4345 This opcode appears only at the beginning of a code block.
9dae56ea
A
4346 */
4347
4348 size_t i = 0;
9dae56ea 4349 for (size_t count = codeBlock->m_numVars; i < count; ++i)
14957cd0 4350 callFrame->uncheckedR(i) = jsUndefined();
9dae56ea 4351
f9bf01c6 4352 vPC += OPCODE_LENGTH(op_enter);
9dae56ea
A
4353 NEXT_INSTRUCTION();
4354 }
14957cd0
A
4355 DEFINE_OPCODE(op_create_activation) {
4356 /* create_activation dst(r)
9dae56ea 4357
14957cd0
A
4358 If the activation object for this callframe has not yet been created,
4359 this creates it and writes it back to dst.
4360 */
4361
4362 int activationReg = vPC[1].u.operand;
4363 if (!callFrame->r(activationReg).jsValue()) {
4364 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable()));
4365 callFrame->r(activationReg) = JSValue(activation);
4366 callFrame->setScopeChain(callFrame->scopeChain()->push(activation));
4367 }
4368 vPC += OPCODE_LENGTH(op_create_activation);
4369 NEXT_INSTRUCTION();
4370 }
4371 DEFINE_OPCODE(op_get_callee) {
4372 /* op_get_callee callee(r)
4373
4374 Move callee into a register.
4375 */
4376
4377 callFrame->uncheckedR(vPC[1].u.operand) = JSValue(callFrame->callee());
4378
4379 vPC += OPCODE_LENGTH(op_get_callee);
4380 NEXT_INSTRUCTION();
4381 }
4382 DEFINE_OPCODE(op_create_this) {
4383 /* op_create_this this(r) proto(r)
4384
4385 Allocate an object as 'this', fr use in construction.
9dae56ea
A
4386
4387 This opcode should only be used at the beginning of a code
4388 block.
4389 */
4390
14957cd0
A
4391 int thisRegister = vPC[1].u.operand;
4392 int protoRegister = vPC[2].u.operand;
9dae56ea 4393
14957cd0
A
4394 JSFunction* constructor = asFunction(callFrame->callee());
4395#if !ASSERT_DISABLED
4396 ConstructData constructData;
4397 ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
4398#endif
9dae56ea 4399
14957cd0
A
4400 Structure* structure;
4401 JSValue proto = callFrame->r(protoRegister).jsValue();
4402 if (proto.isObject())
4403 structure = asObject(proto)->inheritorID(callFrame->globalData());
4404 else
4405 structure = constructor->scope()->globalObject->emptyObjectStructure();
4406 callFrame->uncheckedR(thisRegister) = constructEmptyObject(callFrame, structure);
9dae56ea 4407
14957cd0 4408 vPC += OPCODE_LENGTH(op_create_this);
9dae56ea
A
4409 NEXT_INSTRUCTION();
4410 }
4411 DEFINE_OPCODE(op_convert_this) {
4412 /* convert_this this(r)
4413
4414 Takes the value in the 'this' register, converts it to a
4415 value that is suitable for use as the 'this' value, and
4416 stores it in the 'this' register. This opcode is emitted
4417 to avoid doing the conversion in the caller unnecessarily.
4418
4419 This opcode should only be used at the beginning of a code
4420 block.
4421 */
4422
f9bf01c6 4423 int thisRegister = vPC[1].u.operand;
ba379fdc 4424 JSValue thisVal = callFrame->r(thisRegister).jsValue();
9dae56ea 4425 if (thisVal.needsThisConversion())
14957cd0 4426 callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
9dae56ea 4427
f9bf01c6 4428 vPC += OPCODE_LENGTH(op_convert_this);
9dae56ea
A
4429 NEXT_INSTRUCTION();
4430 }
14957cd0
A
4431 DEFINE_OPCODE(op_convert_this_strict) {
4432 /* convert_this_strict this(r)
4433
4434 Takes the value in the 'this' register, and converts it to
4435 its "this" form if (and only if) "this" is an object with a
4436 custom this conversion
4437
4438 This opcode should only be used at the beginning of a code
4439 block.
4440 */
4441
4442 int thisRegister = vPC[1].u.operand;
4443 JSValue thisVal = callFrame->r(thisRegister).jsValue();
4444 if (thisVal.isObject() && thisVal.needsThisConversion())
4445 callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toStrictThisObject(callFrame));
4446
4447 vPC += OPCODE_LENGTH(op_convert_this_strict);
4448 NEXT_INSTRUCTION();
4449 }
4450 DEFINE_OPCODE(op_init_lazy_reg) {
4451 /* init_lazy_reg dst(r)
9dae56ea 4452
14957cd0 4453 Initialises dst(r) to JSValue().
9dae56ea 4454
14957cd0 4455 This opcode appears only at the beginning of a code block.
ba379fdc 4456 */
14957cd0
A
4457 int dst = vPC[1].u.operand;
4458
4459 callFrame->uncheckedR(dst) = JSValue();
4460 vPC += OPCODE_LENGTH(op_init_lazy_reg);
ba379fdc
A
4461 NEXT_INSTRUCTION();
4462 }
4463 DEFINE_OPCODE(op_create_arguments) {
14957cd0 4464 /* create_arguments dst(r)
9dae56ea 4465
ba379fdc
A
4466 Creates the 'arguments' object and places it in both the
4467 'arguments' call frame slot and the local 'arguments'
4468 register, if it has not already been initialised.
4469 */
9dae56ea 4470
14957cd0
A
4471 int dst = vPC[1].u.operand;
4472
4473 if (!callFrame->r(dst).jsValue()) {
4474 Arguments* arguments = new (globalData) Arguments(callFrame);
4475 callFrame->uncheckedR(dst) = JSValue(arguments);
4476 callFrame->uncheckedR(unmodifiedArgumentsRegister(dst)) = JSValue(arguments);
4477 }
f9bf01c6 4478 vPC += OPCODE_LENGTH(op_create_arguments);
9dae56ea
A
4479 NEXT_INSTRUCTION();
4480 }
4481 DEFINE_OPCODE(op_construct) {
14957cd0 4482 /* construct func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
9dae56ea
A
4483
4484 Invoke register "func" as a constructor. For JS
4485 functions, the calling convention is exactly as for the
4486 "call" opcode, except that the "this" value is a newly
4487 created Object. For native constructors, no "this"
4488 value is passed. In either case, the argCount and registerOffset
4489 registers are interpreted as for the "call" opcode.
4490
4491 Register proto must contain the prototype property of
4492 register func. This is to enable polymorphic inline
4493 caching of this lookup.
4494 */
4495
14957cd0
A
4496 int func = vPC[1].u.operand;
4497 int argCount = vPC[2].u.operand;
4498 int registerOffset = vPC[3].u.operand;
9dae56ea 4499
ba379fdc 4500 JSValue v = callFrame->r(func).jsValue();
9dae56ea
A
4501
4502 ConstructData constructData;
14957cd0 4503 ConstructType constructType = getConstructData(v, constructData);
9dae56ea
A
4504
4505 if (constructType == ConstructTypeJS) {
4506 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
9dae56ea 4507
14957cd0
A
4508 JSObject* error = constructData.js.functionExecutable->compileForConstruct(callFrame, callDataScopeChain);
4509 if (UNLIKELY(!!error)) {
4510 exceptionValue = error;
4511 goto vm_throw;
4512 }
9dae56ea
A
4513
4514 CallFrame* previousCallFrame = callFrame;
14957cd0 4515 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
9dae56ea
A
4516 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
4517 if (UNLIKELY(!callFrame)) {
4518 callFrame = previousCallFrame;
4519 exceptionValue = createStackOverflowError(callFrame);
4520 goto vm_throw;
4521 }
4522
14957cd0
A
4523 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_construct), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
4524 codeBlock = newCodeBlock;
9dae56ea 4525 vPC = newCodeBlock->instructions().begin();
9dae56ea
A
4526#if ENABLE(OPCODE_STATS)
4527 OpcodeStats::resetLastInstruction();
4528#endif
4529
4530 NEXT_INSTRUCTION();
4531 }
4532
4533 if (constructType == ConstructTypeHost) {
9dae56ea
A
4534 ScopeChainNode* scopeChain = callFrame->scopeChain();
4535 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
14957cd0
A
4536 if (!registerFile->grow(newCallFrame->registers())) {
4537 exceptionValue = createStackOverflowError(callFrame);
4538 goto vm_throw;
4539 }
4540 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_construct), scopeChain, callFrame, argCount, asObject(v));
9dae56ea 4541
ba379fdc 4542 JSValue returnValue;
9dae56ea 4543 {
f9bf01c6 4544 SamplingTool::HostCallRecord callRecord(m_sampler.get());
14957cd0 4545 returnValue = JSValue::decode(constructData.native.function(newCallFrame));
9dae56ea
A
4546 }
4547 CHECK_FOR_EXCEPTION();
14957cd0 4548 functionReturnValue = returnValue;
9dae56ea 4549
f9bf01c6 4550 vPC += OPCODE_LENGTH(op_construct);
9dae56ea
A
4551 NEXT_INSTRUCTION();
4552 }
4553
4554 ASSERT(constructType == ConstructTypeNone);
4555
14957cd0 4556 exceptionValue = createNotAConstructorError(callFrame, v);
9dae56ea
A
4557 goto vm_throw;
4558 }
14957cd0
A
4559 DEFINE_OPCODE(op_strcat) {
4560 /* strcat dst(r) src(r) count(n)
9dae56ea 4561
14957cd0
A
4562 Construct a new String instance using the original
4563 constructor, and puts the result in register dst.
4564 The string will be the result of concatenating count
4565 strings with values taken from registers starting at
4566 register src.
9dae56ea 4567 */
f9bf01c6
A
4568 int dst = vPC[1].u.operand;
4569 int src = vPC[2].u.operand;
4570 int count = vPC[3].u.operand;
ba379fdc 4571
14957cd0 4572 callFrame->uncheckedR(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
f9bf01c6
A
4573 CHECK_FOR_EXCEPTION();
4574 vPC += OPCODE_LENGTH(op_strcat);
ba379fdc
A
4575
4576 NEXT_INSTRUCTION();
4577 }
4578 DEFINE_OPCODE(op_to_primitive) {
f9bf01c6
A
4579 int dst = vPC[1].u.operand;
4580 int src = vPC[2].u.operand;
ba379fdc 4581
14957cd0 4582 callFrame->uncheckedR(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);
f9bf01c6 4583 vPC += OPCODE_LENGTH(op_to_primitive);
ba379fdc
A
4584
4585 NEXT_INSTRUCTION();
4586 }
9dae56ea
A
4587 DEFINE_OPCODE(op_push_scope) {
4588 /* push_scope scope(r)
4589
4590 Converts register scope to object, and pushes it onto the top
4591 of the current scope chain. The contents of the register scope
4592 are replaced by the result of toObject conversion of the scope.
4593 */
f9bf01c6 4594 int scope = vPC[1].u.operand;
ba379fdc 4595 JSValue v = callFrame->r(scope).jsValue();
9dae56ea
A
4596 JSObject* o = v.toObject(callFrame);
4597 CHECK_FOR_EXCEPTION();
4598
14957cd0 4599 callFrame->uncheckedR(scope) = JSValue(o);
9dae56ea
A
4600 callFrame->setScopeChain(callFrame->scopeChain()->push(o));
4601
f9bf01c6 4602 vPC += OPCODE_LENGTH(op_push_scope);
9dae56ea
A
4603 NEXT_INSTRUCTION();
4604 }
4605 DEFINE_OPCODE(op_pop_scope) {
4606 /* pop_scope
4607
4608 Removes the top item from the current scope chain.
4609 */
4610 callFrame->setScopeChain(callFrame->scopeChain()->pop());
4611
f9bf01c6 4612 vPC += OPCODE_LENGTH(op_pop_scope);
9dae56ea
A
4613 NEXT_INSTRUCTION();
4614 }
4615 DEFINE_OPCODE(op_get_pnames) {
f9bf01c6 4616 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
9dae56ea
A
4617
4618 Creates a property name list for register base and puts it
f9bf01c6
A
4619 in register dst, initializing i and size for iteration. If
4620 base is undefined or null, jumps to breakTarget.
9dae56ea 4621 */
f9bf01c6
A
4622 int dst = vPC[1].u.operand;
4623 int base = vPC[2].u.operand;
4624 int i = vPC[3].u.operand;
4625 int size = vPC[4].u.operand;
4626 int breakTarget = vPC[5].u.operand;
4627
4628 JSValue v = callFrame->r(base).jsValue();
4629 if (v.isUndefinedOrNull()) {
4630 vPC += breakTarget;
4631 NEXT_INSTRUCTION();
4632 }
4633
4634 JSObject* o = v.toObject(callFrame);
4635 Structure* structure = o->structure();
4636 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
4637 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
4638 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
9dae56ea 4639
14957cd0
A
4640 callFrame->uncheckedR(dst) = jsPropertyNameIterator;
4641 callFrame->uncheckedR(base) = JSValue(o);
4642 callFrame->uncheckedR(i) = Register::withInt(0);
4643 callFrame->uncheckedR(size) = Register::withInt(jsPropertyNameIterator->size());
f9bf01c6 4644 vPC += OPCODE_LENGTH(op_get_pnames);
9dae56ea
A
4645 NEXT_INSTRUCTION();
4646 }
4647 DEFINE_OPCODE(op_next_pname) {
f9bf01c6 4648 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
9dae56ea 4649
f9bf01c6
A
4650 Copies the next name from the property name list in
4651 register iter to dst, then jumps to offset target. If there are no
4652 names left, invalidates the iterator and continues to the next
9dae56ea
A
4653 instruction.
4654 */
f9bf01c6
A
4655 int dst = vPC[1].u.operand;
4656 int base = vPC[2].u.operand;
4657 int i = vPC[3].u.operand;
4658 int size = vPC[4].u.operand;
4659 int iter = vPC[5].u.operand;
4660 int target = vPC[6].u.operand;
9dae56ea 4661
ba379fdc 4662 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
f9bf01c6
A
4663 while (callFrame->r(i).i() != callFrame->r(size).i()) {
4664 JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());
14957cd0
A
4665 CHECK_FOR_EXCEPTION();
4666 callFrame->uncheckedR(i) = Register::withInt(callFrame->r(i).i() + 1);
f9bf01c6
A
4667 if (key) {
4668 CHECK_FOR_TIMEOUT();
14957cd0 4669 callFrame->uncheckedR(dst) = key;
f9bf01c6
A
4670 vPC += target;
4671 NEXT_INSTRUCTION();
4672 }
9dae56ea 4673 }
9dae56ea 4674
f9bf01c6 4675 vPC += OPCODE_LENGTH(op_next_pname);
9dae56ea
A
4676 NEXT_INSTRUCTION();
4677 }
4678 DEFINE_OPCODE(op_jmp_scopes) {
4679 /* jmp_scopes count(n) target(offset)
4680
4681 Removes the a number of items from the current scope chain
4682 specified by immediate number count, then jumps to offset
4683 target.
4684 */
f9bf01c6
A
4685 int count = vPC[1].u.operand;
4686 int target = vPC[2].u.operand;
9dae56ea
A
4687
4688 ScopeChainNode* tmp = callFrame->scopeChain();
4689 while (count--)
4690 tmp = tmp->pop();
4691 callFrame->setScopeChain(tmp);
4692
4693 vPC += target;
4694 NEXT_INSTRUCTION();
4695 }
4e4e5a6f 4696#if ENABLE(COMPUTED_GOTO_INTERPRETER)
9dae56ea
A
4697 // Appease GCC
4698 goto *(&&skip_new_scope);
4699#endif
4700 DEFINE_OPCODE(op_push_new_scope) {
4701 /* new_scope dst(r) property(id) value(r)
4702
4703 Constructs a new StaticScopeObject with property set to value. That scope
4704 object is then pushed onto the ScopeChain. The scope object is then stored
4705 in dst for GC.
4706 */
4707 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));
4708
f9bf01c6 4709 vPC += OPCODE_LENGTH(op_push_new_scope);
9dae56ea
A
4710 NEXT_INSTRUCTION();
4711 }
4e4e5a6f 4712#if ENABLE(COMPUTED_GOTO_INTERPRETER)
9dae56ea
A
4713 skip_new_scope:
4714#endif
4715 DEFINE_OPCODE(op_catch) {
4716 /* catch ex(r)
4717
ba379fdc 4718 Retrieves the VM's current exception and puts it in register
9dae56ea
A
4719 ex. This is only valid after an exception has been raised,
4720 and usually forms the beginning of an exception handler.
4721 */
4722 ASSERT(exceptionValue);
4723 ASSERT(!globalData->exception);
f9bf01c6 4724 int ex = vPC[1].u.operand;
14957cd0 4725 callFrame->uncheckedR(ex) = exceptionValue;
ba379fdc 4726 exceptionValue = JSValue();
9dae56ea 4727
f9bf01c6 4728 vPC += OPCODE_LENGTH(op_catch);
9dae56ea
A
4729 NEXT_INSTRUCTION();
4730 }
4731 DEFINE_OPCODE(op_throw) {
4732 /* throw ex(r)
4733
4734 Throws register ex as an exception. This involves three
4735 steps: first, it is set as the current exception in the
4736 VM's internal state, then the stack is unwound until an
4737 exception handler or a native code boundary is found, and
4738 then control resumes at the exception handler if any or
4739 else the script returns control to the nearest native caller.
4740 */
4741
f9bf01c6 4742 int ex = vPC[1].u.operand;
ba379fdc 4743 exceptionValue = callFrame->r(ex).jsValue();
9dae56ea 4744
14957cd0
A
4745 handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
4746 if (!handler)
4747 return throwError(callFrame, exceptionValue);
9dae56ea 4748
14957cd0
A
4749 codeBlock = callFrame->codeBlock();
4750 vPC = codeBlock->instructions().begin() + handler->target;
9dae56ea
A
4751 NEXT_INSTRUCTION();
4752 }
14957cd0
A
4753 DEFINE_OPCODE(op_throw_reference_error) {
4754 /* op_throw_reference_error message(k)
9dae56ea 4755
14957cd0
A
4756 Constructs a new reference Error instance using the
4757 original constructor, using constant message as the
4758 message string. The result is thrown.
9dae56ea 4759 */
14957cd0
A
4760 UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame);
4761 exceptionValue = JSValue(createReferenceError(callFrame, message));
4762 goto vm_throw;
9dae56ea
A
4763 }
4764 DEFINE_OPCODE(op_end) {
4765 /* end result(r)
4766
4767 Return register result as the value of a global or eval
4768 program. Return control to the calling native code.
4769 */
4770
f9bf01c6 4771 int result = vPC[1].u.operand;
ba379fdc 4772 return callFrame->r(result).jsValue();
9dae56ea
A
4773 }
4774 DEFINE_OPCODE(op_put_getter) {
4775 /* put_getter base(r) property(id) function(r)
4776
4777 Sets register function on register base as the getter named
4778 by identifier property. Base and function are assumed to be
4779 objects as this op should only be used for getters defined
4780 in object literal form.
4781
4782 Unlike many opcodes, this one does not write any output to
4783 the register file.
4784 */
f9bf01c6
A
4785 int base = vPC[1].u.operand;
4786 int property = vPC[2].u.operand;
4787 int function = vPC[3].u.operand;
9dae56ea 4788
ba379fdc
A
4789 ASSERT(callFrame->r(base).jsValue().isObject());
4790 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
14957cd0 4791 Identifier& ident = codeBlock->identifier(property);
ba379fdc
A
4792 ASSERT(callFrame->r(function).jsValue().isObject());
4793 baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue()));
9dae56ea 4794
f9bf01c6 4795 vPC += OPCODE_LENGTH(op_put_getter);
9dae56ea
A
4796 NEXT_INSTRUCTION();
4797 }
4798 DEFINE_OPCODE(op_put_setter) {
4799 /* put_setter base(r) property(id) function(r)
4800
4801 Sets register function on register base as the setter named
4802 by identifier property. Base and function are assumed to be
4803 objects as this op should only be used for setters defined
4804 in object literal form.
4805
4806 Unlike many opcodes, this one does not write any output to
4807 the register file.
4808 */
f9bf01c6
A
4809 int base = vPC[1].u.operand;
4810 int property = vPC[2].u.operand;
4811 int function = vPC[3].u.operand;
9dae56ea 4812
ba379fdc
A
4813 ASSERT(callFrame->r(base).jsValue().isObject());
4814 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
14957cd0 4815 Identifier& ident = codeBlock->identifier(property);
ba379fdc 4816 ASSERT(callFrame->r(function).jsValue().isObject());
f9bf01c6 4817 baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
9dae56ea 4818
f9bf01c6 4819 vPC += OPCODE_LENGTH(op_put_setter);
9dae56ea
A
4820 NEXT_INSTRUCTION();
4821 }
ba379fdc
A
4822 DEFINE_OPCODE(op_method_check) {
4823 vPC++;
4824 NEXT_INSTRUCTION();
4825 }
9dae56ea
A
4826 DEFINE_OPCODE(op_jsr) {
4827 /* jsr retAddrDst(r) target(offset)
4828
4829 Places the address of the next instruction into the retAddrDst
4830 register and jumps to offset target from the current instruction.
4831 */
f9bf01c6
A
4832 int retAddrDst = vPC[1].u.operand;
4833 int target = vPC[2].u.operand;
4834 callFrame->r(retAddrDst) = vPC + OPCODE_LENGTH(op_jsr);
9dae56ea
A
4835
4836 vPC += target;
4837 NEXT_INSTRUCTION();
4838 }
4839 DEFINE_OPCODE(op_sret) {
4840 /* sret retAddrSrc(r)
4841
4842 Jumps to the address stored in the retAddrSrc register. This
4843 differs from op_jmp because the target address is stored in a
4844 register, not as an immediate.
4845 */
f9bf01c6 4846 int retAddrSrc = vPC[1].u.operand;
ba379fdc 4847 vPC = callFrame->r(retAddrSrc).vPC();
9dae56ea
A
4848 NEXT_INSTRUCTION();
4849 }
4850 DEFINE_OPCODE(op_debug) {
4851 /* debug debugHookID(n) firstLine(n) lastLine(n)
4852
4853 Notifies the debugger of the current state of execution. This opcode
4854 is only generated while the debugger is attached.
4855 */
f9bf01c6
A
4856 int debugHookID = vPC[1].u.operand;
4857 int firstLine = vPC[2].u.operand;
4858 int lastLine = vPC[3].u.operand;
9dae56ea
A
4859
4860 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
4861
f9bf01c6 4862 vPC += OPCODE_LENGTH(op_debug);
9dae56ea
A
4863 NEXT_INSTRUCTION();
4864 }
4865 DEFINE_OPCODE(op_profile_will_call) {
4866 /* op_profile_will_call function(r)
4867
4868 Notifies the profiler of the beginning of a function call. This opcode
4869 is only generated if developer tools are enabled.
4870 */
4871 int function = vPC[1].u.operand;
4872
4873 if (*enabledProfilerReference)
ba379fdc 4874 (*enabledProfilerReference)->willExecute(callFrame, callFrame->r(function).jsValue());
9dae56ea 4875
f9bf01c6 4876 vPC += OPCODE_LENGTH(op_profile_will_call);
9dae56ea
A
4877 NEXT_INSTRUCTION();
4878 }
4879 DEFINE_OPCODE(op_profile_did_call) {
4880 /* op_profile_did_call function(r)
4881
4882 Notifies the profiler of the end of a function call. This opcode
4883 is only generated if developer tools are enabled.
4884 */
4885 int function = vPC[1].u.operand;
4886
4887 if (*enabledProfilerReference)
ba379fdc 4888 (*enabledProfilerReference)->didExecute(callFrame, callFrame->r(function).jsValue());
9dae56ea 4889
f9bf01c6 4890 vPC += OPCODE_LENGTH(op_profile_did_call);
9dae56ea
A
4891 NEXT_INSTRUCTION();
4892 }
4893 vm_throw: {
ba379fdc 4894 globalData->exception = JSValue();
9dae56ea
A
4895 if (!tickCount) {
4896 // The exceptionValue is a lie! (GCC produces bad code for reasons I
4897 // cannot fathom if we don't assign to the exceptionValue before branching)
4898 exceptionValue = createInterruptedExecutionException(globalData);
4899 }
14957cd0
A
4900 JSGlobalObject* globalObject = callFrame->lexicalGlobalObject();
4901 handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
9dae56ea 4902 if (!handler) {
14957cd0
A
4903 // Can't use the callframe at this point as the scopechain, etc have
4904 // been released.
4905 return throwError(globalObject->globalExec(), exceptionValue);
9dae56ea
A
4906 }
4907
14957cd0
A
4908 codeBlock = callFrame->codeBlock();
4909 vPC = codeBlock->instructions().begin() + handler->target;
9dae56ea
A
4910 NEXT_INSTRUCTION();
4911 }
4912 }
4e4e5a6f 4913#if !ENABLE(COMPUTED_GOTO_INTERPRETER)
9dae56ea
A
4914 } // iterator loop ends
4915#endif
4916 #undef NEXT_INSTRUCTION
4917 #undef DEFINE_OPCODE
4918 #undef CHECK_FOR_EXCEPTION
4919 #undef CHECK_FOR_TIMEOUT
4e4e5a6f 4920#endif // ENABLE(INTERPRETER)
9dae56ea
A
4921}
4922
ba379fdc 4923JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
9dae56ea
A
4924{
4925 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
4926 if (!functionCallFrame)
4927 return jsNull();
4928
4929 CodeBlock* codeBlock = functionCallFrame->codeBlock();
4930 if (codeBlock->usesArguments()) {
4931 ASSERT(codeBlock->codeType() == FunctionCode);
14957cd0
A
4932 int argumentsRegister = codeBlock->argumentsRegister();
4933 int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);
4934 if (JSValue arguments = functionCallFrame->uncheckedR(argumentsRegister).jsValue())
4935 return arguments;
4936 JSValue arguments = JSValue(new (callFrame) Arguments(functionCallFrame));
4937 functionCallFrame->r(argumentsRegister) = arguments;
4938 functionCallFrame->r(realArgumentsRegister) = arguments;
4939 return arguments;
4940 }
4941
4942 Arguments* arguments = new (functionCallFrame) Arguments(functionCallFrame);
4943 arguments->copyRegisters(functionCallFrame->globalData());
9dae56ea
A
4944 return arguments;
4945}
4946
14957cd0 4947JSValue Interpreter::retrieveCaller(CallFrame* callFrame, JSFunction* function) const
9dae56ea
A
4948{
4949 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
4950 if (!functionCallFrame)
4951 return jsNull();
4952
4953 CallFrame* callerFrame = functionCallFrame->callerFrame();
4954 if (callerFrame->hasHostCallFrameFlag())
4955 return jsNull();
4956
ba379fdc 4957 JSValue caller = callerFrame->callee();
9dae56ea
A
4958 if (!caller)
4959 return jsNull();
4960
4961 return caller;
4962}
4963
ba379fdc 4964void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const
9dae56ea 4965{
ba379fdc 4966 function = JSValue();
9dae56ea
A
4967 lineNumber = -1;
4968 sourceURL = UString();
4969
4970 CallFrame* callerFrame = callFrame->callerFrame();
4971 if (callerFrame->hasHostCallFrameFlag())
4972 return;
4973
4974 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
4975 if (!callerCodeBlock)
4976 return;
4e4e5a6f
A
4977 unsigned bytecodeOffset = 0;
4978#if ENABLE(INTERPRETER)
4979 if (!callerFrame->globalData().canUseJIT())
14957cd0 4980 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());
4e4e5a6f
A
4981#if ENABLE(JIT)
4982 else
14957cd0 4983 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
4e4e5a6f
A
4984#endif
4985#else
14957cd0 4986 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
4e4e5a6f 4987#endif
14957cd0 4988 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);
f9bf01c6
A
4989 sourceID = callerCodeBlock->ownerExecutable()->sourceID();
4990 sourceURL = callerCodeBlock->ownerExecutable()->sourceURL();
9dae56ea
A
4991 function = callerFrame->callee();
4992}
4993
14957cd0 4994CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, JSFunction* function)
9dae56ea
A
4995{
4996 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
4997 if (candidate->callee() == function)
4998 return candidate;
4999 }
5000 return 0;
5001}
5002
f9bf01c6
A
5003void Interpreter::enableSampler()
5004{
5005#if ENABLE(OPCODE_SAMPLING)
5006 if (!m_sampler) {
5007 m_sampler.set(new SamplingTool(this));
5008 m_sampler->setup();
5009 }
5010#endif
5011}
5012void Interpreter::dumpSampleData(ExecState* exec)
5013{
5014#if ENABLE(OPCODE_SAMPLING)
5015 if (m_sampler)
5016 m_sampler->dump(exec);
5017#else
5018 UNUSED_PARAM(exec);
5019#endif
5020}
5021void Interpreter::startSampling()
5022{
5023#if ENABLE(SAMPLING_THREAD)
5024 if (!m_sampleEntryDepth)
5025 SamplingThread::start();
5026
5027 m_sampleEntryDepth++;
5028#endif
5029}
5030void Interpreter::stopSampling()
5031{
5032#if ENABLE(SAMPLING_THREAD)
5033 m_sampleEntryDepth--;
5034 if (!m_sampleEntryDepth)
5035 SamplingThread::stop();
5036#endif
5037}
5038
9dae56ea 5039} // namespace JSC