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