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

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

Unreviewed build fix.

Interpreter fix following r59974.

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::privateExecute):

  • runtime/JSPropertyNameIterator.cpp:

(JSC::JSPropertyNameIterator::get):

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