source: webkit/trunk/JavaScriptCore/interpreter/Interpreter.cpp@ 61778

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

2010-06-21 Nathan Lawrence <[email protected]>

Reviewed by Geoff Garen.

https://bugs.webkit.org/show_bug.cgi?id=40128
Fixed broken debug functionality.

  • interpreter/Interpreter.cpp: (JSC::Interpreter::dumpRegisters):

Fixed to work with updated call frame.

  • runtime/JSImmediate.h: (JSC::JSValue::isCell):

Added assert for aligned cell.

  • runtime/JSValue.cpp: (JSC::JSValue::description):

Fixed to work with current JSValue implementation.

  • runtime/JSZombie.cpp: (JSC::JSZombie::leakedZombieStructure):

JSombies compile again.

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