1/*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
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"
35#include "CallFrame.h"
36#include "CallFrameClosure.h"
37#include "CodeBlock.h"
38#include "Collector.h"
39#include "Debugger.h"
40#include "DebuggerCallFrame.h"
41#include "EvalCodeCache.h"
42#include "ExceptionHelpers.h"
43#include "GlobalEvalFunction.h"
44#include "JSActivation.h"
45#include "JSArray.h"
46#include "JSByteArray.h"
47#include "JSFunction.h"
48#include "JSNotAnObject.h"
49#include "JSPropertyNameIterator.h"
50#include "LiteralParser.h"
51#include "JSStaticScopeObject.h"
52#include "JSString.h"
53#include "ObjectPrototype.h"
54#include "Operations.h"
55#include "Parser.h"
56#include "Profiler.h"
57#include "RegExpObject.h"
58#include "RegExpPrototype.h"
59#include "Register.h"
60#include "SamplingTool.h"
61#include <limits.h>
62#include <stdio.h>
63#include <wtf/Threading.h>
64
65#if ENABLE(JIT)
66#include "JIT.h"
67#endif
68
69#ifdef QT_BUILD_SCRIPT_LIB
70#include "bridge/qscriptobject_p.h"
71#endif
72
73using namespace std;
74
75namespace JSC {
76
77static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, void* pc)
78{
79#if ENABLE(JIT)
80 return codeBlock->getBytecodeIndex(callFrame, returnAddress: ReturnAddressPtr(pc));
81#else
82 UNUSED_PARAM(callFrame);
83 return static_cast<Instruction*>(pc) - codeBlock->instructions().begin();
84#endif
85}
86
87// Returns the depth of the scope chain within a given call frame.
88static int depth(CodeBlock* codeBlock, ScopeChain& sc)
89{
90 if (!codeBlock->needsFullScopeChain())
91 return 0;
92 return sc.localDepth();
93}
94
95#if USE(INTERPRETER)
96NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
97{
98 int dst = vPC[1].u.operand;
99 int property = vPC[2].u.operand;
100
101 ScopeChainNode* scopeChain = callFrame->scopeChain();
102 ScopeChainIterator iter = scopeChain->begin();
103 ScopeChainIterator end = scopeChain->end();
104 ASSERT(iter != end);
105
106 CodeBlock* codeBlock = callFrame->codeBlock();
107 Identifier& ident = codeBlock->identifier(index: property);
108 do {
109 JSObject* o = *iter;
110 PropertySlot slot(o);
111 if (o->getPropertySlot(exec: callFrame, propertyName: ident, slot)) {
112 JSValue result = slot.getValue(exec: callFrame, propertyName: ident);
113 exceptionValue = callFrame->globalData().exception;
114 if (exceptionValue)
115 return false;
116 callFrame->r(index: dst) = JSValue(result);
117 return true;
118 }
119 } while (++iter != end);
120 exceptionValue = createUndefinedVariableError(callFrame, ident, bytecodeOffset: vPC - codeBlock->instructions().begin(), codeBlock);
121 return false;
122}
123
124NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
125{
126 CodeBlock* codeBlock = callFrame->codeBlock();
127
128 int dst = vPC[1].u.operand;
129 int property = vPC[2].u.operand;
130 int skip = vPC[3].u.operand + codeBlock->needsFullScopeChain();
131
132 ScopeChainNode* scopeChain = callFrame->scopeChain();
133 ScopeChainIterator iter = scopeChain->begin();
134 ScopeChainIterator end = scopeChain->end();
135 ASSERT(iter != end);
136 while (skip--) {
137 ++iter;
138 ASSERT(iter != end);
139 }
140 Identifier& ident = codeBlock->identifier(index: property);
141 do {
142 JSObject* o = *iter;
143 PropertySlot slot(o);
144 if (o->getPropertySlot(exec: callFrame, propertyName: ident, slot)) {
145 JSValue result = slot.getValue(exec: callFrame, propertyName: ident);
146 exceptionValue = callFrame->globalData().exception;
147 if (exceptionValue)
148 return false;
149 callFrame->r(index: dst) = JSValue(result);
150 return true;
151 }
152 } while (++iter != end);
153 exceptionValue = createUndefinedVariableError(callFrame, ident, bytecodeOffset: vPC - codeBlock->instructions().begin(), codeBlock);
154 return false;
155}
156
157NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
158{
159 int dst = vPC[1].u.operand;
160 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
161 ASSERT(globalObject->isGlobalObject());
162 int property = vPC[3].u.operand;
163 Structure* structure = vPC[4].u.structure;
164 int offset = vPC[5].u.operand;
165
166 if (structure == globalObject->structure()) {
167 callFrame->r(index: dst) = JSValue(globalObject->getDirectOffset(offset));
168 return true;
169 }
170
171 CodeBlock* codeBlock = callFrame->codeBlock();
172 Identifier& ident = codeBlock->identifier(index: property);
173 PropertySlot slot(globalObject);
174 if (globalObject->getPropertySlot(exec: callFrame, propertyName: ident, slot)) {
175 JSValue result = slot.getValue(exec: callFrame, propertyName: ident);
176 if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
177 if (vPC[4].u.structure)
178 vPC[4].u.structure->deref();
179 globalObject->structure()->ref();
180 vPC[4] = globalObject->structure();
181 vPC[5] = slot.cachedOffset();
182 callFrame->r(index: dst) = JSValue(result);
183 return true;
184 }
185
186 exceptionValue = callFrame->globalData().exception;
187 if (exceptionValue)
188 return false;
189 callFrame->r(index: dst) = JSValue(result);
190 return true;
191 }
192
193 exceptionValue = createUndefinedVariableError(callFrame, ident, bytecodeOffset: vPC - codeBlock->instructions().begin(), codeBlock);
194 return false;
195}
196
197NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
198{
199 int dst = vPC[1].u.operand;
200 int property = vPC[2].u.operand;
201 callFrame->r(index: dst) = JSValue(JSC::resolveBase(callFrame, property&: callFrame->codeBlock()->identifier(index: property), scopeChain: callFrame->scopeChain()));
202}
203
204NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
205{
206 int baseDst = vPC[1].u.operand;
207 int propDst = vPC[2].u.operand;
208 int property = vPC[3].u.operand;
209
210 ScopeChainNode* scopeChain = callFrame->scopeChain();
211 ScopeChainIterator iter = scopeChain->begin();
212 ScopeChainIterator end = scopeChain->end();
213
214 // FIXME: add scopeDepthIsZero optimization
215
216 ASSERT(iter != end);
217
218 CodeBlock* codeBlock = callFrame->codeBlock();
219 Identifier& ident = codeBlock->identifier(index: property);
220 JSObject* base;
221 do {
222 base = *iter;
223 PropertySlot slot(base);
224 if (base->getPropertySlot(exec: callFrame, propertyName: ident, slot)) {
225 JSValue result = slot.getValue(exec: callFrame, propertyName: ident);
226 exceptionValue = callFrame->globalData().exception;
227 if (exceptionValue)
228 return false;
229 callFrame->r(index: propDst) = JSValue(result);
230 callFrame->r(index: baseDst) = JSValue(base);
231 return true;
232 }
233 ++iter;
234 } while (iter != end);
235
236 exceptionValue = createUndefinedVariableError(callFrame, ident, bytecodeOffset: vPC - codeBlock->instructions().begin(), codeBlock);
237 return false;
238}
239
240#endif // USE(INTERPRETER)
241
242ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
243{
244 Register* r = callFrame->registers();
245 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters;
246
247 if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments
248 if (UNLIKELY(!registerFile->grow(newEnd)))
249 return 0;
250 r += registerOffset;
251 } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks
252 size_t omittedArgCount = newCodeBlock->m_numParameters - argc;
253 registerOffset += omittedArgCount;
254 newEnd += omittedArgCount;
255 if (!registerFile->grow(newEnd))
256 return 0;
257 r += registerOffset;
258
259 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
260 for (size_t i = 0; i < omittedArgCount; ++i)
261 argv[i] = jsUndefined();
262 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
263 size_t numParameters = newCodeBlock->m_numParameters;
264 registerOffset += numParameters;
265 newEnd += numParameters;
266
267 if (!registerFile->grow(newEnd))
268 return 0;
269 r += registerOffset;
270
271 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
272 for (size_t i = 0; i < numParameters; ++i)
273 argv[i + argc] = argv[i];
274 }
275
276 return CallFrame::create(callFrameBase: r);
277}
278
279#if USE(INTERPRETER)
280static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
281{
282 if (value.isObject())
283 return false;
284 exceptionData = createInvalidParamError(callFrame, op: "in" , value, bytecodeOffset: vPC - codeBlock->instructions().begin(), codeBlock);
285 return true;
286}
287
288static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
289{
290 if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
291 return false;
292 exceptionData = createInvalidParamError(callFrame, op: "instanceof" , value, bytecodeOffset: vPC - codeBlock->instructions().begin(), codeBlock);
293 return true;
294}
295#endif
296
297NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue& exceptionValue)
298{
299 if (argc < 2)
300 return jsUndefined();
301
302 JSValue program = argv[1].jsValue();
303
304 if (!program.isString())
305 return program;
306
307 UString programSource = asString(value: program)->value(exec: callFrame);
308
309 LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
310 if (JSValue parsedObject = preparser.tryLiteralParse())
311 return parsedObject;
312
313 ScopeChainNode* scopeChain = callFrame->scopeChain();
314 CodeBlock* codeBlock = callFrame->codeBlock();
315 RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(exec: callFrame, evalSource: programSource, scopeChain, exceptionValue);
316
317 JSValue result = jsUndefined();
318 if (eval)
319 result = callFrame->globalData().interpreter->execute(eval.get(), callFrame, thisObject: callFrame->thisValue().toThisObject(exec: callFrame), globalRegisterOffset: callFrame->registers() - registerFile->start() + registerOffset, scopeChain, exception: &exceptionValue);
320
321 return result;
322}
323
324Interpreter::Interpreter()
325 : m_sampleEntryDepth(0)
326 , m_reentryDepth(0)
327{
328#if HAVE(COMPUTED_GOTO)
329 privateExecute(InitializeAndReturn, 0, 0, 0);
330
331 for (int i = 0; i < numOpcodeIDs; ++i)
332 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
333#endif // HAVE(COMPUTED_GOTO)
334
335#if ENABLE(OPCODE_SAMPLING)
336 enableSampler();
337#endif
338}
339
340#ifndef NDEBUG
341
342void Interpreter::dumpCallFrame(CallFrame* callFrame)
343{
344 callFrame->codeBlock()->dump(callFrame);
345 dumpRegisters(callFrame);
346}
347
348void Interpreter::dumpRegisters(CallFrame* callFrame)
349{
350 printf(format: "Register frame: \n\n");
351 printf(format: "-----------------------------------------------------------------------------\n");
352 printf(format: " use | address | value \n");
353 printf(format: "-----------------------------------------------------------------------------\n");
354
355 CodeBlock* codeBlock = callFrame->codeBlock();
356 RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData()->interpreter->registerFile();
357 const Register* it;
358 const Register* end;
359 JSValue v;
360
361 if (codeBlock->codeType() == GlobalCode) {
362 it = registerFile->lastGlobal();
363 end = it + registerFile->numGlobals();
364 while (it != end) {
365 v = (*it).jsValue();
366#if USE(JSVALUE32_64)
367 printf("[global var] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
368#else
369 printf(format: "[global var] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(value: v));
370#endif
371 ++it;
372 }
373 printf(format: "-----------------------------------------------------------------------------\n");
374 }
375
376 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters;
377 v = (*it).jsValue();
378#if USE(JSVALUE32_64)
379 printf("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it;
380#else
381 printf(format: "[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(value: v)); ++it;
382#endif
383 end = it + max(a: codeBlock->m_numParameters - 1, b: 0); // - 1 to skip "this"
384 if (it != end) {
385 do {
386 v = (*it).jsValue();
387#if USE(JSVALUE32_64)
388 printf("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
389#else
390 printf(format: "[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(value: v));
391#endif
392 ++it;
393 } while (it != end);
394 }
395 printf(format: "-----------------------------------------------------------------------------\n");
396 printf(format: "[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it;
397 printf(format: "[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
398 printf(format: "[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
399 printf(format: "[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
400 printf(format: "[ReturnValueRegister] | %10p | %d \n", it, (*it).i()); ++it;
401 printf(format: "[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
402 printf(format: "[Callee] | %10p | %p \n", it, (*it).object()); ++it;
403 printf(format: "[OptionalCalleeArguments] | %10p | %p \n", it, (*it).arguments()); ++it;
404 printf(format: "-----------------------------------------------------------------------------\n");
405
406 int registerCount = 0;
407
408 end = it + codeBlock->m_numVars;
409 if (it != end) {
410 do {
411 v = (*it).jsValue();
412#if USE(JSVALUE32_64)
413 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
414#else
415 printf(format: "[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(value: v));
416#endif
417 ++it;
418 ++registerCount;
419 } while (it != end);
420 }
421 printf(format: "-----------------------------------------------------------------------------\n");
422
423 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
424 if (it != end) {
425 do {
426 v = (*it).jsValue();
427#if USE(JSVALUE32_64)
428 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
429#else
430 printf(format: "[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(value: v));
431#endif
432 ++it;
433 ++registerCount;
434 } while (it != end);
435 }
436 printf(format: "-----------------------------------------------------------------------------\n");
437}
438
439#endif
440
441bool Interpreter::isOpcode(Opcode opcode)
442{
443#if HAVE(COMPUTED_GOTO)
444 return opcode != HashTraits<Opcode>::emptyValue()
445 && !HashTraits<Opcode>::isDeletedValue(opcode)
446 && m_opcodeIDTable.contains(opcode);
447#else
448 return opcode >= 0 && opcode <= op_end;
449#endif
450}
451
452NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
453{
454 CodeBlock* oldCodeBlock = codeBlock;
455 ScopeChainNode* scopeChain = callFrame->scopeChain();
456
457 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
458 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
459 if (callFrame->callee()) {
460 debugger->returnEvent(debuggerCallFrame, sourceID: codeBlock->ownerExecutable()->sourceID(), lineNumber: codeBlock->ownerExecutable()->lastLine());
461#ifdef QT_BUILD_SCRIPT_LIB
462 debugger->functionExit(returnValue: exceptionValue, sourceID: codeBlock->ownerExecutable()->sourceID());
463#endif
464 } else
465 debugger->didExecuteProgram(debuggerCallFrame, sourceID: codeBlock->ownerExecutable()->sourceID(), lineNumber: codeBlock->ownerExecutable()->lastLine());
466 }
467
468 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
469 if (callFrame->callee())
470 profiler->didExecute(callFrame, function: callFrame->callee());
471 else
472 profiler->didExecute(callFrame, sourceURL: codeBlock->ownerExecutable()->sourceURL(), startingLineNumber: codeBlock->ownerExecutable()->lineNo());
473 }
474
475 // If this call frame created an activation or an 'arguments' object, tear it off.
476 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
477 while (!scopeChain->object->inherits(info: &JSActivation::info))
478 scopeChain = scopeChain->pop();
479 static_cast<JSActivation*>(scopeChain->object)->copyRegisters(arguments: callFrame->optionalCalleeArguments());
480 } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) {
481 if (!arguments->isTornOff())
482 arguments->copyRegisters();
483 }
484
485 if (oldCodeBlock->needsFullScopeChain())
486 scopeChain->deref();
487
488 void* returnPC = callFrame->returnPC();
489 callFrame = callFrame->callerFrame();
490 if (callFrame->hasHostCallFrameFlag())
491 return false;
492
493 codeBlock = callFrame->codeBlock();
494 bytecodeOffset = bytecodeOffsetForPC(callFrame, codeBlock, pc: returnPC);
495 return true;
496}
497
498NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset, bool explicitThrow)
499{
500 // Set up the exception object
501
502 CodeBlock* codeBlock = callFrame->codeBlock();
503 if (exceptionValue.isObject()) {
504 JSObject* exception = asObject(value: exceptionValue);
505 if (exception->isNotAnObjectErrorStub()) {
506 exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock);
507 exceptionValue = exception;
508 } else {
509 if (!exception->hasProperty(callFrame, propertyName: Identifier(callFrame, JSC_ERROR_LINENUMBER_PROPERTYNAME)) &&
510 !exception->hasProperty(callFrame, propertyName: Identifier(callFrame, "sourceId")) &&
511 !exception->hasProperty(callFrame, propertyName: Identifier(callFrame, JSC_ERROR_FILENAME_PROPERTYNAME)) &&
512 !exception->hasProperty(callFrame, propertyName: Identifier(callFrame, expressionBeginOffsetPropertyName)) &&
513 !exception->hasProperty(callFrame, propertyName: Identifier(callFrame, expressionCaretOffsetPropertyName)) &&
514 !exception->hasProperty(callFrame, propertyName: Identifier(callFrame, expressionEndOffsetPropertyName))) {
515 if (explicitThrow) {
516 int startOffset = 0;
517 int endOffset = 0;
518 int divotPoint = 0;
519 int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divot&: divotPoint, startOffset, endOffset);
520 exception->putWithAttributes(callFrame, propertyName: Identifier(callFrame, JSC_ERROR_LINENUMBER_PROPERTYNAME), value: jsNumber(exec: callFrame, i: line), attributes: ReadOnly | DontDelete);
521
522 // We only hit this path for error messages and throw statements, which don't have a specific failure position
523 // So we just give the full range of the error/throw statement.
524 exception->putWithAttributes(callFrame, propertyName: Identifier(callFrame, expressionBeginOffsetPropertyName), value: jsNumber(exec: callFrame, i: divotPoint - startOffset), attributes: ReadOnly | DontDelete);
525 exception->putWithAttributes(callFrame, propertyName: Identifier(callFrame, expressionEndOffsetPropertyName), value: jsNumber(exec: callFrame, i: divotPoint + endOffset), attributes: ReadOnly | DontDelete);
526 } else
527 exception->putWithAttributes(callFrame, propertyName: Identifier(callFrame, JSC_ERROR_LINENUMBER_PROPERTYNAME), value: jsNumber(exec: callFrame, i: codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), attributes: ReadOnly | DontDelete);
528 exception->putWithAttributes(callFrame, propertyName: Identifier(callFrame, "sourceId"), value: jsNumber(exec: callFrame, i: codeBlock->ownerExecutable()->sourceID()), attributes: ReadOnly | DontDelete);
529 exception->putWithAttributes(callFrame, propertyName: Identifier(callFrame, JSC_ERROR_FILENAME_PROPERTYNAME), value: jsOwnedString(exec: callFrame, s: codeBlock->ownerExecutable()->sourceURL()), attributes: ReadOnly | DontDelete);
530 }
531
532 if (exception->isWatchdogException()) {
533 while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
534 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
535 }
536 return 0;
537 }
538 }
539 }
540
541 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
542 if (debugger) {
543 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
544 bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
545 debugger->exception(debuggerCallFrame, sourceID: codeBlock->ownerExecutable()->sourceID(), lineNumber: codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset), hasHandler);
546 }
547
548 // If we throw in the middle of a call instruction, we need to notify
549 // the profiler manually that the call instruction has returned, since
550 // we'll never reach the relevant op_profile_did_call.
551 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
552#if !ENABLE(JIT)
553 if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode))
554 profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 2].u.operand).jsValue());
555 else if (codeBlock->instructions().size() > (bytecodeOffset + 8) && codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct))
556 profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 10].u.operand).jsValue());
557#else
558 int functionRegisterIndex;
559 if (codeBlock->functionRegisterForBytecodeOffset(bytecodeOffset, functionRegisterIndex))
560 profiler->didExecute(callFrame, function: callFrame->r(index: functionRegisterIndex).jsValue());
561#endif
562 }
563
564 // Calculate an exception handler vPC, unwinding call frames as necessary.
565
566 HandlerInfo* handler = 0;
567
568#ifdef QT_BUILD_SCRIPT_LIB
569 //try to find handler
570 bool hasHandler = true;
571 CallFrame *callFrameTemp = callFrame;
572 unsigned bytecodeOffsetTemp = bytecodeOffset;
573 CodeBlock *codeBlockTemp = codeBlock;
574 while (!(handler = codeBlockTemp->handlerForBytecodeOffset(bytecodeOffset: bytecodeOffsetTemp))) {
575 void* returnPC = callFrameTemp->returnPC();
576 callFrameTemp = callFrameTemp->callerFrame();
577 if (callFrameTemp->hasHostCallFrameFlag()) {
578 hasHandler = false;
579 break;
580 } else {
581 codeBlockTemp = callFrameTemp->codeBlock();
582 bytecodeOffsetTemp = bytecodeOffsetForPC(callFrame: callFrameTemp, codeBlock: codeBlockTemp, pc: returnPC);
583 }
584 }
585 if (debugger)
586 debugger->exceptionThrow(frame: DebuggerCallFrame(callFrame, exceptionValue), sourceID: codeBlock->ownerExecutable()->sourceID(), hasHandler);
587 else if (!hasHandler)
588 callFrame->globalData().clientData->uncaughtException(callFrame, bytecodeOffset, exceptionValue);
589#endif
590
591 while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
592 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
593 return 0;
594 }
595 }
596 // Now unwind the scope chain within the exception handler's call frame.
597
598 ScopeChainNode* scopeChain = callFrame->scopeChain();
599 ScopeChain sc(scopeChain);
600 int scopeDelta = depth(codeBlock, sc) - handler->scopeDepth;
601 ASSERT(scopeDelta >= 0);
602 while (scopeDelta--)
603 scopeChain = scopeChain->pop();
604 callFrame->setScopeChain(scopeChain);
605
606 return handler;
607}
608
609JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception)
610{
611 ASSERT(!scopeChain->globalData->exception);
612
613 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
614 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
615 *exception = createStackOverflowError(callFrame);
616 return jsNull();
617 }
618 }
619
620 CodeBlock* codeBlock = &program->bytecode(exec: callFrame, scopeChainNode: scopeChain);
621
622 Register* oldEnd = m_registerFile.end();
623 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
624 if (!m_registerFile.grow(newEnd)) {
625 *exception = createStackOverflowError(callFrame);
626 return jsNull();
627 }
628
629 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
630
631 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
632 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
633 globalObject->copyGlobalsTo(m_registerFile);
634
635 CallFrame* newCallFrame = CallFrame::create(callFrameBase: oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
636 newCallFrame->r(index: codeBlock->thisRegister()) = JSValue(thisObj);
637 newCallFrame->init(codeBlock, vPC: 0, scopeChain, callerFrame: CallFrame::noCaller(), returnValueRegister: 0, argc: 0, callee: 0);
638
639 if (codeBlock->needsFullScopeChain())
640 scopeChain->ref();
641
642 Profiler** profiler = Profiler::enabledProfilerReference();
643 if (*profiler)
644 (*profiler)->willExecute(newCallFrame, sourceURL: program->sourceURL(), startingLineNumber: program->lineNo());
645
646 JSValue result;
647 {
648 SamplingTool::CallRecord callRecord(m_sampler.get());
649
650 m_reentryDepth++;
651#if ENABLE(JIT)
652 result = program->jitCode(exec: newCallFrame, scopeChainNode: scopeChain).execute(registerFile: &m_registerFile, callFrame: newCallFrame, globalData: scopeChain->globalData, exception);
653#else
654 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
655#endif
656 m_reentryDepth--;
657 }
658
659 if (*profiler)
660 (*profiler)->didExecute(callFrame, sourceURL: program->sourceURL(), startingLineNumber: program->lineNo());
661
662 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
663 lastGlobalObject->copyGlobalsTo(m_registerFile);
664
665 m_registerFile.shrink(newEnd: oldEnd);
666
667 return result;
668}
669
670JSValue Interpreter::execute(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception)
671{
672 ASSERT(!scopeChain->globalData->exception);
673
674 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
675 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
676 *exception = createStackOverflowError(callFrame);
677 return jsNull();
678 }
679 }
680
681 Register* oldEnd = m_registerFile.end();
682 int argc = 1 + args.size(); // implicit "this" parameter
683
684 if (!m_registerFile.grow(newEnd: oldEnd + argc)) {
685 *exception = createStackOverflowError(callFrame);
686 return jsNull();
687 }
688
689 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
690
691 CallFrame* newCallFrame = CallFrame::create(callFrameBase: oldEnd);
692 size_t dst = 0;
693 newCallFrame->r(index: 0) = JSValue(thisObj);
694 ArgList::const_iterator end = args.end();
695 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
696 newCallFrame->r(index: ++dst) = *it;
697
698 CodeBlock* codeBlock = &functionExecutable->bytecode(exec: callFrame, scopeChainNode: scopeChain);
699 newCallFrame = slideRegisterWindowForCall(newCodeBlock: codeBlock, registerFile: &m_registerFile, callFrame: newCallFrame, registerOffset: argc + RegisterFile::CallFrameHeaderSize, argc);
700 if (UNLIKELY(!newCallFrame)) {
701 *exception = createStackOverflowError(callFrame);
702 m_registerFile.shrink(newEnd: oldEnd);
703 return jsNull();
704 }
705 // a 0 codeBlock indicates a built-in caller
706 newCallFrame->init(codeBlock, vPC: 0, scopeChain, callerFrame: callFrame->addHostCallFrameFlag(), returnValueRegister: 0, argc, callee: function);
707
708 Profiler** profiler = Profiler::enabledProfilerReference();
709 if (*profiler)
710 (*profiler)->willExecute(callFrame, function);
711
712 JSValue result;
713 {
714 SamplingTool::CallRecord callRecord(m_sampler.get());
715
716 m_reentryDepth++;
717#if ENABLE(JIT)
718 result = functionExecutable->jitCode(exec: newCallFrame, scopeChainNode: scopeChain).execute(registerFile: &m_registerFile, callFrame: newCallFrame, globalData: scopeChain->globalData, exception);
719#else
720 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
721#endif
722 m_reentryDepth--;
723 }
724
725 if (*profiler)
726 (*profiler)->didExecute(callFrame, function);
727
728 m_registerFile.shrink(newEnd: oldEnd);
729 return result;
730}
731
732CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain, JSValue* exception)
733{
734 ASSERT(!scopeChain->globalData->exception);
735
736 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
737 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
738 *exception = createStackOverflowError(callFrame);
739 return CallFrameClosure();
740 }
741 }
742
743 Register* oldEnd = m_registerFile.end();
744 int argc = 1 + argCount; // implicit "this" parameter
745
746 if (!m_registerFile.grow(newEnd: oldEnd + argc)) {
747 *exception = createStackOverflowError(callFrame);
748 return CallFrameClosure();
749 }
750
751 CallFrame* newCallFrame = CallFrame::create(callFrameBase: oldEnd);
752 size_t dst = 0;
753 for (int i = 0; i < argc; ++i)
754 newCallFrame->r(index: ++dst) = jsUndefined();
755
756 CodeBlock* codeBlock = &FunctionExecutable->bytecode(exec: callFrame, scopeChainNode: scopeChain);
757 newCallFrame = slideRegisterWindowForCall(newCodeBlock: codeBlock, registerFile: &m_registerFile, callFrame: newCallFrame, registerOffset: argc + RegisterFile::CallFrameHeaderSize, argc);
758 if (UNLIKELY(!newCallFrame)) {
759 *exception = createStackOverflowError(callFrame);
760 m_registerFile.shrink(newEnd: oldEnd);
761 return CallFrameClosure();
762 }
763 // a 0 codeBlock indicates a built-in caller
764 newCallFrame->init(codeBlock, vPC: 0, scopeChain, callerFrame: callFrame->addHostCallFrameFlag(), returnValueRegister: 0, argc, callee: function);
765#if ENABLE(JIT)
766 FunctionExecutable->jitCode(exec: newCallFrame, scopeChainNode: scopeChain);
767#endif
768
769 CallFrameClosure result = { .oldCallFrame: callFrame, .newCallFrame: newCallFrame, .function: function, .functionExecutable: FunctionExecutable, .globalData: scopeChain->globalData, .oldEnd: oldEnd, .scopeChain: scopeChain, .expectedParams: codeBlock->m_numParameters, .providedParams: argc };
770 return result;
771}
772
773JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception)
774{
775 closure.resetCallFrame();
776 Profiler** profiler = Profiler::enabledProfilerReference();
777 if (*profiler)
778 (*profiler)->willExecute(closure.oldCallFrame, function: closure.function);
779
780 JSValue result;
781 {
782 SamplingTool::CallRecord callRecord(m_sampler.get());
783
784 m_reentryDepth++;
785#if ENABLE(JIT)
786 result = closure.functionExecutable->generatedJITCode().execute(registerFile: &m_registerFile, callFrame: closure.newCallFrame, globalData: closure.globalData, exception);
787#else
788 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame, exception);
789#endif
790 m_reentryDepth--;
791 }
792
793 if (*profiler)
794 (*profiler)->didExecute(closure.oldCallFrame, function: closure.function);
795 return result;
796}
797
798void Interpreter::endRepeatCall(CallFrameClosure& closure)
799{
800 m_registerFile.shrink(newEnd: closure.oldEnd);
801}
802
803JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception)
804{
805 return execute(eval, callFrame, thisObject: thisObj, globalRegisterOffset: m_registerFile.size() + eval->bytecode(exec: callFrame, scopeChainNode: scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
806}
807
808JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue* exception)
809{
810 ASSERT(!scopeChain->globalData->exception);
811
812 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
813 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
814 *exception = createStackOverflowError(callFrame);
815 return jsNull();
816 }
817 }
818
819 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
820
821 EvalCodeBlock* codeBlock = &eval->bytecode(exec: callFrame, scopeChainNode: scopeChain);
822
823 JSVariableObject* variableObject;
824 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
825 ASSERT(node);
826 if (node->object->isVariableObject()) {
827 variableObject = static_cast<JSVariableObject*>(node->object);
828 break;
829 }
830 }
831
832 { // Scope for BatchedTransitionOptimizer
833
834 BatchedTransitionOptimizer optimizer(variableObject);
835
836 unsigned numVariables = codeBlock->numVariables();
837 for (unsigned i = 0; i < numVariables; ++i) {
838 const Identifier& ident = codeBlock->variable(index: i);
839 if (!variableObject->hasProperty(callFrame, propertyName: ident)) {
840 PutPropertySlot slot;
841 variableObject->put(callFrame, propertyName: ident, value: jsUndefined(), slot);
842 }
843 }
844
845 int numFunctions = codeBlock->numberOfFunctionDecls();
846 for (int i = 0; i < numFunctions; ++i) {
847 FunctionExecutable* function = codeBlock->functionDecl(index: i);
848 PutPropertySlot slot;
849 variableObject->put(callFrame, propertyName: function->name(), value: function->make(exec: callFrame, scopeChain), slot);
850 }
851
852 }
853
854 Register* oldEnd = m_registerFile.end();
855#ifdef QT_BUILD_SCRIPT_LIB //with Qt Script, we do not necesserly start from scratch
856 Register* newEnd = oldEnd + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
857#else
858 Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
859#endif
860 if (!m_registerFile.grow(newEnd)) {
861 *exception = createStackOverflowError(callFrame);
862 return jsNull();
863 }
864
865#ifdef QT_BUILD_SCRIPT_LIB //with Qt Script, we do not necesserly start from scratch
866 CallFrame* newCallFrame = CallFrame::create(callFrameBase: oldEnd + globalRegisterOffset);
867#else
868 CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
869#endif
870
871 // a 0 codeBlock indicates a built-in caller
872 newCallFrame->r(index: codeBlock->thisRegister()) = JSValue(thisObj);
873 newCallFrame->init(codeBlock, vPC: 0, scopeChain, callerFrame: callFrame->addHostCallFrameFlag(), returnValueRegister: 0, argc: 0, callee: 0);
874
875 if (codeBlock->needsFullScopeChain())
876 scopeChain->ref();
877
878 Profiler** profiler = Profiler::enabledProfilerReference();
879 if (*profiler)
880 (*profiler)->willExecute(newCallFrame, sourceURL: eval->sourceURL(), startingLineNumber: eval->lineNo());
881
882 JSValue result;
883 {
884 SamplingTool::CallRecord callRecord(m_sampler.get());
885
886 m_reentryDepth++;
887#if ENABLE(JIT)
888 result = eval->jitCode(exec: newCallFrame, scopeChainNode: scopeChain).execute(registerFile: &m_registerFile, callFrame: newCallFrame, globalData: scopeChain->globalData, exception);
889#else
890 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
891#endif
892 m_reentryDepth--;
893 }
894
895 if (*profiler)
896 (*profiler)->didExecute(callFrame, sourceURL: eval->sourceURL(), startingLineNumber: eval->lineNo());
897
898 m_registerFile.shrink(newEnd: oldEnd);
899 return result;
900}
901
902NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
903{
904 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
905 if (!debugger)
906 return;
907
908 switch (debugHookID) {
909 case DidEnterCallFrame:
910 debugger->callEvent(callFrame, sourceID: callFrame->codeBlock()->ownerExecutable()->sourceID(), lineNumber: firstLine);
911 return;
912 case WillLeaveCallFrame:
913 debugger->returnEvent(callFrame, sourceID: callFrame->codeBlock()->ownerExecutable()->sourceID(), lineNumber: lastLine);
914 return;
915 case WillExecuteStatement:
916 debugger->atStatement(callFrame, sourceID: callFrame->codeBlock()->ownerExecutable()->sourceID(), lineNumber: firstLine);
917 return;
918 case WillExecuteProgram:
919 debugger->willExecuteProgram(callFrame, sourceID: callFrame->codeBlock()->ownerExecutable()->sourceID(), lineNumber: firstLine);
920 return;
921 case DidExecuteProgram:
922 debugger->didExecuteProgram(callFrame, sourceID: callFrame->codeBlock()->ownerExecutable()->sourceID(), lineNumber: lastLine);
923 return;
924 case DidReachBreakpoint:
925 debugger->didReachBreakpoint(callFrame, sourceID: callFrame->codeBlock()->ownerExecutable()->sourceID(), lineNumber: lastLine);
926 return;
927 }
928}
929
930#if USE(INTERPRETER)
931NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
932{
933 int dst = vPC[1].u.operand;
934 CodeBlock* codeBlock = callFrame->codeBlock();
935 Identifier& property = codeBlock->identifier(index: vPC[2].u.operand);
936 JSValue value = callFrame->r(index: vPC[3].u.operand).jsValue();
937 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
938 callFrame->r(index: dst) = JSValue(scope);
939
940 return callFrame->scopeChain()->push(o: scope);
941}
942
943NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot)
944{
945 // Recursive invocation may already have specialized this instruction.
946 if (vPC[0].u.opcode != getOpcode(id: op_put_by_id))
947 return;
948
949 if (!baseValue.isCell())
950 return;
951
952 // Uncacheable: give up.
953 if (!slot.isCacheable()) {
954 vPC[0] = getOpcode(id: op_put_by_id_generic);
955 return;
956 }
957
958 JSCell* baseCell = asCell(value: baseValue);
959 Structure* structure = baseCell->structure();
960
961 if (structure->isUncacheableDictionary()) {
962 vPC[0] = getOpcode(id: op_put_by_id_generic);
963 return;
964 }
965
966 // Cache miss: record Structure to compare against next time.
967 Structure* lastStructure = vPC[4].u.structure;
968 if (structure != lastStructure) {
969 // First miss: record Structure to compare against next time.
970 if (!lastStructure) {
971 vPC[4] = structure;
972 return;
973 }
974
975 // Second miss: give up.
976 vPC[0] = getOpcode(id: op_put_by_id_generic);
977 return;
978 }
979
980 // Cache hit: Specialize instruction and ref Structures.
981
982 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
983 if (baseCell != slot.base()) {
984 vPC[0] = getOpcode(id: op_put_by_id_generic);
985 return;
986 }
987
988 // Structure transition, cache transition info
989 if (slot.type() == PutPropertySlot::NewProperty) {
990 if (structure->isDictionary()) {
991 vPC[0] = getOpcode(id: op_put_by_id_generic);
992 return;
993 }
994
995 // put_by_id_transition checks the prototype chain for setters.
996 normalizePrototypeChain(callFrame, base: baseCell);
997
998 vPC[0] = getOpcode(id: op_put_by_id_transition);
999 vPC[4] = structure->previousID();
1000 vPC[5] = structure;
1001 vPC[6] = structure->prototypeChain(exec: callFrame);
1002 vPC[7] = slot.cachedOffset();
1003 codeBlock->refStructures(vPC);
1004 return;
1005 }
1006
1007 vPC[0] = getOpcode(id: op_put_by_id_replace);
1008 vPC[5] = slot.cachedOffset();
1009 codeBlock->refStructures(vPC);
1010}
1011
1012NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1013{
1014 codeBlock->derefStructures(vPC);
1015 vPC[0] = getOpcode(id: op_put_by_id);
1016 vPC[4] = 0;
1017}
1018
1019NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)
1020{
1021 // Recursive invocation may already have specialized this instruction.
1022 if (vPC[0].u.opcode != getOpcode(id: op_get_by_id))
1023 return;
1024
1025 // FIXME: Cache property access for immediates.
1026 if (!baseValue.isCell()) {
1027 vPC[0] = getOpcode(id: op_get_by_id_generic);
1028 return;
1029 }
1030
1031 JSGlobalData* globalData = &callFrame->globalData();
1032 if (isJSArray(globalData, v: baseValue) && propertyName == callFrame->propertyNames().length) {
1033 vPC[0] = getOpcode(id: op_get_array_length);
1034 return;
1035 }
1036
1037 if (isJSString(globalData, v: baseValue) && propertyName == callFrame->propertyNames().length) {
1038 vPC[0] = getOpcode(id: op_get_string_length);
1039 return;
1040 }
1041
1042 // Uncacheable: give up.
1043 if (!slot.isCacheable()) {
1044 vPC[0] = getOpcode(id: op_get_by_id_generic);
1045 return;
1046 }
1047
1048 Structure* structure = asCell(value: baseValue)->structure();
1049
1050 if (structure->isUncacheableDictionary()) {
1051 vPC[0] = getOpcode(id: op_get_by_id_generic);
1052 return;
1053 }
1054
1055 // Cache miss
1056 Structure* lastStructure = vPC[4].u.structure;
1057 if (structure != lastStructure) {
1058 // First miss: record Structure to compare against next time.
1059 if (!lastStructure) {
1060 vPC[4] = structure;
1061 return;
1062 }
1063
1064 // Second miss: give up.
1065 vPC[0] = getOpcode(id: op_get_by_id_generic);
1066 return;
1067 }
1068
1069 // Cache hit: Specialize instruction and ref Structures.
1070
1071 if (slot.slotBase() == baseValue) {
1072 vPC[0] = getOpcode(id: op_get_by_id_self);
1073 vPC[5] = slot.cachedOffset();
1074
1075 codeBlock->refStructures(vPC);
1076 return;
1077 }
1078
1079 if (structure->isDictionary()) {
1080 vPC[0] = getOpcode(id: op_get_by_id_generic);
1081 return;
1082 }
1083
1084 if (slot.slotBase() == structure->prototypeForLookup(exec: callFrame)) {
1085 ASSERT(slot.slotBase().isObject());
1086
1087 JSObject* baseObject = asObject(value: slot.slotBase());
1088 size_t offset = slot.cachedOffset();
1089
1090 // Since we're accessing a prototype in a loop, it's a good bet that it
1091 // should not be treated as a dictionary.
1092 if (baseObject->structure()->isDictionary()) {
1093 baseObject->flattenDictionaryObject();
1094 offset = baseObject->structure()->get(propertyName);
1095 }
1096
1097 ASSERT(!baseObject->structure()->isUncacheableDictionary());
1098
1099 vPC[0] = getOpcode(id: op_get_by_id_proto);
1100 vPC[5] = baseObject->structure();
1101 vPC[6] = offset;
1102
1103 codeBlock->refStructures(vPC);
1104 return;
1105 }
1106
1107 size_t offset = slot.cachedOffset();
1108 size_t count = normalizePrototypeChain(callFrame, base: baseValue, slotBase: slot.slotBase(), propertyName, slotOffset&: offset);
1109 if (!count) {
1110 vPC[0] = getOpcode(id: op_get_by_id_generic);
1111 return;
1112 }
1113
1114 vPC[0] = getOpcode(id: op_get_by_id_chain);
1115 vPC[4] = structure;
1116 vPC[5] = structure->prototypeChain(exec: callFrame);
1117 vPC[6] = count;
1118 vPC[7] = offset;
1119 codeBlock->refStructures(vPC);
1120}
1121
1122NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1123{
1124 codeBlock->derefStructures(vPC);
1125 vPC[0] = getOpcode(id: op_get_by_id);
1126 vPC[4] = 0;
1127}
1128
1129#endif // USE(INTERPRETER)
1130
1131JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValue* exception)
1132{
1133 // One-time initialization of our address tables. We have to put this code
1134 // here because our labels are only in scope inside this function.
1135 if (UNLIKELY(flag == InitializeAndReturn)) {
1136 #if HAVE(COMPUTED_GOTO)
1137 #define LIST_OPCODE_LABEL(id, length) &&id,
1138 static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) };
1139 for (size_t i = 0; i < sizeof(labels) / sizeof(Opcode); ++i)
1140 m_opcodeTable[i] = labels[i];
1141 #undef LIST_OPCODE_LABEL
1142 #endif // HAVE(COMPUTED_GOTO)
1143 return JSValue();
1144 }
1145
1146#if ENABLE(JIT)
1147 // Mixing Interpreter + JIT is not supported.
1148 ASSERT_NOT_REACHED();
1149#endif
1150#if !USE(INTERPRETER)
1151 UNUSED_PARAM(registerFile);
1152 UNUSED_PARAM(callFrame);
1153 UNUSED_PARAM(exception);
1154 return JSValue();
1155#else
1156
1157 JSGlobalData* globalData = &callFrame->globalData();
1158 JSValue exceptionValue;
1159 HandlerInfo* handler = 0;
1160
1161 Instruction* vPC = callFrame->codeBlock()->instructions().begin();
1162 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1163 unsigned tickCount = globalData->timeoutChecker->ticksUntilNextCheck();
1164
1165#define CHECK_FOR_EXCEPTION() \
1166 do { \
1167 if (UNLIKELY(globalData->exception != JSValue())) { \
1168 exceptionValue = globalData->exception; \
1169 goto vm_throw; \
1170 } \
1171 } while (0)
1172
1173#if ENABLE(OPCODE_STATS)
1174 OpcodeStats::resetLastInstruction();
1175#endif
1176
1177#define CHECK_FOR_TIMEOUT() \
1178 if (!--tickCount) { \
1179 if (globalData->timeoutChecker->didTimeOut(callFrame)) { \
1180 exceptionValue = jsNull(); \
1181 goto vm_throw; \
1182 } \
1183 tickCount = globalData->timeoutChecker->ticksUntilNextCheck(); \
1184 CHECK_FOR_EXCEPTION(); \
1185 }
1186
1187#if ENABLE(OPCODE_SAMPLING)
1188 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1189#else
1190 #define SAMPLE(codeBlock, vPC)
1191#endif
1192
1193#if HAVE(COMPUTED_GOTO)
1194 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
1195#if ENABLE(OPCODE_STATS)
1196 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1197#else
1198 #define DEFINE_OPCODE(opcode) opcode:
1199#endif
1200 NEXT_INSTRUCTION();
1201#else
1202 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
1203#if ENABLE(OPCODE_STATS)
1204 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1205#else
1206 #define DEFINE_OPCODE(opcode) case opcode:
1207#endif
1208 while (1) { // iterator loop begins
1209 interpreterLoopStart:;
1210 switch (vPC->u.opcode)
1211#endif
1212 {
1213 DEFINE_OPCODE(op_new_object) {
1214 /* new_object dst(r)
1215
1216 Constructs a new empty Object instance using the original
1217 constructor, and puts the result in register dst.
1218 */
1219 int dst = vPC[1].u.operand;
1220 callFrame->r(index: dst) = JSValue(constructEmptyObject(exec: callFrame));
1221
1222 vPC += OPCODE_LENGTH(op_new_object);
1223 NEXT_INSTRUCTION();
1224 }
1225 DEFINE_OPCODE(op_new_array) {
1226 /* new_array dst(r) firstArg(r) argCount(n)
1227
1228 Constructs a new Array instance using the original
1229 constructor, and puts the result in register dst.
1230 The array will contain argCount elements with values
1231 taken from registers starting at register firstArg.
1232 */
1233 int dst = vPC[1].u.operand;
1234 int firstArg = vPC[2].u.operand;
1235 int argCount = vPC[3].u.operand;
1236 ArgList args(callFrame->registers() + firstArg, argCount);
1237 callFrame->r(index: dst) = JSValue(constructArray(exec: callFrame, values: args));
1238
1239 vPC += OPCODE_LENGTH(op_new_array);
1240 NEXT_INSTRUCTION();
1241 }
1242 DEFINE_OPCODE(op_new_regexp) {
1243 /* new_regexp dst(r) regExp(re)
1244
1245 Constructs a new RegExp instance using the original
1246 constructor from regexp regExp, and puts the result in
1247 register dst.
1248 */
1249 int dst = vPC[1].u.operand;
1250 int regExp = vPC[2].u.operand;
1251 callFrame->r(index: dst) = JSValue(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject->regExpStructure(), callFrame->codeBlock()->regexp(index: regExp)));
1252
1253 vPC += OPCODE_LENGTH(op_new_regexp);
1254 NEXT_INSTRUCTION();
1255 }
1256 DEFINE_OPCODE(op_mov) {
1257 /* mov dst(r) src(r)
1258
1259 Copies register src to register dst.
1260 */
1261 int dst = vPC[1].u.operand;
1262 int src = vPC[2].u.operand;
1263 callFrame->r(index: dst) = callFrame->r(index: src);
1264
1265 vPC += OPCODE_LENGTH(op_mov);
1266 NEXT_INSTRUCTION();
1267 }
1268 DEFINE_OPCODE(op_eq) {
1269 /* eq dst(r) src1(r) src2(r)
1270
1271 Checks whether register src1 and register src2 are equal,
1272 as with the ECMAScript '==' operator, and puts the result
1273 as a boolean in register dst.
1274 */
1275 int dst = vPC[1].u.operand;
1276 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1277 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1278 if (src1.isInt32() && src2.isInt32())
1279 callFrame->r(index: dst) = jsBoolean(b: src1.asInt32() == src2.asInt32());
1280 else {
1281 JSValue result = jsBoolean(b: JSValue::equalSlowCase(exec: callFrame, v1: src1, v2: src2));
1282 CHECK_FOR_EXCEPTION();
1283 callFrame->r(index: dst) = result;
1284 }
1285
1286 vPC += OPCODE_LENGTH(op_eq);
1287 NEXT_INSTRUCTION();
1288 }
1289 DEFINE_OPCODE(op_eq_null) {
1290 /* eq_null dst(r) src(r)
1291
1292 Checks whether register src is null, as with the ECMAScript '!='
1293 operator, and puts the result as a boolean in register dst.
1294 */
1295 int dst = vPC[1].u.operand;
1296 JSValue src = callFrame->r(index: vPC[2].u.operand).jsValue();
1297
1298 if (src.isUndefinedOrNull()) {
1299 callFrame->r(index: dst) = jsBoolean(b: true);
1300 vPC += OPCODE_LENGTH(op_eq_null);
1301 NEXT_INSTRUCTION();
1302 }
1303
1304 callFrame->r(index: dst) = jsBoolean(b: src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1305 vPC += OPCODE_LENGTH(op_eq_null);
1306 NEXT_INSTRUCTION();
1307 }
1308 DEFINE_OPCODE(op_neq) {
1309 /* neq dst(r) src1(r) src2(r)
1310
1311 Checks whether register src1 and register src2 are not
1312 equal, as with the ECMAScript '!=' operator, and puts the
1313 result as a boolean in register dst.
1314 */
1315 int dst = vPC[1].u.operand;
1316 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1317 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1318 if (src1.isInt32() && src2.isInt32())
1319 callFrame->r(index: dst) = jsBoolean(b: src1.asInt32() != src2.asInt32());
1320 else {
1321 JSValue result = jsBoolean(b: !JSValue::equalSlowCase(exec: callFrame, v1: src1, v2: src2));
1322 CHECK_FOR_EXCEPTION();
1323 callFrame->r(index: dst) = result;
1324 }
1325
1326 vPC += OPCODE_LENGTH(op_neq);
1327 NEXT_INSTRUCTION();
1328 }
1329 DEFINE_OPCODE(op_neq_null) {
1330 /* neq_null dst(r) src(r)
1331
1332 Checks whether register src is not null, as with the ECMAScript '!='
1333 operator, and puts the result as a boolean in register dst.
1334 */
1335 int dst = vPC[1].u.operand;
1336 JSValue src = callFrame->r(index: vPC[2].u.operand).jsValue();
1337
1338 if (src.isUndefinedOrNull()) {
1339 callFrame->r(index: dst) = jsBoolean(b: false);
1340 vPC += OPCODE_LENGTH(op_neq_null);
1341 NEXT_INSTRUCTION();
1342 }
1343
1344 callFrame->r(index: dst) = jsBoolean(b: !src.isCell() || !asCell(value: src)->structure()->typeInfo().masqueradesAsUndefined());
1345 vPC += OPCODE_LENGTH(op_neq_null);
1346 NEXT_INSTRUCTION();
1347 }
1348 DEFINE_OPCODE(op_stricteq) {
1349 /* stricteq dst(r) src1(r) src2(r)
1350
1351 Checks whether register src1 and register src2 are strictly
1352 equal, as with the ECMAScript '===' operator, and puts the
1353 result as a boolean in register dst.
1354 */
1355 int dst = vPC[1].u.operand;
1356 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1357 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1358 callFrame->r(index: dst) = jsBoolean(b: JSValue::strictEqual(exec: callFrame, v1: src1, v2: src2));
1359
1360 vPC += OPCODE_LENGTH(op_stricteq);
1361 NEXT_INSTRUCTION();
1362 }
1363 DEFINE_OPCODE(op_nstricteq) {
1364 /* nstricteq dst(r) src1(r) src2(r)
1365
1366 Checks whether register src1 and register src2 are not
1367 strictly equal, as with the ECMAScript '!==' operator, and
1368 puts the result as a boolean in register dst.
1369 */
1370 int dst = vPC[1].u.operand;
1371 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1372 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1373 callFrame->r(index: dst) = jsBoolean(b: !JSValue::strictEqual(exec: callFrame, v1: src1, v2: src2));
1374
1375 vPC += OPCODE_LENGTH(op_nstricteq);
1376 NEXT_INSTRUCTION();
1377 }
1378 DEFINE_OPCODE(op_less) {
1379 /* less dst(r) src1(r) src2(r)
1380
1381 Checks whether register src1 is less than register src2, as
1382 with the ECMAScript '<' operator, and puts the result as
1383 a boolean in register dst.
1384 */
1385 int dst = vPC[1].u.operand;
1386 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1387 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1388 JSValue result = jsBoolean(b: jsLess(callFrame, v1: src1, v2: src2));
1389 CHECK_FOR_EXCEPTION();
1390 callFrame->r(index: dst) = result;
1391
1392 vPC += OPCODE_LENGTH(op_less);
1393 NEXT_INSTRUCTION();
1394 }
1395 DEFINE_OPCODE(op_lesseq) {
1396 /* lesseq dst(r) src1(r) src2(r)
1397
1398 Checks whether register src1 is less than or equal to
1399 register src2, as with the ECMAScript '<=' operator, and
1400 puts the result as a boolean in register dst.
1401 */
1402 int dst = vPC[1].u.operand;
1403 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1404 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1405 JSValue result = jsBoolean(b: jsLessEq(callFrame, v1: src1, v2: src2));
1406 CHECK_FOR_EXCEPTION();
1407 callFrame->r(index: dst) = result;
1408
1409 vPC += OPCODE_LENGTH(op_lesseq);
1410 NEXT_INSTRUCTION();
1411 }
1412 DEFINE_OPCODE(op_pre_inc) {
1413 /* pre_inc srcDst(r)
1414
1415 Converts register srcDst to number, adds one, and puts the result
1416 back in register srcDst.
1417 */
1418 int srcDst = vPC[1].u.operand;
1419 JSValue v = callFrame->r(index: srcDst).jsValue();
1420 if (v.isInt32() && v.asInt32() < INT_MAX)
1421 callFrame->r(index: srcDst) = jsNumber(exec: callFrame, i: v.asInt32() + 1);
1422 else {
1423 JSValue result = jsNumber(exec: callFrame, d: v.toNumber(exec: callFrame) + 1);
1424 CHECK_FOR_EXCEPTION();
1425 callFrame->r(index: srcDst) = result;
1426 }
1427
1428 vPC += OPCODE_LENGTH(op_pre_inc);
1429 NEXT_INSTRUCTION();
1430 }
1431 DEFINE_OPCODE(op_pre_dec) {
1432 /* pre_dec srcDst(r)
1433
1434 Converts register srcDst to number, subtracts one, and puts the result
1435 back in register srcDst.
1436 */
1437 int srcDst = vPC[1].u.operand;
1438 JSValue v = callFrame->r(index: srcDst).jsValue();
1439 if (v.isInt32() && v.asInt32() > INT_MIN)
1440 callFrame->r(index: srcDst) = jsNumber(exec: callFrame, i: v.asInt32() - 1);
1441 else {
1442 JSValue result = jsNumber(exec: callFrame, d: v.toNumber(exec: callFrame) - 1);
1443 CHECK_FOR_EXCEPTION();
1444 callFrame->r(index: srcDst) = result;
1445 }
1446
1447 vPC += OPCODE_LENGTH(op_pre_dec);
1448 NEXT_INSTRUCTION();
1449 }
1450 DEFINE_OPCODE(op_post_inc) {
1451 /* post_inc dst(r) srcDst(r)
1452
1453 Converts register srcDst to number. The number itself is
1454 written to register dst, and the number plus one is written
1455 back to register srcDst.
1456 */
1457 int dst = vPC[1].u.operand;
1458 int srcDst = vPC[2].u.operand;
1459 JSValue v = callFrame->r(index: srcDst).jsValue();
1460 if (v.isInt32() && v.asInt32() < INT_MAX) {
1461 callFrame->r(index: srcDst) = jsNumber(exec: callFrame, i: v.asInt32() + 1);
1462 callFrame->r(index: dst) = v;
1463 } else {
1464 JSValue number = callFrame->r(index: srcDst).jsValue().toJSNumber(exec: callFrame);
1465 CHECK_FOR_EXCEPTION();
1466 callFrame->r(index: srcDst) = jsNumber(exec: callFrame, d: number.uncheckedGetNumber() + 1);
1467 callFrame->r(index: dst) = number;
1468 }
1469
1470 vPC += OPCODE_LENGTH(op_post_inc);
1471 NEXT_INSTRUCTION();
1472 }
1473 DEFINE_OPCODE(op_post_dec) {
1474 /* post_dec dst(r) srcDst(r)
1475
1476 Converts register srcDst to number. The number itself is
1477 written to register dst, and the number minus one is written
1478 back to register srcDst.
1479 */
1480 int dst = vPC[1].u.operand;
1481 int srcDst = vPC[2].u.operand;
1482 JSValue v = callFrame->r(index: srcDst).jsValue();
1483 if (v.isInt32() && v.asInt32() > INT_MIN) {
1484 callFrame->r(index: srcDst) = jsNumber(exec: callFrame, i: v.asInt32() - 1);
1485 callFrame->r(index: dst) = v;
1486 } else {
1487 JSValue number = callFrame->r(index: srcDst).jsValue().toJSNumber(exec: callFrame);
1488 CHECK_FOR_EXCEPTION();
1489 callFrame->r(index: srcDst) = jsNumber(exec: callFrame, d: number.uncheckedGetNumber() - 1);
1490 callFrame->r(index: dst) = number;
1491 }
1492
1493 vPC += OPCODE_LENGTH(op_post_dec);
1494 NEXT_INSTRUCTION();
1495 }
1496 DEFINE_OPCODE(op_to_jsnumber) {
1497 /* to_jsnumber dst(r) src(r)
1498
1499 Converts register src to number, and puts the result
1500 in register dst.
1501 */
1502 int dst = vPC[1].u.operand;
1503 int src = vPC[2].u.operand;
1504
1505 JSValue srcVal = callFrame->r(index: src).jsValue();
1506
1507 if (LIKELY(srcVal.isNumber()))
1508 callFrame->r(index: dst) = callFrame->r(index: src);
1509 else {
1510 JSValue result = srcVal.toJSNumber(exec: callFrame);
1511 CHECK_FOR_EXCEPTION();
1512 callFrame->r(index: dst) = result;
1513 }
1514
1515 vPC += OPCODE_LENGTH(op_to_jsnumber);
1516 NEXT_INSTRUCTION();
1517 }
1518 DEFINE_OPCODE(op_negate) {
1519 /* negate dst(r) src(r)
1520
1521 Converts register src to number, negates it, and puts the
1522 result in register dst.
1523 */
1524 int dst = vPC[1].u.operand;
1525 JSValue src = callFrame->r(index: vPC[2].u.operand).jsValue();
1526 if (src.isInt32() && src.asInt32())
1527 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: -src.asInt32());
1528 else {
1529 JSValue result = jsNumber(exec: callFrame, d: -src.toNumber(exec: callFrame));
1530 CHECK_FOR_EXCEPTION();
1531 callFrame->r(index: dst) = result;
1532 }
1533
1534 vPC += OPCODE_LENGTH(op_negate);
1535 NEXT_INSTRUCTION();
1536 }
1537 DEFINE_OPCODE(op_add) {
1538 /* add dst(r) src1(r) src2(r)
1539
1540 Adds register src1 and register src2, and puts the result
1541 in register dst. (JS add may be string concatenation or
1542 numeric add, depending on the types of the operands.)
1543 */
1544 int dst = vPC[1].u.operand;
1545 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1546 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1547 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
1548 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: src1.asInt32() + src2.asInt32());
1549 else {
1550 JSValue result = jsAdd(callFrame, v1: src1, v2: src2);
1551 CHECK_FOR_EXCEPTION();
1552 callFrame->r(index: dst) = result;
1553 }
1554 vPC += OPCODE_LENGTH(op_add);
1555 NEXT_INSTRUCTION();
1556 }
1557 DEFINE_OPCODE(op_mul) {
1558 /* mul dst(r) src1(r) src2(r)
1559
1560 Multiplies register src1 and register src2 (converted to
1561 numbers), and puts the product in register dst.
1562 */
1563 int dst = vPC[1].u.operand;
1564 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1565 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1566 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
1567 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: src1.asInt32() * src2.asInt32());
1568 else {
1569 JSValue result = jsNumber(exec: callFrame, d: src1.toNumber(exec: callFrame) * src2.toNumber(exec: callFrame));
1570 CHECK_FOR_EXCEPTION();
1571 callFrame->r(index: dst) = result;
1572 }
1573
1574 vPC += OPCODE_LENGTH(op_mul);
1575 NEXT_INSTRUCTION();
1576 }
1577 DEFINE_OPCODE(op_div) {
1578 /* div dst(r) dividend(r) divisor(r)
1579
1580 Divides register dividend (converted to number) by the
1581 register divisor (converted to number), and puts the
1582 quotient in register dst.
1583 */
1584 int dst = vPC[1].u.operand;
1585 JSValue dividend = callFrame->r(index: vPC[2].u.operand).jsValue();
1586 JSValue divisor = callFrame->r(index: vPC[3].u.operand).jsValue();
1587
1588 JSValue result = jsNumber(exec: callFrame, d: dividend.toNumber(exec: callFrame) / divisor.toNumber(exec: callFrame));
1589 CHECK_FOR_EXCEPTION();
1590 callFrame->r(index: dst) = result;
1591
1592 vPC += OPCODE_LENGTH(op_div);
1593 NEXT_INSTRUCTION();
1594 }
1595 DEFINE_OPCODE(op_mod) {
1596 /* mod dst(r) dividend(r) divisor(r)
1597
1598 Divides register dividend (converted to number) by
1599 register divisor (converted to number), and puts the
1600 remainder in register dst.
1601 */
1602 int dst = vPC[1].u.operand;
1603 JSValue dividend = callFrame->r(index: vPC[2].u.operand).jsValue();
1604 JSValue divisor = callFrame->r(index: vPC[3].u.operand).jsValue();
1605
1606 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
1607 JSValue result = jsNumber(exec: callFrame, i: dividend.asInt32() % divisor.asInt32());
1608 ASSERT(result);
1609 callFrame->r(index: dst) = result;
1610 vPC += OPCODE_LENGTH(op_mod);
1611 NEXT_INSTRUCTION();
1612 }
1613
1614 // Conversion to double must happen outside the call to fmod since the
1615 // order of argument evaluation is not guaranteed.
1616 double d1 = dividend.toNumber(exec: callFrame);
1617 double d2 = divisor.toNumber(exec: callFrame);
1618 JSValue result = jsNumber(exec: callFrame, d: fmod(x: d1, y: d2));
1619 CHECK_FOR_EXCEPTION();
1620 callFrame->r(index: dst) = result;
1621 vPC += OPCODE_LENGTH(op_mod);
1622 NEXT_INSTRUCTION();
1623 }
1624 DEFINE_OPCODE(op_sub) {
1625 /* sub dst(r) src1(r) src2(r)
1626
1627 Subtracts register src2 (converted to number) from register
1628 src1 (converted to number), and puts the difference in
1629 register dst.
1630 */
1631 int dst = vPC[1].u.operand;
1632 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1633 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1634 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
1635 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: src1.asInt32() - src2.asInt32());
1636 else {
1637 JSValue result = jsNumber(exec: callFrame, d: src1.toNumber(exec: callFrame) - src2.toNumber(exec: callFrame));
1638 CHECK_FOR_EXCEPTION();
1639 callFrame->r(index: dst) = result;
1640 }
1641 vPC += OPCODE_LENGTH(op_sub);
1642 NEXT_INSTRUCTION();
1643 }
1644 DEFINE_OPCODE(op_lshift) {
1645 /* lshift dst(r) val(r) shift(r)
1646
1647 Performs left shift of register val (converted to int32) by
1648 register shift (converted to uint32), and puts the result
1649 in register dst.
1650 */
1651 int dst = vPC[1].u.operand;
1652 JSValue val = callFrame->r(index: vPC[2].u.operand).jsValue();
1653 JSValue shift = callFrame->r(index: vPC[3].u.operand).jsValue();
1654
1655 if (val.isInt32() && shift.isInt32())
1656 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: val.asInt32() << (shift.asInt32() & 0x1f));
1657 else {
1658 JSValue result = jsNumber(exec: callFrame, i: (val.toInt32(exec: callFrame)) << (shift.toUInt32(exec: callFrame) & 0x1f));
1659 CHECK_FOR_EXCEPTION();
1660 callFrame->r(index: dst) = result;
1661 }
1662
1663 vPC += OPCODE_LENGTH(op_lshift);
1664 NEXT_INSTRUCTION();
1665 }
1666 DEFINE_OPCODE(op_rshift) {
1667 /* rshift dst(r) val(r) shift(r)
1668
1669 Performs arithmetic right shift of register val (converted
1670 to int32) by register shift (converted to
1671 uint32), and puts the result in register dst.
1672 */
1673 int dst = vPC[1].u.operand;
1674 JSValue val = callFrame->r(index: vPC[2].u.operand).jsValue();
1675 JSValue shift = callFrame->r(index: vPC[3].u.operand).jsValue();
1676
1677 if (val.isInt32() && shift.isInt32())
1678 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: val.asInt32() >> (shift.asInt32() & 0x1f));
1679 else {
1680 JSValue result = jsNumber(exec: callFrame, i: (val.toInt32(exec: callFrame)) >> (shift.toUInt32(exec: callFrame) & 0x1f));
1681 CHECK_FOR_EXCEPTION();
1682 callFrame->r(index: dst) = result;
1683 }
1684
1685 vPC += OPCODE_LENGTH(op_rshift);
1686 NEXT_INSTRUCTION();
1687 }
1688 DEFINE_OPCODE(op_urshift) {
1689 /* rshift dst(r) val(r) shift(r)
1690
1691 Performs logical right shift of register val (converted
1692 to uint32) by register shift (converted to
1693 uint32), and puts the result in register dst.
1694 */
1695 int dst = vPC[1].u.operand;
1696 JSValue val = callFrame->r(index: vPC[2].u.operand).jsValue();
1697 JSValue shift = callFrame->r(index: vPC[3].u.operand).jsValue();
1698 if (val.isUInt32() && shift.isInt32())
1699 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: val.asInt32() >> (shift.asInt32() & 0x1f));
1700 else {
1701 JSValue result = jsNumber(exec: callFrame, i: (val.toUInt32(exec: callFrame)) >> (shift.toUInt32(exec: callFrame) & 0x1f));
1702 CHECK_FOR_EXCEPTION();
1703 callFrame->r(index: dst) = result;
1704 }
1705
1706 vPC += OPCODE_LENGTH(op_urshift);
1707 NEXT_INSTRUCTION();
1708 }
1709 DEFINE_OPCODE(op_bitand) {
1710 /* bitand dst(r) src1(r) src2(r)
1711
1712 Computes bitwise AND of register src1 (converted to int32)
1713 and register src2 (converted to int32), and puts the result
1714 in register dst.
1715 */
1716 int dst = vPC[1].u.operand;
1717 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1718 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1719 if (src1.isInt32() && src2.isInt32())
1720 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: src1.asInt32() & src2.asInt32());
1721 else {
1722 JSValue result = jsNumber(exec: callFrame, i: src1.toInt32(exec: callFrame) & src2.toInt32(exec: callFrame));
1723 CHECK_FOR_EXCEPTION();
1724 callFrame->r(index: dst) = result;
1725 }
1726
1727 vPC += OPCODE_LENGTH(op_bitand);
1728 NEXT_INSTRUCTION();
1729 }
1730 DEFINE_OPCODE(op_bitxor) {
1731 /* bitxor dst(r) src1(r) src2(r)
1732
1733 Computes bitwise XOR of register src1 (converted to int32)
1734 and register src2 (converted to int32), and puts the result
1735 in register dst.
1736 */
1737 int dst = vPC[1].u.operand;
1738 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1739 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1740 if (src1.isInt32() && src2.isInt32())
1741 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: src1.asInt32() ^ src2.asInt32());
1742 else {
1743 JSValue result = jsNumber(exec: callFrame, i: src1.toInt32(exec: callFrame) ^ src2.toInt32(exec: callFrame));
1744 CHECK_FOR_EXCEPTION();
1745 callFrame->r(index: dst) = result;
1746 }
1747
1748 vPC += OPCODE_LENGTH(op_bitxor);
1749 NEXT_INSTRUCTION();
1750 }
1751 DEFINE_OPCODE(op_bitor) {
1752 /* bitor dst(r) src1(r) src2(r)
1753
1754 Computes bitwise OR of register src1 (converted to int32)
1755 and register src2 (converted to int32), and puts the
1756 result in register dst.
1757 */
1758 int dst = vPC[1].u.operand;
1759 JSValue src1 = callFrame->r(index: vPC[2].u.operand).jsValue();
1760 JSValue src2 = callFrame->r(index: vPC[3].u.operand).jsValue();
1761 if (src1.isInt32() && src2.isInt32())
1762 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: src1.asInt32() | src2.asInt32());
1763 else {
1764 JSValue result = jsNumber(exec: callFrame, i: src1.toInt32(exec: callFrame) | src2.toInt32(exec: callFrame));
1765 CHECK_FOR_EXCEPTION();
1766 callFrame->r(index: dst) = result;
1767 }
1768
1769 vPC += OPCODE_LENGTH(op_bitor);
1770 NEXT_INSTRUCTION();
1771 }
1772 DEFINE_OPCODE(op_bitnot) {
1773 /* bitnot dst(r) src(r)
1774
1775 Computes bitwise NOT of register src1 (converted to int32),
1776 and puts the result in register dst.
1777 */
1778 int dst = vPC[1].u.operand;
1779 JSValue src = callFrame->r(index: vPC[2].u.operand).jsValue();
1780 if (src.isInt32())
1781 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: ~src.asInt32());
1782 else {
1783 JSValue result = jsNumber(exec: callFrame, i: ~src.toInt32(exec: callFrame));
1784 CHECK_FOR_EXCEPTION();
1785 callFrame->r(index: dst) = result;
1786 }
1787 vPC += OPCODE_LENGTH(op_bitnot);
1788 NEXT_INSTRUCTION();
1789 }
1790 DEFINE_OPCODE(op_not) {
1791 /* not dst(r) src(r)
1792
1793 Computes logical NOT of register src (converted to
1794 boolean), and puts the result in register dst.
1795 */
1796 int dst = vPC[1].u.operand;
1797 int src = vPC[2].u.operand;
1798 JSValue result = jsBoolean(b: !callFrame->r(index: src).jsValue().toBoolean(exec: callFrame));
1799 CHECK_FOR_EXCEPTION();
1800 callFrame->r(index: dst) = result;
1801
1802 vPC += OPCODE_LENGTH(op_not);
1803 NEXT_INSTRUCTION();
1804 }
1805 DEFINE_OPCODE(op_instanceof) {
1806 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
1807
1808 Tests whether register value is an instance of register
1809 constructor, and puts the boolean result in register
1810 dst. Register constructorProto must contain the "prototype"
1811 property (not the actual prototype) of the object in
1812 register constructor. This lookup is separated so that
1813 polymorphic inline caching can apply.
1814
1815 Raises an exception if register constructor is not an
1816 object.
1817 */
1818 int dst = vPC[1].u.operand;
1819 int value = vPC[2].u.operand;
1820 int base = vPC[3].u.operand;
1821 int baseProto = vPC[4].u.operand;
1822
1823 JSValue baseVal = callFrame->r(index: base).jsValue();
1824
1825 if (isInvalidParamForInstanceOf(callFrame, codeBlock: callFrame->codeBlock(), vPC, value: baseVal, exceptionData&: exceptionValue))
1826 goto vm_throw;
1827
1828 bool result = asObject(value: baseVal)->hasInstance(callFrame, callFrame->r(index: value).jsValue(), prototypeProperty: callFrame->r(index: baseProto).jsValue());
1829 CHECK_FOR_EXCEPTION();
1830 callFrame->r(index: dst) = jsBoolean(b: result);
1831
1832 vPC += OPCODE_LENGTH(op_instanceof);
1833 NEXT_INSTRUCTION();
1834 }
1835 DEFINE_OPCODE(op_typeof) {
1836 /* typeof dst(r) src(r)
1837
1838 Determines the type string for src according to ECMAScript
1839 rules, and puts the result in register dst.
1840 */
1841 int dst = vPC[1].u.operand;
1842 int src = vPC[2].u.operand;
1843 callFrame->r(index: dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(index: src).jsValue()));
1844
1845 vPC += OPCODE_LENGTH(op_typeof);
1846 NEXT_INSTRUCTION();
1847 }
1848 DEFINE_OPCODE(op_is_undefined) {
1849 /* is_undefined dst(r) src(r)
1850
1851 Determines whether the type string for src according to
1852 the ECMAScript rules is "undefined", and puts the result
1853 in register dst.
1854 */
1855 int dst = vPC[1].u.operand;
1856 int src = vPC[2].u.operand;
1857 JSValue v = callFrame->r(index: src).jsValue();
1858 callFrame->r(index: dst) = jsBoolean(b: v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
1859
1860 vPC += OPCODE_LENGTH(op_is_undefined);
1861 NEXT_INSTRUCTION();
1862 }
1863 DEFINE_OPCODE(op_is_boolean) {
1864 /* is_boolean dst(r) src(r)
1865
1866 Determines whether the type string for src according to
1867 the ECMAScript rules is "boolean", and puts the result
1868 in register dst.
1869 */
1870 int dst = vPC[1].u.operand;
1871 int src = vPC[2].u.operand;
1872 callFrame->r(index: dst) = jsBoolean(b: callFrame->r(index: src).jsValue().isBoolean());
1873
1874 vPC += OPCODE_LENGTH(op_is_boolean);
1875 NEXT_INSTRUCTION();
1876 }
1877 DEFINE_OPCODE(op_is_number) {
1878 /* is_number dst(r) src(r)
1879
1880 Determines whether the type string for src according to
1881 the ECMAScript rules is "number", and puts the result
1882 in register dst.
1883 */
1884 int dst = vPC[1].u.operand;
1885 int src = vPC[2].u.operand;
1886 callFrame->r(index: dst) = jsBoolean(b: callFrame->r(index: src).jsValue().isNumber());
1887
1888 vPC += OPCODE_LENGTH(op_is_number);
1889 NEXT_INSTRUCTION();
1890 }
1891 DEFINE_OPCODE(op_is_string) {
1892 /* is_string dst(r) src(r)
1893
1894 Determines whether the type string for src according to
1895 the ECMAScript rules is "string", and puts the result
1896 in register dst.
1897 */
1898 int dst = vPC[1].u.operand;
1899 int src = vPC[2].u.operand;
1900 callFrame->r(index: dst) = jsBoolean(b: callFrame->r(index: src).jsValue().isString());
1901
1902 vPC += OPCODE_LENGTH(op_is_string);
1903 NEXT_INSTRUCTION();
1904 }
1905 DEFINE_OPCODE(op_is_object) {
1906 /* is_object dst(r) src(r)
1907
1908 Determines whether the type string for src according to
1909 the ECMAScript rules is "object", and puts the result
1910 in register dst.
1911 */
1912 int dst = vPC[1].u.operand;
1913 int src = vPC[2].u.operand;
1914 callFrame->r(index: dst) = jsBoolean(b: jsIsObjectType(callFrame->r(index: src).jsValue()));
1915
1916 vPC += OPCODE_LENGTH(op_is_object);
1917 NEXT_INSTRUCTION();
1918 }
1919 DEFINE_OPCODE(op_is_function) {
1920 /* is_function dst(r) src(r)
1921
1922 Determines whether the type string for src according to
1923 the ECMAScript rules is "function", and puts the result
1924 in register dst.
1925 */
1926 int dst = vPC[1].u.operand;
1927 int src = vPC[2].u.operand;
1928 callFrame->r(index: dst) = jsBoolean(b: jsIsFunctionType(callFrame->r(index: src).jsValue()));
1929
1930 vPC += OPCODE_LENGTH(op_is_function);
1931 NEXT_INSTRUCTION();
1932 }
1933 DEFINE_OPCODE(op_in) {
1934 /* in dst(r) property(r) base(r)
1935
1936 Tests whether register base has a property named register
1937 property, and puts the boolean result in register dst.
1938
1939 Raises an exception if register constructor is not an
1940 object.
1941 */
1942 int dst = vPC[1].u.operand;
1943 int property = vPC[2].u.operand;
1944 int base = vPC[3].u.operand;
1945
1946 JSValue baseVal = callFrame->r(index: base).jsValue();
1947 if (isInvalidParamForIn(callFrame, codeBlock: callFrame->codeBlock(), vPC, value: baseVal, exceptionData&: exceptionValue))
1948 goto vm_throw;
1949
1950 JSObject* baseObj = asObject(value: baseVal);
1951
1952 JSValue propName = callFrame->r(index: property).jsValue();
1953
1954 uint32_t i;
1955 if (propName.getUInt32(v&: i))
1956 callFrame->r(index: dst) = jsBoolean(b: baseObj->hasProperty(callFrame, propertyName: i));
1957 else {
1958 Identifier property(callFrame, propName.toString(exec: callFrame));
1959 CHECK_FOR_EXCEPTION();
1960 callFrame->r(index: dst) = jsBoolean(b: baseObj->hasProperty(callFrame, propertyName: property));
1961 }
1962
1963 vPC += OPCODE_LENGTH(op_in);
1964 NEXT_INSTRUCTION();
1965 }
1966 DEFINE_OPCODE(op_resolve) {
1967 /* resolve dst(r) property(id)
1968
1969 Looks up the property named by identifier property in the
1970 scope chain, and writes the resulting value to register
1971 dst. If the property is not found, raises an exception.
1972 */
1973 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
1974 goto vm_throw;
1975
1976 vPC += OPCODE_LENGTH(op_resolve);
1977 NEXT_INSTRUCTION();
1978 }
1979 DEFINE_OPCODE(op_resolve_skip) {
1980 /* resolve_skip dst(r) property(id) skip(n)
1981
1982 Looks up the property named by identifier property in the
1983 scope chain skipping the top 'skip' levels, and writes the resulting
1984 value to register dst. If the property is not found, raises an exception.
1985 */
1986 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
1987 goto vm_throw;
1988
1989 vPC += OPCODE_LENGTH(op_resolve_skip);
1990
1991 NEXT_INSTRUCTION();
1992 }
1993 DEFINE_OPCODE(op_resolve_global) {
1994 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
1995
1996 Performs a dynamic property lookup for the given property, on the provided
1997 global object. If structure matches the Structure of the global then perform
1998 a fast lookup using the case offset, otherwise fall back to a full resolve and
1999 cache the new structure and offset
2000 */
2001 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
2002 goto vm_throw;
2003
2004 vPC += OPCODE_LENGTH(op_resolve_global);
2005
2006 NEXT_INSTRUCTION();
2007 }
2008 DEFINE_OPCODE(op_get_global_var) {
2009 /* get_global_var dst(r) globalObject(c) index(n)
2010
2011 Gets the global var at global slot index and places it in register dst.
2012 */
2013 int dst = vPC[1].u.operand;
2014 JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
2015 ASSERT(scope->isGlobalObject());
2016 int index = vPC[3].u.operand;
2017
2018 callFrame->r(index: dst) = scope->registerAt(index);
2019 vPC += OPCODE_LENGTH(op_get_global_var);
2020 NEXT_INSTRUCTION();
2021 }
2022 DEFINE_OPCODE(op_put_global_var) {
2023 /* put_global_var globalObject(c) index(n) value(r)
2024
2025 Puts value into global slot index.
2026 */
2027 JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[1].u.jsCell);
2028 ASSERT(scope->isGlobalObject());
2029 int index = vPC[2].u.operand;
2030 int value = vPC[3].u.operand;
2031
2032 scope->registerAt(index) = JSValue(callFrame->r(index: value).jsValue());
2033 vPC += OPCODE_LENGTH(op_put_global_var);
2034 NEXT_INSTRUCTION();
2035 }
2036 DEFINE_OPCODE(op_get_scoped_var) {
2037 /* get_scoped_var dst(r) index(n) skip(n)
2038
2039 Loads the contents of the index-th local from the scope skip nodes from
2040 the top of the scope chain, and places it in register dst
2041 */
2042 int dst = vPC[1].u.operand;
2043 int index = vPC[2].u.operand;
2044 int skip = vPC[3].u.operand + callFrame->codeBlock()->needsFullScopeChain();
2045
2046 ScopeChainNode* scopeChain = callFrame->scopeChain();
2047 ScopeChainIterator iter = scopeChain->begin();
2048 ScopeChainIterator end = scopeChain->end();
2049 ASSERT(iter != end);
2050 while (skip--) {
2051 ++iter;
2052 ASSERT(iter != end);
2053 }
2054
2055 ASSERT((*iter)->isVariableObject());
2056 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2057 callFrame->r(index: dst) = scope->registerAt(index);
2058 vPC += OPCODE_LENGTH(op_get_scoped_var);
2059 NEXT_INSTRUCTION();
2060 }
2061 DEFINE_OPCODE(op_put_scoped_var) {
2062 /* put_scoped_var index(n) skip(n) value(r)
2063
2064 */
2065 int index = vPC[1].u.operand;
2066 int skip = vPC[2].u.operand + callFrame->codeBlock()->needsFullScopeChain();
2067 int value = vPC[3].u.operand;
2068
2069 ScopeChainNode* scopeChain = callFrame->scopeChain();
2070 ScopeChainIterator iter = scopeChain->begin();
2071 ScopeChainIterator end = scopeChain->end();
2072 ASSERT(iter != end);
2073 while (skip--) {
2074 ++iter;
2075 ASSERT(iter != end);
2076 }
2077
2078 ASSERT((*iter)->isVariableObject());
2079 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2080 scope->registerAt(index) = JSValue(callFrame->r(index: value).jsValue());
2081 vPC += OPCODE_LENGTH(op_put_scoped_var);
2082 NEXT_INSTRUCTION();
2083 }
2084 DEFINE_OPCODE(op_resolve_base) {
2085 /* resolve_base dst(r) property(id)
2086
2087 Searches the scope chain for an object containing
2088 identifier property, and if one is found, writes it to
2089 register dst. If none is found, the outermost scope (which
2090 will be the global object) is stored in register dst.
2091 */
2092 resolveBase(callFrame, vPC);
2093
2094 vPC += OPCODE_LENGTH(op_resolve_base);
2095 NEXT_INSTRUCTION();
2096 }
2097 DEFINE_OPCODE(op_resolve_with_base) {
2098 /* resolve_with_base baseDst(r) propDst(r) property(id)
2099
2100 Searches the scope chain for an object containing
2101 identifier property, and if one is found, writes it to
2102 register srcDst, and the retrieved property value to register
2103 propDst. If the property is not found, raises an exception.
2104
2105 This is more efficient than doing resolve_base followed by
2106 resolve, or resolve_base followed by get_by_id, as it
2107 avoids duplicate hash lookups.
2108 */
2109 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
2110 goto vm_throw;
2111
2112 vPC += OPCODE_LENGTH(op_resolve_with_base);
2113 NEXT_INSTRUCTION();
2114 }
2115 DEFINE_OPCODE(op_get_by_id) {
2116 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2117
2118 Generic property access: Gets the property named by identifier
2119 property from the value base, and puts the result in register dst.
2120 */
2121 int dst = vPC[1].u.operand;
2122 int base = vPC[2].u.operand;
2123 int property = vPC[3].u.operand;
2124
2125 CodeBlock* codeBlock = callFrame->codeBlock();
2126 Identifier& ident = codeBlock->identifier(index: property);
2127 JSValue baseValue = callFrame->r(index: base).jsValue();
2128 PropertySlot slot(baseValue);
2129 JSValue result = baseValue.get(exec: callFrame, propertyName: ident, slot);
2130 CHECK_FOR_EXCEPTION();
2131
2132 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, propertyName: ident, slot);
2133
2134 callFrame->r(index: dst) = result;
2135 vPC += OPCODE_LENGTH(op_get_by_id);
2136 NEXT_INSTRUCTION();
2137 }
2138 DEFINE_OPCODE(op_get_by_id_self) {
2139 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2140
2141 Cached property access: Attempts to get a cached property from the
2142 value base. If the cache misses, op_get_by_id_self reverts to
2143 op_get_by_id.
2144 */
2145 int base = vPC[2].u.operand;
2146 JSValue baseValue = callFrame->r(index: base).jsValue();
2147
2148 if (LIKELY(baseValue.isCell())) {
2149 JSCell* baseCell = asCell(value: baseValue);
2150 Structure* structure = vPC[4].u.structure;
2151
2152 if (LIKELY(baseCell->structure() == structure)) {
2153 ASSERT(baseCell->isObject());
2154 JSObject* baseObject = asObject(cell: baseCell);
2155 int dst = vPC[1].u.operand;
2156 int offset = vPC[5].u.operand;
2157
2158 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2159 callFrame->r(index: dst) = JSValue(baseObject->getDirectOffset(offset));
2160
2161 vPC += OPCODE_LENGTH(op_get_by_id_self);
2162 NEXT_INSTRUCTION();
2163 }
2164 }
2165
2166 uncacheGetByID(codeBlock: callFrame->codeBlock(), vPC);
2167 NEXT_INSTRUCTION();
2168 }
2169 DEFINE_OPCODE(op_get_by_id_proto) {
2170 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2171
2172 Cached property access: Attempts to get a cached property from the
2173 value base's prototype. If the cache misses, op_get_by_id_proto
2174 reverts to op_get_by_id.
2175 */
2176 int base = vPC[2].u.operand;
2177 JSValue baseValue = callFrame->r(index: base).jsValue();
2178
2179 if (LIKELY(baseValue.isCell())) {
2180 JSCell* baseCell = asCell(value: baseValue);
2181 Structure* structure = vPC[4].u.structure;
2182
2183 if (LIKELY(baseCell->structure() == structure)) {
2184 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2185 JSObject* protoObject = asObject(value: structure->prototypeForLookup(exec: callFrame));
2186 Structure* prototypeStructure = vPC[5].u.structure;
2187
2188 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2189 int dst = vPC[1].u.operand;
2190 int offset = vPC[6].u.operand;
2191
2192 ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2193 ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2194 callFrame->r(index: dst) = JSValue(protoObject->getDirectOffset(offset));
2195
2196 vPC += OPCODE_LENGTH(op_get_by_id_proto);
2197 NEXT_INSTRUCTION();
2198 }
2199 }
2200 }
2201
2202 uncacheGetByID(codeBlock: callFrame->codeBlock(), vPC);
2203 NEXT_INSTRUCTION();
2204 }
2205 DEFINE_OPCODE(op_get_by_id_self_list) {
2206 // Polymorphic self access caching currently only supported when JITting.
2207 ASSERT_NOT_REACHED();
2208 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2209 vPC += OPCODE_LENGTH(op_get_by_id_self_list);
2210 NEXT_INSTRUCTION();
2211 }
2212 DEFINE_OPCODE(op_get_by_id_proto_list) {
2213 // Polymorphic prototype access caching currently only supported when JITting.
2214 ASSERT_NOT_REACHED();
2215 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2216 vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
2217 NEXT_INSTRUCTION();
2218 }
2219 DEFINE_OPCODE(op_get_by_id_chain) {
2220 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2221
2222 Cached property access: Attempts to get a cached property from the
2223 value base's prototype chain. If the cache misses, op_get_by_id_chain
2224 reverts to op_get_by_id.
2225 */
2226 int base = vPC[2].u.operand;
2227 JSValue baseValue = callFrame->r(index: base).jsValue();
2228
2229 if (LIKELY(baseValue.isCell())) {
2230 JSCell* baseCell = asCell(value: baseValue);
2231 Structure* structure = vPC[4].u.structure;
2232
2233 if (LIKELY(baseCell->structure() == structure)) {
2234 RefPtr<Structure>* it = vPC[5].u.structureChain->head();
2235 size_t count = vPC[6].u.operand;
2236 RefPtr<Structure>* end = it + count;
2237
2238 while (true) {
2239 JSObject* baseObject = asObject(value: baseCell->structure()->prototypeForLookup(exec: callFrame));
2240
2241 if (UNLIKELY(baseObject->structure() != (*it).get()))
2242 break;
2243
2244 if (++it == end) {
2245 int dst = vPC[1].u.operand;
2246 int offset = vPC[7].u.operand;
2247
2248 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2249 ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2250 callFrame->r(index: dst) = JSValue(baseObject->getDirectOffset(offset));
2251
2252 vPC += OPCODE_LENGTH(op_get_by_id_chain);
2253 NEXT_INSTRUCTION();
2254 }
2255
2256 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2257 baseCell = baseObject;
2258 }
2259 }
2260 }
2261
2262 uncacheGetByID(codeBlock: callFrame->codeBlock(), vPC);
2263 NEXT_INSTRUCTION();
2264 }
2265 DEFINE_OPCODE(op_get_by_id_generic) {
2266 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2267
2268 Generic property access: Gets the property named by identifier
2269 property from the value base, and puts the result in register dst.
2270 */
2271 int dst = vPC[1].u.operand;
2272 int base = vPC[2].u.operand;
2273 int property = vPC[3].u.operand;
2274
2275 Identifier& ident = callFrame->codeBlock()->identifier(index: property);
2276 JSValue baseValue = callFrame->r(index: base).jsValue();
2277 PropertySlot slot(baseValue);
2278 JSValue result = baseValue.get(exec: callFrame, propertyName: ident, slot);
2279 CHECK_FOR_EXCEPTION();
2280
2281 callFrame->r(index: dst) = result;
2282 vPC += OPCODE_LENGTH(op_get_by_id_generic);
2283 NEXT_INSTRUCTION();
2284 }
2285 DEFINE_OPCODE(op_get_array_length) {
2286 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2287
2288 Cached property access: Gets the length of the array in register base,
2289 and puts the result in register dst. If register base does not hold
2290 an array, op_get_array_length reverts to op_get_by_id.
2291 */
2292
2293 int base = vPC[2].u.operand;
2294 JSValue baseValue = callFrame->r(index: base).jsValue();
2295 if (LIKELY(isJSArray(globalData, baseValue))) {
2296 int dst = vPC[1].u.operand;
2297 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: asArray(value: baseValue)->length());
2298 vPC += OPCODE_LENGTH(op_get_array_length);
2299 NEXT_INSTRUCTION();
2300 }
2301
2302 uncacheGetByID(codeBlock: callFrame->codeBlock(), vPC);
2303 NEXT_INSTRUCTION();
2304 }
2305 DEFINE_OPCODE(op_get_string_length) {
2306 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2307
2308 Cached property access: Gets the length of the string in register base,
2309 and puts the result in register dst. If register base does not hold
2310 a string, op_get_string_length reverts to op_get_by_id.
2311 */
2312
2313 int base = vPC[2].u.operand;
2314 JSValue baseValue = callFrame->r(index: base).jsValue();
2315 if (LIKELY(isJSString(globalData, baseValue))) {
2316 int dst = vPC[1].u.operand;
2317 callFrame->r(index: dst) = jsNumber(exec: callFrame, i: asString(value: baseValue)->length());
2318 vPC += OPCODE_LENGTH(op_get_string_length);
2319 NEXT_INSTRUCTION();
2320 }
2321
2322 uncacheGetByID(codeBlock: callFrame->codeBlock(), vPC);
2323 NEXT_INSTRUCTION();
2324 }
2325 DEFINE_OPCODE(op_put_by_id) {
2326 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2327
2328 Generic property access: Sets the property named by identifier
2329 property, belonging to register base, to register value.
2330
2331 Unlike many opcodes, this one does not write any output to
2332 the register file.
2333 */
2334
2335 int base = vPC[1].u.operand;
2336 int property = vPC[2].u.operand;
2337 int value = vPC[3].u.operand;
2338
2339 CodeBlock* codeBlock = callFrame->codeBlock();
2340 JSValue baseValue = callFrame->r(index: base).jsValue();
2341 Identifier& ident = codeBlock->identifier(index: property);
2342 PutPropertySlot slot;
2343 baseValue.put(exec: callFrame, propertyName: ident, value: callFrame->r(index: value).jsValue(), slot);
2344 CHECK_FOR_EXCEPTION();
2345
2346 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
2347
2348 vPC += OPCODE_LENGTH(op_put_by_id);
2349 NEXT_INSTRUCTION();
2350 }
2351 DEFINE_OPCODE(op_put_by_id_transition) {
2352 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)
2353
2354 Cached property access: Attempts to set a new property with a cached transition
2355 property named by identifier property, belonging to register base,
2356 to register value. If the cache misses, op_put_by_id_transition
2357 reverts to op_put_by_id_generic.
2358
2359 Unlike many opcodes, this one does not write any output to
2360 the register file.
2361 */
2362 int base = vPC[1].u.operand;
2363 JSValue baseValue = callFrame->r(index: base).jsValue();
2364
2365 if (LIKELY(baseValue.isCell())) {
2366 JSCell* baseCell = asCell(value: baseValue);
2367 Structure* oldStructure = vPC[4].u.structure;
2368 Structure* newStructure = vPC[5].u.structure;
2369
2370 if (LIKELY(baseCell->structure() == oldStructure)) {
2371 ASSERT(baseCell->isObject());
2372 JSObject* baseObject = asObject(cell: baseCell);
2373
2374 RefPtr<Structure>* it = vPC[6].u.structureChain->head();
2375
2376 JSValue proto = baseObject->structure()->prototypeForLookup(exec: callFrame);
2377 while (!proto.isNull()) {
2378 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
2379 uncachePutByID(codeBlock: callFrame->codeBlock(), vPC);
2380 NEXT_INSTRUCTION();
2381 }
2382 ++it;
2383 proto = asObject(value: proto)->structure()->prototypeForLookup(exec: callFrame);
2384 }
2385
2386 baseObject->transitionTo(newStructure);
2387
2388 int value = vPC[3].u.operand;
2389 unsigned offset = vPC[7].u.operand;
2390 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2391 baseObject->putDirectOffset(offset, value: callFrame->r(index: value).jsValue());
2392
2393 vPC += OPCODE_LENGTH(op_put_by_id_transition);
2394 NEXT_INSTRUCTION();
2395 }
2396 }
2397
2398 uncachePutByID(codeBlock: callFrame->codeBlock(), vPC);
2399 NEXT_INSTRUCTION();
2400 }
2401 DEFINE_OPCODE(op_put_by_id_replace) {
2402 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)
2403
2404 Cached property access: Attempts to set a pre-existing, cached
2405 property named by identifier property, belonging to register base,
2406 to register value. If the cache misses, op_put_by_id_replace
2407 reverts to op_put_by_id.
2408
2409 Unlike many opcodes, this one does not write any output to
2410 the register file.
2411 */
2412 int base = vPC[1].u.operand;
2413 JSValue baseValue = callFrame->r(index: base).jsValue();
2414
2415 if (LIKELY(baseValue.isCell())) {
2416 JSCell* baseCell = asCell(value: baseValue);
2417 Structure* structure = vPC[4].u.structure;
2418
2419 if (LIKELY(baseCell->structure() == structure)) {
2420 ASSERT(baseCell->isObject());
2421 JSObject* baseObject = asObject(cell: baseCell);
2422 int value = vPC[3].u.operand;
2423 unsigned offset = vPC[5].u.operand;
2424
2425 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2426 baseObject->putDirectOffset(offset, value: callFrame->r(index: value).jsValue());
2427
2428 vPC += OPCODE_LENGTH(op_put_by_id_replace);
2429 NEXT_INSTRUCTION();
2430 }
2431 }
2432
2433 uncachePutByID(codeBlock: callFrame->codeBlock(), vPC);
2434 NEXT_INSTRUCTION();
2435 }
2436 DEFINE_OPCODE(op_put_by_id_generic) {
2437 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2438
2439 Generic property access: Sets the property named by identifier
2440 property, belonging to register base, to register value.
2441
2442 Unlike many opcodes, this one does not write any output to
2443 the register file.
2444 */
2445 int base = vPC[1].u.operand;
2446 int property = vPC[2].u.operand;
2447 int value = vPC[3].u.operand;
2448
2449 JSValue baseValue = callFrame->r(index: base).jsValue();
2450 Identifier& ident = callFrame->codeBlock()->identifier(index: property);
2451 PutPropertySlot slot;
2452 baseValue.put(exec: callFrame, propertyName: ident, value: callFrame->r(index: value).jsValue(), slot);
2453 CHECK_FOR_EXCEPTION();
2454
2455 vPC += OPCODE_LENGTH(op_put_by_id_generic);
2456 NEXT_INSTRUCTION();
2457 }
2458 DEFINE_OPCODE(op_del_by_id) {
2459 /* del_by_id dst(r) base(r) property(id)
2460
2461 Converts register base to Object, deletes the property
2462 named by identifier property from the object, and writes a
2463 boolean indicating success (if true) or failure (if false)
2464 to register dst.
2465 */
2466 int dst = vPC[1].u.operand;
2467 int base = vPC[2].u.operand;
2468 int property = vPC[3].u.operand;
2469
2470 JSObject* baseObj = callFrame->r(index: base).jsValue().toObject(exec: callFrame);
2471 Identifier& ident = callFrame->codeBlock()->identifier(index: property);
2472 JSValue result = jsBoolean(b: baseObj->deleteProperty(callFrame, propertyName: ident));
2473 CHECK_FOR_EXCEPTION();
2474 callFrame->r(index: dst) = result;
2475 vPC += OPCODE_LENGTH(op_del_by_id);
2476 NEXT_INSTRUCTION();
2477 }
2478 DEFINE_OPCODE(op_get_by_pname) {
2479 int dst = vPC[1].u.operand;
2480 int base = vPC[2].u.operand;
2481 int property = vPC[3].u.operand;
2482 int expected = vPC[4].u.operand;
2483 int iter = vPC[5].u.operand;
2484 int i = vPC[6].u.operand;
2485
2486 JSValue baseValue = callFrame->r(index: base).jsValue();
2487 JSPropertyNameIterator* it = callFrame->r(index: iter).propertyNameIterator();
2488 JSValue subscript = callFrame->r(index: property).jsValue();
2489 JSValue expectedSubscript = callFrame->r(index: expected).jsValue();
2490 int index = callFrame->r(index: i).i() - 1;
2491 JSValue result;
2492 int offset = 0;
2493 if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(i: index, offset)) {
2494 callFrame->r(index: dst) = asObject(value: baseValue)->getDirectOffset(offset);
2495 vPC += OPCODE_LENGTH(op_get_by_pname);
2496 NEXT_INSTRUCTION();
2497 }
2498 {
2499 Identifier propertyName(callFrame, subscript.toString(exec: callFrame));
2500 result = baseValue.get(exec: callFrame, propertyName);
2501 }
2502 CHECK_FOR_EXCEPTION();
2503 callFrame->r(index: dst) = result;
2504 vPC += OPCODE_LENGTH(op_get_by_pname);
2505 NEXT_INSTRUCTION();
2506 }
2507 DEFINE_OPCODE(op_get_by_val) {
2508 /* get_by_val dst(r) base(r) property(r)
2509
2510 Converts register base to Object, gets the property named
2511 by register property from the object, and puts the result
2512 in register dst. property is nominally converted to string
2513 but numbers are treated more efficiently.
2514 */
2515 int dst = vPC[1].u.operand;
2516 int base = vPC[2].u.operand;
2517 int property = vPC[3].u.operand;
2518
2519 JSValue baseValue = callFrame->r(index: base).jsValue();
2520 JSValue subscript = callFrame->r(index: property).jsValue();
2521
2522 JSValue result;
2523
2524 if (LIKELY(subscript.isUInt32())) {
2525 uint32_t i = subscript.asUInt32();
2526 if (isJSArray(globalData, v: baseValue)) {
2527 JSArray* jsArray = asArray(value: baseValue);
2528 if (jsArray->canGetIndex(i))
2529 result = jsArray->getIndex(i);
2530 else
2531 result = jsArray->JSArray::get(exec: callFrame, propertyName: i);
2532 } else if (isJSString(globalData, v: baseValue) && asString(value: baseValue)->canGetIndex(i))
2533 result = asString(value: baseValue)->getIndex(exec: callFrame, i);
2534 else if (isJSByteArray(globalData, v: baseValue) && asByteArray(value: baseValue)->canAccessIndex(i))
2535 result = asByteArray(value: baseValue)->getIndex(exec: callFrame, i);
2536 else
2537 result = baseValue.get(exec: callFrame, propertyName: i);
2538 } else {
2539 Identifier property(callFrame, subscript.toString(exec: callFrame));
2540 result = baseValue.get(exec: callFrame, propertyName: property);
2541 }
2542
2543 CHECK_FOR_EXCEPTION();
2544 callFrame->r(index: dst) = result;
2545 vPC += OPCODE_LENGTH(op_get_by_val);
2546 NEXT_INSTRUCTION();
2547 }
2548 DEFINE_OPCODE(op_put_by_val) {
2549 /* put_by_val base(r) property(r) value(r)
2550
2551 Sets register value on register base as the property named
2552 by register property. Base is converted to object
2553 first. register property is nominally converted to string
2554 but numbers are treated more efficiently.
2555
2556 Unlike many opcodes, this one does not write any output to
2557 the register file.
2558 */
2559 int base = vPC[1].u.operand;
2560 int property = vPC[2].u.operand;
2561 int value = vPC[3].u.operand;
2562
2563 JSValue baseValue = callFrame->r(index: base).jsValue();
2564 JSValue subscript = callFrame->r(index: property).jsValue();
2565
2566 if (LIKELY(subscript.isUInt32())) {
2567 uint32_t i = subscript.asUInt32();
2568 if (isJSArray(globalData, v: baseValue)) {
2569 JSArray* jsArray = asArray(value: baseValue);
2570 if (jsArray->canSetIndex(i))
2571 jsArray->setIndex(i, v: callFrame->r(index: value).jsValue());
2572 else
2573 jsArray->JSArray::put(callFrame, propertyName: i, callFrame->r(index: value).jsValue());
2574 } else if (isJSByteArray(globalData, v: baseValue) && asByteArray(value: baseValue)->canAccessIndex(i)) {
2575 JSByteArray* jsByteArray = asByteArray(value: baseValue);
2576 double dValue = 0;
2577 JSValue jsValue = callFrame->r(index: value).jsValue();
2578 if (jsValue.isInt32())
2579 jsByteArray->setIndex(i, value: jsValue.asInt32());
2580 else if (jsValue.getNumber(result&: dValue))
2581 jsByteArray->setIndex(i, value: dValue);
2582 else
2583 baseValue.put(exec: callFrame, propertyName: i, value: jsValue);
2584 } else
2585 baseValue.put(exec: callFrame, propertyName: i, value: callFrame->r(index: value).jsValue());
2586 } else {
2587 Identifier property(callFrame, subscript.toString(exec: callFrame));
2588 if (!globalData->exception) { // Don't put to an object if toString threw an exception.
2589 PutPropertySlot slot;
2590 baseValue.put(exec: callFrame, propertyName: property, value: callFrame->r(index: value).jsValue(), slot);
2591 }
2592 }
2593
2594 CHECK_FOR_EXCEPTION();
2595 vPC += OPCODE_LENGTH(op_put_by_val);
2596 NEXT_INSTRUCTION();
2597 }
2598 DEFINE_OPCODE(op_del_by_val) {
2599 /* del_by_val dst(r) base(r) property(r)
2600
2601 Converts register base to Object, deletes the property
2602 named by register property from the object, and writes a
2603 boolean indicating success (if true) or failure (if false)
2604 to register dst.
2605 */
2606 int dst = vPC[1].u.operand;
2607 int base = vPC[2].u.operand;
2608 int property = vPC[3].u.operand;
2609
2610 JSObject* baseObj = callFrame->r(index: base).jsValue().toObject(exec: callFrame); // may throw
2611
2612 JSValue subscript = callFrame->r(index: property).jsValue();
2613 JSValue result;
2614 uint32_t i;
2615 if (subscript.getUInt32(v&: i))
2616 result = jsBoolean(b: baseObj->deleteProperty(callFrame, propertyName: i));
2617 else {
2618 CHECK_FOR_EXCEPTION();
2619 Identifier property(callFrame, subscript.toString(exec: callFrame));
2620 CHECK_FOR_EXCEPTION();
2621 result = jsBoolean(b: baseObj->deleteProperty(callFrame, propertyName: property));
2622 }
2623
2624 CHECK_FOR_EXCEPTION();
2625 callFrame->r(index: dst) = result;
2626 vPC += OPCODE_LENGTH(op_del_by_val);
2627 NEXT_INSTRUCTION();
2628 }
2629 DEFINE_OPCODE(op_put_by_index) {
2630 /* put_by_index base(r) property(n) value(r)
2631
2632 Sets register value on register base as the property named
2633 by the immediate number property. Base is converted to
2634 object first.
2635
2636 Unlike many opcodes, this one does not write any output to
2637 the register file.
2638
2639 This opcode is mainly used to initialize array literals.
2640 */
2641 int base = vPC[1].u.operand;
2642 unsigned property = vPC[2].u.operand;
2643 int value = vPC[3].u.operand;
2644
2645 callFrame->r(index: base).jsValue().put(exec: callFrame, propertyName: property, value: callFrame->r(index: value).jsValue());
2646
2647 vPC += OPCODE_LENGTH(op_put_by_index);
2648 NEXT_INSTRUCTION();
2649 }
2650 DEFINE_OPCODE(op_loop) {
2651 /* loop target(offset)
2652
2653 Jumps unconditionally to offset target from the current
2654 instruction.
2655
2656 Additionally this loop instruction may terminate JS execution is
2657 the JS timeout is reached.
2658 */
2659#if ENABLE(OPCODE_STATS)
2660 OpcodeStats::resetLastInstruction();
2661#endif
2662 int target = vPC[1].u.operand;
2663 CHECK_FOR_TIMEOUT();
2664 vPC += target;
2665 NEXT_INSTRUCTION();
2666 }
2667 DEFINE_OPCODE(op_jmp) {
2668 /* jmp target(offset)
2669
2670 Jumps unconditionally to offset target from the current
2671 instruction.
2672 */
2673#if ENABLE(OPCODE_STATS)
2674 OpcodeStats::resetLastInstruction();
2675#endif
2676 int target = vPC[1].u.operand;
2677
2678 vPC += target;
2679 NEXT_INSTRUCTION();
2680 }
2681 DEFINE_OPCODE(op_loop_if_true) {
2682 /* loop_if_true cond(r) target(offset)
2683
2684 Jumps to offset target from the current instruction, if and
2685 only if register cond converts to boolean as true.
2686
2687 Additionally this loop instruction may terminate JS execution is
2688 the JS timeout is reached.
2689 */
2690 int cond = vPC[1].u.operand;
2691 int target = vPC[2].u.operand;
2692 if (callFrame->r(index: cond).jsValue().toBoolean(exec: callFrame)) {
2693 vPC += target;
2694 CHECK_FOR_TIMEOUT();
2695 NEXT_INSTRUCTION();
2696 }
2697
2698 vPC += OPCODE_LENGTH(op_loop_if_true);
2699 NEXT_INSTRUCTION();
2700 }
2701 DEFINE_OPCODE(op_loop_if_false) {
2702 /* loop_if_true cond(r) target(offset)
2703
2704 Jumps to offset target from the current instruction, if and
2705 only if register cond converts to boolean as false.
2706
2707 Additionally this loop instruction may terminate JS execution is
2708 the JS timeout is reached.
2709 */
2710 int cond = vPC[1].u.operand;
2711 int target = vPC[2].u.operand;
2712 if (!callFrame->r(index: cond).jsValue().toBoolean(exec: callFrame)) {
2713 vPC += target;
2714 CHECK_FOR_TIMEOUT();
2715 NEXT_INSTRUCTION();
2716 }
2717
2718 vPC += OPCODE_LENGTH(op_loop_if_true);
2719 NEXT_INSTRUCTION();
2720 }
2721 DEFINE_OPCODE(op_jtrue) {
2722 /* jtrue cond(r) target(offset)
2723
2724 Jumps to offset target from the current instruction, if and
2725 only if register cond converts to boolean as true.
2726 */
2727 int cond = vPC[1].u.operand;
2728 int target = vPC[2].u.operand;
2729 if (callFrame->r(index: cond).jsValue().toBoolean(exec: callFrame)) {
2730 vPC += target;
2731 NEXT_INSTRUCTION();
2732 }
2733
2734 vPC += OPCODE_LENGTH(op_jtrue);
2735 NEXT_INSTRUCTION();
2736 }
2737 DEFINE_OPCODE(op_jfalse) {
2738 /* jfalse cond(r) target(offset)
2739
2740 Jumps to offset target from the current instruction, if and
2741 only if register cond converts to boolean as false.
2742 */
2743 int cond = vPC[1].u.operand;
2744 int target = vPC[2].u.operand;
2745 if (!callFrame->r(index: cond).jsValue().toBoolean(exec: callFrame)) {
2746 vPC += target;
2747 NEXT_INSTRUCTION();
2748 }
2749
2750 vPC += OPCODE_LENGTH(op_jfalse);
2751 NEXT_INSTRUCTION();
2752 }
2753 DEFINE_OPCODE(op_jeq_null) {
2754 /* jeq_null src(r) target(offset)
2755
2756 Jumps to offset target from the current instruction, if and
2757 only if register src is null.
2758 */
2759 int src = vPC[1].u.operand;
2760 int target = vPC[2].u.operand;
2761 JSValue srcValue = callFrame->r(index: src).jsValue();
2762
2763 if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2764 vPC += target;
2765 NEXT_INSTRUCTION();
2766 }
2767
2768 vPC += OPCODE_LENGTH(op_jeq_null);
2769 NEXT_INSTRUCTION();
2770 }
2771 DEFINE_OPCODE(op_jneq_null) {
2772 /* jneq_null src(r) target(offset)
2773
2774 Jumps to offset target from the current instruction, if and
2775 only if register src is not null.
2776 */
2777 int src = vPC[1].u.operand;
2778 int target = vPC[2].u.operand;
2779 JSValue srcValue = callFrame->r(index: src).jsValue();
2780
2781 if (!srcValue.isUndefinedOrNull() && (!srcValue.isCell() || !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2782 vPC += target;
2783 NEXT_INSTRUCTION();
2784 }
2785
2786 vPC += OPCODE_LENGTH(op_jneq_null);
2787 NEXT_INSTRUCTION();
2788 }
2789 DEFINE_OPCODE(op_jneq_ptr) {
2790 /* jneq_ptr src(r) ptr(jsCell) target(offset)
2791
2792 Jumps to offset target from the current instruction, if the value r is equal
2793 to ptr, using pointer equality.
2794 */
2795 int src = vPC[1].u.operand;
2796 JSValue ptr = JSValue(vPC[2].u.jsCell);
2797 int target = vPC[3].u.operand;
2798 JSValue srcValue = callFrame->r(index: src).jsValue();
2799 if (srcValue != ptr) {
2800 vPC += target;
2801 NEXT_INSTRUCTION();
2802 }
2803
2804 vPC += OPCODE_LENGTH(op_jneq_ptr);
2805 NEXT_INSTRUCTION();
2806 }
2807 DEFINE_OPCODE(op_loop_if_less) {
2808 /* loop_if_less src1(r) src2(r) target(offset)
2809
2810 Checks whether register src1 is less than register src2, as
2811 with the ECMAScript '<' operator, and then jumps to offset
2812 target from the current instruction, if and only if the
2813 result of the comparison is true.
2814
2815 Additionally this loop instruction may terminate JS execution is
2816 the JS timeout is reached.
2817 */
2818 JSValue src1 = callFrame->r(index: vPC[1].u.operand).jsValue();
2819 JSValue src2 = callFrame->r(index: vPC[2].u.operand).jsValue();
2820 int target = vPC[3].u.operand;
2821
2822 bool result = jsLess(callFrame, v1: src1, v2: src2);
2823 CHECK_FOR_EXCEPTION();
2824
2825 if (result) {
2826 vPC += target;
2827 CHECK_FOR_TIMEOUT();
2828 NEXT_INSTRUCTION();
2829 }
2830
2831 vPC += OPCODE_LENGTH(op_loop_if_less);
2832 NEXT_INSTRUCTION();
2833 }
2834 DEFINE_OPCODE(op_loop_if_lesseq) {
2835 /* loop_if_lesseq src1(r) src2(r) target(offset)
2836
2837 Checks whether register src1 is less than or equal to register
2838 src2, as with the ECMAScript '<=' operator, and then jumps to
2839 offset target from the current instruction, if and only if the
2840 result of the comparison is true.
2841
2842 Additionally this loop instruction may terminate JS execution is
2843 the JS timeout is reached.
2844 */
2845 JSValue src1 = callFrame->r(index: vPC[1].u.operand).jsValue();
2846 JSValue src2 = callFrame->r(index: vPC[2].u.operand).jsValue();
2847 int target = vPC[3].u.operand;
2848
2849 bool result = jsLessEq(callFrame, v1: src1, v2: src2);
2850 CHECK_FOR_EXCEPTION();
2851
2852 if (result) {
2853 vPC += target;
2854 CHECK_FOR_TIMEOUT();
2855 NEXT_INSTRUCTION();
2856 }
2857
2858 vPC += OPCODE_LENGTH(op_loop_if_lesseq);
2859 NEXT_INSTRUCTION();
2860 }
2861 DEFINE_OPCODE(op_jnless) {
2862 /* jnless src1(r) src2(r) target(offset)
2863
2864 Checks whether register src1 is less than register src2, as
2865 with the ECMAScript '<' operator, and then jumps to offset
2866 target from the current instruction, if and only if the
2867 result of the comparison is false.
2868 */
2869 JSValue src1 = callFrame->r(index: vPC[1].u.operand).jsValue();
2870 JSValue src2 = callFrame->r(index: vPC[2].u.operand).jsValue();
2871 int target = vPC[3].u.operand;
2872
2873 bool result = jsLess(callFrame, v1: src1, v2: src2);
2874 CHECK_FOR_EXCEPTION();
2875
2876 if (!result) {
2877 vPC += target;
2878 NEXT_INSTRUCTION();
2879 }
2880
2881 vPC += OPCODE_LENGTH(op_jnless);
2882 NEXT_INSTRUCTION();
2883 }
2884 DEFINE_OPCODE(op_jless) {
2885 /* jless src1(r) src2(r) target(offset)
2886
2887 Checks whether register src1 is less than register src2, as
2888 with the ECMAScript '<' operator, and then jumps to offset
2889 target from the current instruction, if and only if the
2890 result of the comparison is true.
2891 */
2892 JSValue src1 = callFrame->r(index: vPC[1].u.operand).jsValue();
2893 JSValue src2 = callFrame->r(index: vPC[2].u.operand).jsValue();
2894 int target = vPC[3].u.operand;
2895
2896 bool result = jsLess(callFrame, v1: src1, v2: src2);
2897 CHECK_FOR_EXCEPTION();
2898
2899 if (result) {
2900 vPC += target;
2901 NEXT_INSTRUCTION();
2902 }
2903
2904 vPC += OPCODE_LENGTH(op_jless);
2905 NEXT_INSTRUCTION();
2906 }
2907 DEFINE_OPCODE(op_jnlesseq) {
2908 /* jnlesseq src1(r) src2(r) target(offset)
2909
2910 Checks whether register src1 is less than or equal to
2911 register src2, as with the ECMAScript '<=' operator,
2912 and then jumps to offset target from the current instruction,
2913 if and only if theresult of the comparison is false.
2914 */
2915 JSValue src1 = callFrame->r(index: vPC[1].u.operand).jsValue();
2916 JSValue src2 = callFrame->r(index: vPC[2].u.operand).jsValue();
2917 int target = vPC[3].u.operand;
2918
2919 bool result = jsLessEq(callFrame, v1: src1, v2: src2);
2920 CHECK_FOR_EXCEPTION();
2921
2922 if (!result) {
2923 vPC += target;
2924 NEXT_INSTRUCTION();
2925 }
2926
2927 vPC += OPCODE_LENGTH(op_jnlesseq);
2928 NEXT_INSTRUCTION();
2929 }
2930 DEFINE_OPCODE(op_switch_imm) {
2931 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2932
2933 Performs a range checked switch on the scrutinee value, using
2934 the tableIndex-th immediate switch jump table. If the scrutinee value
2935 is an immediate number in the range covered by the referenced jump
2936 table, and the value at jumpTable[scrutinee value] is non-zero, then
2937 that value is used as the jump offset, otherwise defaultOffset is used.
2938 */
2939 int tableIndex = vPC[1].u.operand;
2940 int defaultOffset = vPC[2].u.operand;
2941 JSValue scrutinee = callFrame->r(index: vPC[3].u.operand).jsValue();
2942 if (scrutinee.isInt32())
2943 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(value: scrutinee.asInt32(), defaultOffset);
2944 else {
2945 double value;
2946 int32_t intValue;
2947 if (scrutinee.getNumber(result&: value) && ((intValue = static_cast<int32_t>(value)) == value))
2948 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(value: intValue, defaultOffset);
2949 else
2950 vPC += defaultOffset;
2951 }
2952 NEXT_INSTRUCTION();
2953 }
2954 DEFINE_OPCODE(op_switch_char) {
2955 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2956
2957 Performs a range checked switch on the scrutinee value, using
2958 the tableIndex-th character switch jump table. If the scrutinee value
2959 is a single character string in the range covered by the referenced jump
2960 table, and the value at jumpTable[scrutinee value] is non-zero, then
2961 that value is used as the jump offset, otherwise defaultOffset is used.
2962 */
2963 int tableIndex = vPC[1].u.operand;
2964 int defaultOffset = vPC[2].u.operand;
2965 JSValue scrutinee = callFrame->r(index: vPC[3].u.operand).jsValue();
2966 if (!scrutinee.isString())
2967 vPC += defaultOffset;
2968 else {
2969 UString::Rep* value = asString(value: scrutinee)->value(exec: callFrame).rep();
2970 if (value->size() != 1)
2971 vPC += defaultOffset;
2972 else
2973 vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value: value->data()[0], defaultOffset);
2974 }
2975 NEXT_INSTRUCTION();
2976 }
2977 DEFINE_OPCODE(op_switch_string) {
2978 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2979
2980 Performs a sparse hashmap based switch on the value in the scrutinee
2981 register, using the tableIndex-th string switch jump table. If the
2982 scrutinee value is a string that exists as a key in the referenced
2983 jump table, then the value associated with the string is used as the
2984 jump offset, otherwise defaultOffset is used.
2985 */
2986 int tableIndex = vPC[1].u.operand;
2987 int defaultOffset = vPC[2].u.operand;
2988 JSValue scrutinee = callFrame->r(index: vPC[3].u.operand).jsValue();
2989 if (!scrutinee.isString())
2990 vPC += defaultOffset;
2991 else
2992 vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(value: asString(value: scrutinee)->value(exec: callFrame).rep(), defaultOffset);
2993 NEXT_INSTRUCTION();
2994 }
2995 DEFINE_OPCODE(op_new_func) {
2996 /* new_func dst(r) func(f)
2997
2998 Constructs a new Function instance from function func and
2999 the current scope chain using the original Function
3000 constructor, using the rules for function declarations, and
3001 puts the result in register dst.
3002 */
3003 int dst = vPC[1].u.operand;
3004 int func = vPC[2].u.operand;
3005
3006 callFrame->r(index: dst) = JSValue(callFrame->codeBlock()->functionDecl(index: func)->make(exec: callFrame, scopeChain: callFrame->scopeChain()));
3007
3008 vPC += OPCODE_LENGTH(op_new_func);
3009 NEXT_INSTRUCTION();
3010 }
3011 DEFINE_OPCODE(op_new_func_exp) {
3012 /* new_func_exp dst(r) func(f)
3013
3014 Constructs a new Function instance from function func and
3015 the current scope chain using the original Function
3016 constructor, using the rules for function expressions, and
3017 puts the result in register dst.
3018 */
3019 int dst = vPC[1].u.operand;
3020 int funcIndex = vPC[2].u.operand;
3021
3022 FunctionExecutable* function = callFrame->codeBlock()->functionExpr(index: funcIndex);
3023 JSFunction* func = function->make(exec: callFrame, scopeChain: callFrame->scopeChain());
3024
3025 /*
3026 The Identifier in a FunctionExpression can be referenced from inside
3027 the FunctionExpression's FunctionBody to allow the function to call
3028 itself recursively. However, unlike in a FunctionDeclaration, the
3029 Identifier in a FunctionExpression cannot be referenced from and
3030 does not affect the scope enclosing the FunctionExpression.
3031 */
3032 if (!function->name().isNull()) {
3033 JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete);
3034 func->scope().push(o: functionScopeObject);
3035 }
3036
3037 callFrame->r(index: dst) = JSValue(func);
3038
3039 vPC += OPCODE_LENGTH(op_new_func_exp);
3040 NEXT_INSTRUCTION();
3041 }
3042 DEFINE_OPCODE(op_call_eval) {
3043 /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
3044
3045 Call a function named "eval" with no explicit "this" value
3046 (which may therefore be the eval operator). If register
3047 thisVal is the global object, and register func contains
3048 that global object's original global eval function, then
3049 perform the eval operator in local scope (interpreting
3050 the argument registers as for the "call"
3051 opcode). Otherwise, act exactly as the "call" opcode would.
3052 */
3053
3054 int dst = vPC[1].u.operand;
3055 int func = vPC[2].u.operand;
3056 int argCount = vPC[3].u.operand;
3057 int registerOffset = vPC[4].u.operand;
3058
3059 JSValue funcVal = callFrame->r(index: func).jsValue();
3060
3061 Register* newCallFrame = callFrame->registers() + registerOffset;
3062 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
3063 JSValue thisValue = argv[0].jsValue();
3064 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject;
3065
3066 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
3067 JSValue result = callEval(callFrame, registerFile, argv, argc: argCount, registerOffset, exceptionValue);
3068 if (exceptionValue)
3069 goto vm_throw;
3070 callFrame->r(index: dst) = result;
3071
3072 vPC += OPCODE_LENGTH(op_call_eval);
3073 NEXT_INSTRUCTION();
3074 }
3075
3076 // We didn't find the blessed version of eval, so process this
3077 // instruction as a normal function call.
3078 // fall through to op_call
3079 }
3080 DEFINE_OPCODE(op_call) {
3081 /* call dst(r) func(r) argCount(n) registerOffset(n)
3082
3083 Perform a function call.
3084
3085 registerOffset is the distance the callFrame pointer should move
3086 before the VM initializes the new call frame's header.
3087
3088 dst is where op_ret should store its result.
3089 */
3090
3091 int dst = vPC[1].u.operand;
3092 int func = vPC[2].u.operand;
3093 int argCount = vPC[3].u.operand;
3094 int registerOffset = vPC[4].u.operand;
3095
3096 JSValue v = callFrame->r(index: func).jsValue();
3097
3098 CallData callData;
3099 CallType callType = v.getCallData(callData);
3100
3101 if (callType == CallTypeJS) {
3102 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3103 CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(exec: callFrame, scopeChainNode: callDataScopeChain);
3104
3105 CallFrame* previousCallFrame = callFrame;
3106
3107 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argc: argCount);
3108 if (UNLIKELY(!callFrame)) {
3109 callFrame = previousCallFrame;
3110 exceptionValue = createStackOverflowError(callFrame);
3111 goto vm_throw;
3112 }
3113
3114 callFrame->init(codeBlock: newCodeBlock, vPC: vPC + 5, scopeChain: callDataScopeChain, callerFrame: previousCallFrame, returnValueRegister: dst, argc: argCount, callee: asFunction(value: v));
3115 vPC = newCodeBlock->instructions().begin();
3116
3117#if ENABLE(OPCODE_STATS)
3118 OpcodeStats::resetLastInstruction();
3119#endif
3120
3121 NEXT_INSTRUCTION();
3122 }
3123
3124 if (callType == CallTypeHost) {
3125 ScopeChainNode* scopeChain = callFrame->scopeChain();
3126 CallFrame* newCallFrame = CallFrame::create(callFrameBase: callFrame->registers() + registerOffset);
3127#ifdef QT_BUILD_SCRIPT_LIB //we need the returnValue to be 0 as it is used as flags
3128 newCallFrame->init(codeBlock: 0, vPC: vPC + 5, scopeChain, callerFrame: callFrame, returnValueRegister: 0, argc: argCount, callee: asObject(value: v));
3129#else
3130 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, asObject(v));
3131#endif
3132 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
3133 ArgList args(thisRegister + 1, argCount - 1);
3134
3135 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3136 JSValue thisValue = thisRegister->jsValue();
3137 if (thisValue == jsNull())
3138 thisValue = callFrame->globalThisValue();
3139
3140 JSValue returnValue;
3141 {
3142 SamplingTool::HostCallRecord callRecord(m_sampler.get());
3143 returnValue = callData.native.function(newCallFrame, asObject(value: v), thisValue, args);
3144 }
3145 CHECK_FOR_EXCEPTION();
3146
3147 callFrame->r(index: dst) = returnValue;
3148
3149 vPC += OPCODE_LENGTH(op_call);
3150 NEXT_INSTRUCTION();
3151 }
3152
3153 ASSERT(callType == CallTypeNone);
3154
3155 exceptionValue = createNotAFunctionError(callFrame, v, bytecodeOffset: vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3156 goto vm_throw;
3157 }
3158 DEFINE_OPCODE(op_load_varargs) {
3159 int argCountDst = vPC[1].u.operand;
3160 int argsOffset = vPC[2].u.operand;
3161
3162 JSValue arguments = callFrame->r(index: argsOffset).jsValue();
3163 int32_t argCount = 0;
3164 if (!arguments) {
3165 argCount = (uint32_t)(callFrame->argumentCount()) - 1;
3166 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3167 Register* newEnd = callFrame->registers() + sizeDelta;
3168 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3169 exceptionValue = createStackOverflowError(callFrame);
3170 goto vm_throw;
3171 }
3172 ASSERT(!asFunction(callFrame->callee())->isHostFunction());
3173 int32_t expectedParams = static_cast<JSFunction*>(callFrame->callee())->jsExecutable()->parameterCount();
3174 int32_t inplaceArgs = min(a: argCount, b: expectedParams);
3175 int32_t i = 0;
3176 Register* argStore = callFrame->registers() + argsOffset;
3177
3178 // First step is to copy the "expected" parameters from their normal location relative to the callframe
3179 for (; i < inplaceArgs; i++)
3180 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
3181 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
3182 for (; i < argCount; i++)
3183 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - argCount - 1];
3184 } else if (!arguments.isUndefinedOrNull()) {
3185 if (!arguments.isObject()) {
3186 exceptionValue = createInvalidParamError(callFrame, op: "Function.prototype.apply", arguments, bytecodeOffset: vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3187 goto vm_throw;
3188 }
3189 if (asObject(value: arguments)->classInfo() == &Arguments::info) {
3190 Arguments* args = asArguments(value: arguments);
3191 argCount = args->numProvidedArguments(exec: callFrame);
3192 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3193 Register* newEnd = callFrame->registers() + sizeDelta;
3194 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3195 exceptionValue = createStackOverflowError(callFrame);
3196 goto vm_throw;
3197 }
3198 args->copyToRegisters(exec: callFrame, buffer: callFrame->registers() + argsOffset, maxSize: argCount);
3199 } else if (isJSArray(globalData: &callFrame->globalData(), v: arguments)) {
3200 JSArray* array = asArray(value: arguments);
3201 argCount = array->length();
3202 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3203 Register* newEnd = callFrame->registers() + sizeDelta;
3204 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3205 exceptionValue = createStackOverflowError(callFrame);
3206 goto vm_throw;
3207 }
3208 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
3209 } else if (asObject(value: arguments)->inherits(info: &JSArray::info)) {
3210 JSObject* argObject = asObject(value: arguments);
3211 argCount = argObject->get(exec: callFrame, propertyName: callFrame->propertyNames().length).toUInt32(exec: callFrame);
3212 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3213 Register* newEnd = callFrame->registers() + sizeDelta;
3214 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3215 exceptionValue = createStackOverflowError(callFrame);
3216 goto vm_throw;
3217 }
3218 Register* argsBuffer = callFrame->registers() + argsOffset;
3219 for (int32_t i = 0; i < argCount; ++i) {
3220 argsBuffer[i] = asObject(value: arguments)->get(exec: callFrame, propertyName: i);
3221 CHECK_FOR_EXCEPTION();
3222 }
3223 } else {
3224 if (!arguments.isObject()) {
3225 exceptionValue = createInvalidParamError(callFrame, op: "Function.prototype.apply", arguments, bytecodeOffset: vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3226 goto vm_throw;
3227 }
3228 }
3229 }
3230 CHECK_FOR_EXCEPTION();
3231 callFrame->r(index: argCountDst) = Register::withInt(i: argCount + 1);
3232 vPC += OPCODE_LENGTH(op_load_varargs);
3233 NEXT_INSTRUCTION();
3234 }
3235 DEFINE_OPCODE(op_call_varargs) {
3236 /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
3237
3238 Perform a function call with a dynamic set of arguments.
3239
3240 registerOffset is the distance the callFrame pointer should move
3241 before the VM initializes the new call frame's header, excluding
3242 space for arguments.
3243
3244 dst is where op_ret should store its result.
3245 */
3246
3247 int dst = vPC[1].u.operand;
3248 int func = vPC[2].u.operand;
3249 int argCountReg = vPC[3].u.operand;
3250 int registerOffset = vPC[4].u.operand;
3251
3252 JSValue v = callFrame->r(index: func).jsValue();
3253 int argCount = callFrame->r(index: argCountReg).i();
3254 registerOffset += argCount;
3255 CallData callData;
3256 CallType callType = v.getCallData(callData);
3257
3258 if (callType == CallTypeJS) {
3259 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3260 CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(exec: callFrame, scopeChainNode: callDataScopeChain);
3261
3262 CallFrame* previousCallFrame = callFrame;
3263
3264 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argc: argCount);
3265 if (UNLIKELY(!callFrame)) {
3266 callFrame = previousCallFrame;
3267 exceptionValue = createStackOverflowError(callFrame);
3268 goto vm_throw;
3269 }
3270
3271 callFrame->init(codeBlock: newCodeBlock, vPC: vPC + 5, scopeChain: callDataScopeChain, callerFrame: previousCallFrame, returnValueRegister: dst, argc: argCount, callee: asFunction(value: v));
3272 vPC = newCodeBlock->instructions().begin();
3273
3274#if ENABLE(OPCODE_STATS)
3275 OpcodeStats::resetLastInstruction();
3276#endif
3277
3278 NEXT_INSTRUCTION();
3279 }
3280
3281 if (callType == CallTypeHost) {
3282 ScopeChainNode* scopeChain = callFrame->scopeChain();
3283 CallFrame* newCallFrame = CallFrame::create(callFrameBase: callFrame->registers() + registerOffset);
3284#ifdef QT_BUILD_SCRIPT_LIB //we need the returnValue to be 0 as it is used as flags
3285 newCallFrame->init(codeBlock: 0, vPC: vPC + 5, scopeChain, callerFrame: callFrame, returnValueRegister: 0, argc: argCount, callee: asObject(value: v));
3286#else
3287 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, asObject(v));
3288#endif
3289
3290 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
3291 ArgList args(thisRegister + 1, argCount - 1);
3292
3293 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3294 JSValue thisValue = thisRegister->jsValue();
3295 if (thisValue == jsNull())
3296 thisValue = callFrame->globalThisValue();
3297
3298 JSValue returnValue;
3299 {
3300 SamplingTool::HostCallRecord callRecord(m_sampler.get());
3301 returnValue = callData.native.function(newCallFrame, asObject(value: v), thisValue, args);
3302 }
3303 CHECK_FOR_EXCEPTION();
3304
3305 callFrame->r(index: dst) = returnValue;
3306
3307 vPC += OPCODE_LENGTH(op_call_varargs);
3308 NEXT_INSTRUCTION();
3309 }
3310
3311 ASSERT(callType == CallTypeNone);
3312
3313 exceptionValue = createNotAFunctionError(callFrame, v, bytecodeOffset: vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3314 goto vm_throw;
3315 }
3316 DEFINE_OPCODE(op_tear_off_activation) {
3317 /* tear_off_activation activation(r)
3318
3319 Copy all locals and parameters to new memory allocated on
3320 the heap, and make the passed activation use this memory
3321 in the future when looking up entries in the symbol table.
3322 If there is an 'arguments' object, then it will also use
3323 this memory for storing the named parameters, but not any
3324 extra arguments.
3325
3326 This opcode should only be used immediately before op_ret.
3327 */
3328
3329 int src = vPC[1].u.operand;
3330 ASSERT(callFrame->codeBlock()->needsFullScopeChain());
3331
3332 asActivation(value: callFrame->r(index: src).jsValue())->copyRegisters(arguments: callFrame->optionalCalleeArguments());
3333
3334 vPC += OPCODE_LENGTH(op_tear_off_activation);
3335 NEXT_INSTRUCTION();
3336 }
3337 DEFINE_OPCODE(op_tear_off_arguments) {
3338 /* tear_off_arguments
3339
3340 Copy all arguments to new memory allocated on the heap,
3341 and make the 'arguments' object use this memory in the
3342 future when looking up named parameters, but not any
3343 extra arguments. If an activation object exists for the
3344 current function context, then the tear_off_activation
3345 opcode should be used instead.
3346
3347 This opcode should only be used immediately before op_ret.
3348 */
3349
3350 ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());
3351
3352 if (callFrame->optionalCalleeArguments())
3353 callFrame->optionalCalleeArguments()->copyRegisters();
3354
3355 vPC += OPCODE_LENGTH(op_tear_off_arguments);
3356 NEXT_INSTRUCTION();
3357 }
3358 DEFINE_OPCODE(op_ret) {
3359 /* ret result(r)
3360
3361 Return register result as the return value of the current
3362 function call, writing it into the caller's expected return
3363 value register. In addition, unwind one call frame and
3364 restore the scope chain, code block instruction pointer and
3365 register base to those of the calling function.
3366 */
3367
3368#ifdef QT_BUILD_SCRIPT_LIB
3369 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
3370 intptr_t sourceId = callFrame->codeBlock()->source()->asID();
3371#endif
3372
3373 int result = vPC[1].u.operand;
3374
3375 if (callFrame->codeBlock()->needsFullScopeChain())
3376 callFrame->scopeChain()->deref();
3377
3378 JSValue returnValue = callFrame->r(index: result).jsValue();
3379#ifdef QT_BUILD_SCRIPT_LIB
3380 if (debugger)
3381 debugger->functionExit(returnValue, sourceID: sourceId);
3382#endif
3383
3384 vPC = callFrame->returnPC();
3385 int dst = callFrame->returnValueRegister();
3386 callFrame = callFrame->callerFrame();
3387
3388 if (callFrame->hasHostCallFrameFlag())
3389 return returnValue;
3390
3391 callFrame->r(index: dst) = returnValue;
3392
3393 NEXT_INSTRUCTION();
3394 }
3395 DEFINE_OPCODE(op_enter) {
3396 /* enter
3397
3398 Initializes local variables to undefined and fills constant
3399 registers with their values. If the code block requires an
3400 activation, enter_with_activation should be used instead.
3401
3402 This opcode should only be used at the beginning of a code
3403 block.
3404 */
3405
3406 size_t i = 0;
3407 CodeBlock* codeBlock = callFrame->codeBlock();
3408
3409 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3410 callFrame->r(index: i) = jsUndefined();
3411
3412 vPC += OPCODE_LENGTH(op_enter);
3413 NEXT_INSTRUCTION();
3414 }
3415 DEFINE_OPCODE(op_enter_with_activation) {
3416 /* enter_with_activation dst(r)
3417
3418 Initializes local variables to undefined, fills constant
3419 registers with their values, creates an activation object,
3420 and places the new activation both in dst and at the top
3421 of the scope chain. If the code block does not require an
3422 activation, enter should be used instead.
3423
3424 This opcode should only be used at the beginning of a code
3425 block.
3426 */
3427
3428 size_t i = 0;
3429 CodeBlock* codeBlock = callFrame->codeBlock();
3430
3431 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3432 callFrame->r(index: i) = jsUndefined();
3433
3434 int dst = vPC[1].u.operand;
3435 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable()));
3436 callFrame->r(index: dst) = JSValue(activation);
3437 callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(o: activation));
3438
3439 vPC += OPCODE_LENGTH(op_enter_with_activation);
3440 NEXT_INSTRUCTION();
3441 }
3442 DEFINE_OPCODE(op_convert_this) {
3443 /* convert_this this(r)
3444
3445 Takes the value in the 'this' register, converts it to a
3446 value that is suitable for use as the 'this' value, and
3447 stores it in the 'this' register. This opcode is emitted
3448 to avoid doing the conversion in the caller unnecessarily.
3449
3450 This opcode should only be used at the beginning of a code
3451 block.
3452 */
3453
3454 int thisRegister = vPC[1].u.operand;
3455 JSValue thisVal = callFrame->r(index: thisRegister).jsValue();
3456 if (thisVal.needsThisConversion())
3457 callFrame->r(index: thisRegister) = JSValue(thisVal.toThisObject(exec: callFrame));
3458
3459 vPC += OPCODE_LENGTH(op_convert_this);
3460 NEXT_INSTRUCTION();
3461 }
3462 DEFINE_OPCODE(op_init_arguments) {
3463 /* create_arguments
3464
3465 Initialises the arguments object reference to null to ensure
3466 we can correctly detect that we need to create it later (or
3467 avoid creating it altogether).
3468
3469 This opcode should only be used at the beginning of a code
3470 block.
3471 */
3472 callFrame->r(index: RegisterFile::ArgumentsRegister) = JSValue();
3473 vPC += OPCODE_LENGTH(op_init_arguments);
3474 NEXT_INSTRUCTION();
3475 }
3476 DEFINE_OPCODE(op_create_arguments) {
3477 /* create_arguments
3478
3479 Creates the 'arguments' object and places it in both the
3480 'arguments' call frame slot and the local 'arguments'
3481 register, if it has not already been initialised.
3482 */
3483
3484 if (!callFrame->r(index: RegisterFile::ArgumentsRegister).jsValue()) {
3485 Arguments* arguments = new (globalData) Arguments(callFrame);
3486 callFrame->setCalleeArguments(arguments);
3487 callFrame->r(index: RegisterFile::ArgumentsRegister) = JSValue(arguments);
3488 }
3489 vPC += OPCODE_LENGTH(op_create_arguments);
3490 NEXT_INSTRUCTION();
3491 }
3492 DEFINE_OPCODE(op_construct) {
3493 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
3494
3495 Invoke register "func" as a constructor. For JS
3496 functions, the calling convention is exactly as for the
3497 "call" opcode, except that the "this" value is a newly
3498 created Object. For native constructors, no "this"
3499 value is passed. In either case, the argCount and registerOffset
3500 registers are interpreted as for the "call" opcode.
3501
3502 Register proto must contain the prototype property of
3503 register func. This is to enable polymorphic inline
3504 caching of this lookup.
3505 */
3506
3507 int dst = vPC[1].u.operand;
3508 int func = vPC[2].u.operand;
3509 int argCount = vPC[3].u.operand;
3510 int registerOffset = vPC[4].u.operand;
3511 int proto = vPC[5].u.operand;
3512 int thisRegister = vPC[6].u.operand;
3513
3514 JSValue v = callFrame->r(index: func).jsValue();
3515
3516 ConstructData constructData;
3517 ConstructType constructType = v.getConstructData(constructData);
3518
3519 if (constructType == ConstructTypeJS) {
3520 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3521 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->bytecode(exec: callFrame, scopeChainNode: callDataScopeChain);
3522
3523 Structure* structure;
3524 JSValue prototype = callFrame->r(index: proto).jsValue();
3525 if (prototype.isObject())
3526 structure = asObject(value: prototype)->inheritorID();
3527 else
3528 structure = callDataScopeChain->globalObject->emptyObjectStructure();
3529#ifdef QT_BUILD_SCRIPT_LIB
3530 // ### world-class hack
3531 QT_PREPEND_NAMESPACE(QScriptObject)* newObject = new (globalData) QT_PREPEND_NAMESPACE(QScriptObject)(structure);
3532#else
3533 JSObject* newObject = new (globalData) JSObject(structure);
3534#endif
3535 callFrame->r(index: thisRegister) = JSValue(newObject); // "this" value
3536
3537 CallFrame* previousCallFrame = callFrame;
3538
3539 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argc: argCount);
3540 if (UNLIKELY(!callFrame)) {
3541 callFrame = previousCallFrame;
3542 exceptionValue = createStackOverflowError(callFrame);
3543 goto vm_throw;
3544 }
3545
3546 callFrame->init(codeBlock: newCodeBlock, vPC: vPC + 7, scopeChain: callDataScopeChain, callerFrame: previousCallFrame, returnValueRegister: dst, argc: argCount, callee: asFunction(value: v));
3547 vPC = newCodeBlock->instructions().begin();
3548
3549#if ENABLE(OPCODE_STATS)
3550 OpcodeStats::resetLastInstruction();
3551#endif
3552
3553 NEXT_INSTRUCTION();
3554 }
3555
3556 if (constructType == ConstructTypeHost) {
3557 ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1);
3558
3559 ScopeChainNode* scopeChain = callFrame->scopeChain();
3560 CallFrame* newCallFrame = CallFrame::create(callFrameBase: callFrame->registers() + registerOffset);
3561#ifdef QT_BUILD_SCRIPT_LIB //we need the returnValue to be 0 as it is used as flags
3562 newCallFrame->init(codeBlock: 0, vPC: vPC + 7, scopeChain, callerFrame: callFrame, returnValueRegister: 0, argc: argCount, callee: asObject(value: v));
3563#else
3564 newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, asObject(v));
3565#endif
3566
3567 JSValue returnValue;
3568 {
3569 SamplingTool::HostCallRecord callRecord(m_sampler.get());
3570 returnValue = constructData.native.function(newCallFrame, asObject(value: v), args);
3571 }
3572 CHECK_FOR_EXCEPTION();
3573 callFrame->r(index: dst) = JSValue(returnValue);
3574
3575 vPC += OPCODE_LENGTH(op_construct);
3576 NEXT_INSTRUCTION();
3577 }
3578
3579 ASSERT(constructType == ConstructTypeNone);
3580
3581 exceptionValue = createNotAConstructorError(callFrame, v, bytecodeOffset: vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3582 goto vm_throw;
3583 }
3584 DEFINE_OPCODE(op_construct_verify) {
3585 /* construct_verify dst(r) override(r)
3586
3587 Verifies that register dst holds an object. If not, moves
3588 the object in register override to register dst.
3589 */
3590
3591 int dst = vPC[1].u.operand;
3592 if (LIKELY(callFrame->r(dst).jsValue().isObject())) {
3593 vPC += OPCODE_LENGTH(op_construct_verify);
3594 NEXT_INSTRUCTION();
3595 }
3596
3597 int override = vPC[2].u.operand;
3598 callFrame->r(index: dst) = callFrame->r(index: override);
3599
3600 vPC += OPCODE_LENGTH(op_construct_verify);
3601 NEXT_INSTRUCTION();
3602 }
3603 DEFINE_OPCODE(op_strcat) {
3604 int dst = vPC[1].u.operand;
3605 int src = vPC[2].u.operand;
3606 int count = vPC[3].u.operand;
3607
3608 callFrame->r(index: dst) = jsString(exec: callFrame, strings: &callFrame->registers()[src], count);
3609 CHECK_FOR_EXCEPTION();
3610 vPC += OPCODE_LENGTH(op_strcat);
3611
3612 NEXT_INSTRUCTION();
3613 }
3614 DEFINE_OPCODE(op_to_primitive) {
3615 int dst = vPC[1].u.operand;
3616 int src = vPC[2].u.operand;
3617
3618 callFrame->r(index: dst) = callFrame->r(index: src).jsValue().toPrimitive(exec: callFrame);
3619 vPC += OPCODE_LENGTH(op_to_primitive);
3620
3621 NEXT_INSTRUCTION();
3622 }
3623 DEFINE_OPCODE(op_push_scope) {
3624 /* push_scope scope(r)
3625
3626 Converts register scope to object, and pushes it onto the top
3627 of the current scope chain. The contents of the register scope
3628 are replaced by the result of toObject conversion of the scope.
3629 */
3630 int scope = vPC[1].u.operand;
3631 JSValue v = callFrame->r(index: scope).jsValue();
3632 JSObject* o = v.toObject(exec: callFrame);
3633 CHECK_FOR_EXCEPTION();
3634
3635 callFrame->r(index: scope) = JSValue(o);
3636 callFrame->setScopeChain(callFrame->scopeChain()->push(o));
3637
3638 vPC += OPCODE_LENGTH(op_push_scope);
3639 NEXT_INSTRUCTION();
3640 }
3641 DEFINE_OPCODE(op_pop_scope) {
3642 /* pop_scope
3643
3644 Removes the top item from the current scope chain.
3645 */
3646 callFrame->setScopeChain(callFrame->scopeChain()->pop());
3647
3648 vPC += OPCODE_LENGTH(op_pop_scope);
3649 NEXT_INSTRUCTION();
3650 }
3651 DEFINE_OPCODE(op_get_pnames) {
3652 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
3653
3654 Creates a property name list for register base and puts it
3655 in register dst, initializing i and size for iteration. If
3656 base is undefined or null, jumps to breakTarget.
3657 */
3658 int dst = vPC[1].u.operand;
3659 int base = vPC[2].u.operand;
3660 int i = vPC[3].u.operand;
3661 int size = vPC[4].u.operand;
3662 int breakTarget = vPC[5].u.operand;
3663
3664 JSValue v = callFrame->r(index: base).jsValue();
3665 if (v.isUndefinedOrNull()) {
3666 vPC += breakTarget;
3667 NEXT_INSTRUCTION();
3668 }
3669
3670 JSObject* o = v.toObject(exec: callFrame);
3671 Structure* structure = o->structure();
3672 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
3673 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(exec: callFrame))
3674 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
3675
3676 callFrame->r(index: dst) = jsPropertyNameIterator;
3677 callFrame->r(index: base) = JSValue(o);
3678 callFrame->r(index: i) = Register::withInt(i: 0);
3679 callFrame->r(index: size) = Register::withInt(i: jsPropertyNameIterator->size());
3680 vPC += OPCODE_LENGTH(op_get_pnames);
3681 NEXT_INSTRUCTION();
3682 }
3683 DEFINE_OPCODE(op_next_pname) {
3684 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
3685
3686 Copies the next name from the property name list in
3687 register iter to dst, then jumps to offset target. If there are no
3688 names left, invalidates the iterator and continues to the next
3689 instruction.
3690 */
3691 int dst = vPC[1].u.operand;
3692 int base = vPC[2].u.operand;
3693 int i = vPC[3].u.operand;
3694 int size = vPC[4].u.operand;
3695 int iter = vPC[5].u.operand;
3696 int target = vPC[6].u.operand;
3697
3698 JSPropertyNameIterator* it = callFrame->r(index: iter).propertyNameIterator();
3699 while (callFrame->r(index: i).i() != callFrame->r(index: size).i()) {
3700 JSValue key = it->get(callFrame, asObject(value: callFrame->r(index: base).jsValue()), i: callFrame->r(index: i).i());
3701 callFrame->r(index: i) = Register::withInt(i: callFrame->r(index: i).i() + 1);
3702 if (key) {
3703 CHECK_FOR_TIMEOUT();
3704 callFrame->r(index: dst) = key;
3705 vPC += target;
3706 NEXT_INSTRUCTION();
3707 }
3708 }
3709
3710 vPC += OPCODE_LENGTH(op_next_pname);
3711 NEXT_INSTRUCTION();
3712 }
3713 DEFINE_OPCODE(op_jmp_scopes) {
3714 /* jmp_scopes count(n) target(offset)
3715
3716 Removes the a number of items from the current scope chain
3717 specified by immediate number count, then jumps to offset
3718 target.
3719 */
3720 int count = vPC[1].u.operand;
3721 int target = vPC[2].u.operand;
3722
3723 ScopeChainNode* tmp = callFrame->scopeChain();
3724 while (count--)
3725 tmp = tmp->pop();
3726 callFrame->setScopeChain(tmp);
3727
3728 vPC += target;
3729 NEXT_INSTRUCTION();
3730 }
3731#if HAVE(COMPUTED_GOTO)
3732 // Appease GCC
3733 goto *(&&skip_new_scope);
3734#endif
3735 DEFINE_OPCODE(op_push_new_scope) {
3736 /* new_scope dst(r) property(id) value(r)
3737
3738 Constructs a new StaticScopeObject with property set to value. That scope
3739 object is then pushed onto the ScopeChain. The scope object is then stored
3740 in dst for GC.
3741 */
3742 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));
3743
3744 vPC += OPCODE_LENGTH(op_push_new_scope);
3745 NEXT_INSTRUCTION();
3746 }
3747#if HAVE(COMPUTED_GOTO)
3748 skip_new_scope:
3749#endif
3750 DEFINE_OPCODE(op_catch) {
3751 /* catch ex(r)
3752
3753 Retrieves the VM's current exception and puts it in register
3754 ex. This is only valid after an exception has been raised,
3755 and usually forms the beginning of an exception handler.
3756 */
3757 ASSERT(exceptionValue);
3758 ASSERT(!globalData->exception);
3759
3760#ifdef QT_BUILD_SCRIPT_LIB
3761 CodeBlock* codeBlock = callFrame->codeBlock();
3762 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
3763 if (debugger) {
3764 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
3765 debugger->exceptionCatch(frame: debuggerCallFrame, sourceID: codeBlock->ownerExecutable()->sourceID());
3766 }
3767#endif
3768
3769 int ex = vPC[1].u.operand;
3770 callFrame->r(index: ex) = exceptionValue;
3771 exceptionValue = JSValue();
3772
3773 vPC += OPCODE_LENGTH(op_catch);
3774 NEXT_INSTRUCTION();
3775 }
3776 DEFINE_OPCODE(op_throw) {
3777 /* throw ex(r)
3778
3779 Throws register ex as an exception. This involves three
3780 steps: first, it is set as the current exception in the
3781 VM's internal state, then the stack is unwound until an
3782 exception handler or a native code boundary is found, and
3783 then control resumes at the exception handler if any or
3784 else the script returns control to the nearest native caller.
3785 */
3786
3787 int ex = vPC[1].u.operand;
3788 exceptionValue = callFrame->r(index: ex).jsValue();
3789
3790 handler = throwException(callFrame, exceptionValue, bytecodeOffset: vPC - callFrame->codeBlock()->instructions().begin(), explicitThrow: true);
3791 if (!handler) {
3792 *exception = exceptionValue;
3793 return jsNull();
3794 }
3795
3796 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
3797 NEXT_INSTRUCTION();
3798 }
3799 DEFINE_OPCODE(op_new_error) {
3800 /* new_error dst(r) type(n) message(k)
3801
3802 Constructs a new Error instance using the original
3803 constructor, using immediate number n as the type and
3804 constant message as the message string. The result is
3805 written to register dst.
3806 */
3807 int dst = vPC[1].u.operand;
3808 int type = vPC[2].u.operand;
3809 int message = vPC[3].u.operand;
3810
3811 CodeBlock* codeBlock = callFrame->codeBlock();
3812 callFrame->r(index: dst) = JSValue(Error::create(callFrame, (ErrorType)type, message: callFrame->r(index: message).jsValue().toString(exec: callFrame), lineNumber: codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset: vPC - codeBlock->instructions().begin()), sourceID: codeBlock->ownerExecutable()->sourceID(), sourceURL: codeBlock->ownerExecutable()->sourceURL()));
3813
3814 vPC += OPCODE_LENGTH(op_new_error);
3815 NEXT_INSTRUCTION();
3816 }
3817 DEFINE_OPCODE(op_end) {
3818 /* end result(r)
3819
3820 Return register result as the value of a global or eval
3821 program. Return control to the calling native code.
3822 */
3823
3824 if (callFrame->codeBlock()->needsFullScopeChain()) {
3825 ScopeChainNode* scopeChain = callFrame->scopeChain();
3826 ASSERT(scopeChain->refCount > 1);
3827 scopeChain->deref();
3828 }
3829 int result = vPC[1].u.operand;
3830 return callFrame->r(index: result).jsValue();
3831 }
3832 DEFINE_OPCODE(op_put_getter) {
3833 /* put_getter base(r) property(id) function(r)
3834
3835 Sets register function on register base as the getter named
3836 by identifier property. Base and function are assumed to be
3837 objects as this op should only be used for getters defined
3838 in object literal form.
3839
3840 Unlike many opcodes, this one does not write any output to
3841 the register file.
3842 */
3843 int base = vPC[1].u.operand;
3844 int property = vPC[2].u.operand;
3845 int function = vPC[3].u.operand;
3846
3847 ASSERT(callFrame->r(base).jsValue().isObject());
3848 JSObject* baseObj = asObject(value: callFrame->r(index: base).jsValue());
3849 Identifier& ident = callFrame->codeBlock()->identifier(index: property);
3850 ASSERT(callFrame->r(function).jsValue().isObject());
3851 baseObj->defineGetter(callFrame, propertyName: ident, getterFunction: asObject(value: callFrame->r(index: function).jsValue()));
3852
3853 vPC += OPCODE_LENGTH(op_put_getter);
3854 NEXT_INSTRUCTION();
3855 }
3856 DEFINE_OPCODE(op_put_setter) {
3857 /* put_setter base(r) property(id) function(r)
3858
3859 Sets register function on register base as the setter named
3860 by identifier property. Base and function are assumed to be
3861 objects as this op should only be used for setters defined
3862 in object literal form.
3863
3864 Unlike many opcodes, this one does not write any output to
3865 the register file.
3866 */
3867 int base = vPC[1].u.operand;
3868 int property = vPC[2].u.operand;
3869 int function = vPC[3].u.operand;
3870
3871 ASSERT(callFrame->r(base).jsValue().isObject());
3872 JSObject* baseObj = asObject(value: callFrame->r(index: base).jsValue());
3873 Identifier& ident = callFrame->codeBlock()->identifier(index: property);
3874 ASSERT(callFrame->r(function).jsValue().isObject());
3875 baseObj->defineSetter(callFrame, propertyName: ident, setterFunction: asObject(value: callFrame->r(index: function).jsValue()), attributes: 0);
3876
3877 vPC += OPCODE_LENGTH(op_put_setter);
3878 NEXT_INSTRUCTION();
3879 }
3880 DEFINE_OPCODE(op_method_check) {
3881 vPC++;
3882 NEXT_INSTRUCTION();
3883 }
3884 DEFINE_OPCODE(op_jsr) {
3885 /* jsr retAddrDst(r) target(offset)
3886
3887 Places the address of the next instruction into the retAddrDst
3888 register and jumps to offset target from the current instruction.
3889 */
3890 int retAddrDst = vPC[1].u.operand;
3891 int target = vPC[2].u.operand;
3892 callFrame->r(index: retAddrDst) = vPC + OPCODE_LENGTH(op_jsr);
3893
3894 vPC += target;
3895 NEXT_INSTRUCTION();
3896 }
3897 DEFINE_OPCODE(op_sret) {
3898 /* sret retAddrSrc(r)
3899
3900 Jumps to the address stored in the retAddrSrc register. This
3901 differs from op_jmp because the target address is stored in a
3902 register, not as an immediate.
3903 */
3904 int retAddrSrc = vPC[1].u.operand;
3905 vPC = callFrame->r(index: retAddrSrc).vPC();
3906 NEXT_INSTRUCTION();
3907 }
3908 DEFINE_OPCODE(op_debug) {
3909 /* debug debugHookID(n) firstLine(n) lastLine(n)
3910
3911 Notifies the debugger of the current state of execution. This opcode
3912 is only generated while the debugger is attached.
3913 */
3914 int debugHookID = vPC[1].u.operand;
3915 int firstLine = vPC[2].u.operand;
3916 int lastLine = vPC[3].u.operand;
3917
3918 debug(callFrame, debugHookID: static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3919
3920 vPC += OPCODE_LENGTH(op_debug);
3921 NEXT_INSTRUCTION();
3922 }
3923 DEFINE_OPCODE(op_profile_will_call) {
3924 /* op_profile_will_call function(r)
3925
3926 Notifies the profiler of the beginning of a function call. This opcode
3927 is only generated if developer tools are enabled.
3928 */
3929 int function = vPC[1].u.operand;
3930
3931 if (*enabledProfilerReference)
3932 (*enabledProfilerReference)->willExecute(callFrame, function: callFrame->r(index: function).jsValue());
3933
3934 vPC += OPCODE_LENGTH(op_profile_will_call);
3935 NEXT_INSTRUCTION();
3936 }
3937 DEFINE_OPCODE(op_profile_did_call) {
3938 /* op_profile_did_call function(r)
3939
3940 Notifies the profiler of the end of a function call. This opcode
3941 is only generated if developer tools are enabled.
3942 */
3943 int function = vPC[1].u.operand;
3944
3945 if (*enabledProfilerReference)
3946 (*enabledProfilerReference)->didExecute(callFrame, function: callFrame->r(index: function).jsValue());
3947
3948 vPC += OPCODE_LENGTH(op_profile_did_call);
3949 NEXT_INSTRUCTION();
3950 }
3951 vm_throw: {
3952 globalData->exception = JSValue();
3953 if (!tickCount) {
3954 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3955 // cannot fathom if we don't assign to the exceptionValue before branching)
3956 exceptionValue = createInterruptedExecutionException(globalData);
3957 }
3958 handler = throwException(callFrame, exceptionValue, bytecodeOffset: vPC - callFrame->codeBlock()->instructions().begin(), explicitThrow: false);
3959 if (!handler) {
3960 *exception = exceptionValue;
3961 return jsNull();
3962 }
3963
3964 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
3965 NEXT_INSTRUCTION();
3966 }
3967 }
3968#if !HAVE(COMPUTED_GOTO)
3969 } // iterator loop ends
3970#endif
3971#endif // USE(INTERPRETER)
3972 #undef NEXT_INSTRUCTION
3973 #undef DEFINE_OPCODE
3974 #undef CHECK_FOR_EXCEPTION
3975 #undef CHECK_FOR_TIMEOUT
3976}
3977
3978JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
3979{
3980 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
3981 if (!functionCallFrame)
3982 return jsNull();
3983
3984 CodeBlock* codeBlock = functionCallFrame->codeBlock();
3985 if (codeBlock->usesArguments()) {
3986 ASSERT(codeBlock->codeType() == FunctionCode);
3987 SymbolTable& symbolTable = *codeBlock->symbolTable();
3988 int argumentsIndex = symbolTable.get(key: functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();
3989 if (!functionCallFrame->r(index: argumentsIndex).jsValue()) {
3990 Arguments* arguments = new (callFrame) Arguments(functionCallFrame);
3991 functionCallFrame->setCalleeArguments(arguments);
3992 functionCallFrame->r(index: RegisterFile::ArgumentsRegister) = JSValue(arguments);
3993 }
3994 return functionCallFrame->r(index: argumentsIndex).jsValue();
3995 }
3996
3997 Arguments* arguments = functionCallFrame->optionalCalleeArguments();
3998 if (!arguments) {
3999 arguments = new (functionCallFrame) Arguments(functionCallFrame);
4000 arguments->copyRegisters();
4001 callFrame->setCalleeArguments(arguments);
4002 }
4003
4004 return arguments;
4005}
4006
4007JSValue Interpreter::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const
4008{
4009 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
4010 if (!functionCallFrame)
4011 return jsNull();
4012
4013 CallFrame* callerFrame = functionCallFrame->callerFrame();
4014 if (callerFrame->hasHostCallFrameFlag())
4015 return jsNull();
4016
4017 JSValue caller = callerFrame->callee();
4018 if (!caller)
4019 return jsNull();
4020
4021 return caller;
4022}
4023
4024void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const
4025{
4026 function = JSValue();
4027 lineNumber = -1;
4028 sourceURL = UString();
4029
4030 CallFrame* callerFrame = callFrame->callerFrame();
4031 if (callerFrame->hasHostCallFrameFlag())
4032 return;
4033
4034 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
4035 if (!callerCodeBlock)
4036 return;
4037
4038 unsigned bytecodeOffset = bytecodeOffsetForPC(callFrame: callerFrame, codeBlock: callerCodeBlock, pc: callFrame->returnPC());
4039 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(callerFrame, bytecodeOffset: bytecodeOffset - 1);
4040 sourceID = callerCodeBlock->ownerExecutable()->sourceID();
4041 sourceURL = callerCodeBlock->ownerExecutable()->sourceURL();
4042 function = callerFrame->callee();
4043}
4044
4045CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunction* function)
4046{
4047 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
4048 if (candidate->callee() == function)
4049 return candidate;
4050 }
4051 return 0;
4052}
4053
4054void Interpreter::enableSampler()
4055{
4056#if ENABLE(OPCODE_SAMPLING)
4057 if (!m_sampler) {
4058 m_sampler.set(new SamplingTool(this));
4059 m_sampler->setup();
4060 }
4061#endif
4062}
4063void Interpreter::dumpSampleData(ExecState* exec)
4064{
4065#if ENABLE(OPCODE_SAMPLING)
4066 if (m_sampler)
4067 m_sampler->dump(exec);
4068#else
4069 UNUSED_PARAM(exec);
4070#endif
4071}
4072void Interpreter::startSampling()
4073{
4074#if ENABLE(SAMPLING_THREAD)
4075 if (!m_sampleEntryDepth)
4076 SamplingThread::start();
4077
4078 m_sampleEntryDepth++;
4079#endif
4080}
4081void Interpreter::stopSampling()
4082{
4083#if ENABLE(SAMPLING_THREAD)
4084 m_sampleEntryDepth--;
4085 if (!m_sampleEntryDepth)
4086 SamplingThread::stop();
4087#endif
4088}
4089
4090} // namespace JSC
4091

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/interpreter/Interpreter.cpp