Interpreter.cpp 147 KB
Newer Older
1
/*
2
 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
ggaren@apple.com's avatar
ggaren@apple.com committed
31
#include "Interpreter.h"
32

33
#include "Arguments.h"
ggaren@apple.com's avatar
ggaren@apple.com committed
34
#include "BatchedTransitionOptimizer.h"
35
#include "CallFrame.h"
36
#include "CallFrameClosure.h"
37
#include "CodeBlock.h"
38 39
#include "Collector.h"
#include "Debugger.h"
40
#include "DebuggerCallFrame.h"
41
#include "EvalCodeCache.h"
42
#include "ExceptionHelpers.h"
weinig@apple.com's avatar
weinig@apple.com committed
43
#include "GlobalEvalFunction.h"
44
#include "JSActivation.h"
45
#include "JSArray.h"
46
#include "JSByteArray.h"
47
#include "JSFunction.h"
48
#include "JSNotAnObject.h"
49
#include "JSPropertyNameIterator.h"
50
#include "LiteralParser.h"
51
#include "JSStaticScopeObject.h"
52
#include "JSString.h"
weinig@apple.com's avatar
weinig@apple.com committed
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 <stdio.h>
62
#include <wtf/Threading.h>
63

64
#if ENABLE(JIT)
ggaren@apple.com's avatar
ggaren@apple.com committed
65
#include "JIT.h"
66 67
#endif

68 69 70 71
#if ENABLE(ASSEMBLER)
#include "AssemblerBuffer.h"
#endif

ggaren@apple.com's avatar
ggaren@apple.com committed
72 73
using namespace std;

74
namespace JSC {
75

76
static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, void* pc)
77
{
78
#if ENABLE(JIT)
79
    return codeBlock->getBytecodeIndex(callFrame, ReturnAddressPtr(pc));
80
#else
81
    UNUSED_PARAM(callFrame);
82 83
    return static_cast<Instruction*>(pc) - codeBlock->instructions().begin();
#endif
84 85
}

86
// Returns the depth of the scope chain within a given call frame.
87
static int depth(CodeBlock* codeBlock, ScopeChain& sc)
88
{
89
    if (!codeBlock->needsFullScopeChain())
90
        return 0;
91
    return sc.localDepth();
92
}
93

94
#if USE(INTERPRETER)
ggaren@apple.com's avatar
ggaren@apple.com committed
95
NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
96 97 98 99
{
    int dst = (vPC + 1)->u.operand;
    int property = (vPC + 2)->u.operand;

darin@apple.com's avatar
darin@apple.com committed
100
    ScopeChainNode* scopeChain = callFrame->scopeChain();
101 102 103 104
    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
    ASSERT(iter != end);

darin@apple.com's avatar
darin@apple.com committed
105
    CodeBlock* codeBlock = callFrame->codeBlock();
106
    Identifier& ident = codeBlock->identifier(property);
107 108
    do {
        JSObject* o = *iter;
darin@apple.com's avatar
darin@apple.com committed
109
        PropertySlot slot(o);
darin@apple.com's avatar
darin@apple.com committed
110
        if (o->getPropertySlot(callFrame, ident, slot)) {
ggaren@apple.com's avatar
ggaren@apple.com committed
111
            JSValue result = slot.getValue(callFrame, ident);
darin@apple.com's avatar
darin@apple.com committed
112
            exceptionValue = callFrame->globalData().exception;
113 114
            if (exceptionValue)
                return false;
ggaren@apple.com's avatar
ggaren@apple.com committed
115
            callFrame[dst] = JSValue(result);
116 117 118
            return true;
        }
    } while (++iter != end);
119
    exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
120 121
    return false;
}
122

ggaren@apple.com's avatar
ggaren@apple.com committed
123
NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
124
{
darin@apple.com's avatar
darin@apple.com committed
125
    CodeBlock* codeBlock = callFrame->codeBlock();
126

127 128
    int dst = (vPC + 1)->u.operand;
    int property = (vPC + 2)->u.operand;
129
    int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain();
130

darin@apple.com's avatar
darin@apple.com committed
131
    ScopeChainNode* scopeChain = callFrame->scopeChain();
132 133 134 135 136 137 138
    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
    ASSERT(iter != end);
    while (skip--) {
        ++iter;
        ASSERT(iter != end);
    }
139
    Identifier& ident = codeBlock->identifier(property);
140 141
    do {
        JSObject* o = *iter;
darin@apple.com's avatar
darin@apple.com committed
142
        PropertySlot slot(o);
darin@apple.com's avatar
darin@apple.com committed
143
        if (o->getPropertySlot(callFrame, ident, slot)) {
ggaren@apple.com's avatar
ggaren@apple.com committed
144
            JSValue result = slot.getValue(callFrame, ident);
darin@apple.com's avatar
darin@apple.com committed
145
            exceptionValue = callFrame->globalData().exception;
146 147
            if (exceptionValue)
                return false;
ggaren@apple.com's avatar
ggaren@apple.com committed
148
            callFrame[dst] = JSValue(result);
149 150 151
            return true;
        }
    } while (++iter != end);
152
    exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
153 154 155
    return false;
}

ggaren@apple.com's avatar
ggaren@apple.com committed
156
NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
157 158 159 160 161
{
    int dst = (vPC + 1)->u.operand;
    JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
    ASSERT(globalObject->isGlobalObject());
    int property = (vPC + 3)->u.operand;
darin@apple.com's avatar
darin@apple.com committed
162
    Structure* structure = (vPC + 4)->u.structure;
163 164
    int offset = (vPC + 5)->u.operand;

darin@apple.com's avatar
darin@apple.com committed
165
    if (structure == globalObject->structure()) {
ggaren@apple.com's avatar
ggaren@apple.com committed
166
        callFrame[dst] = JSValue(globalObject->getDirectOffset(offset));
167 168 169
        return true;
    }

darin@apple.com's avatar
darin@apple.com committed
170
    CodeBlock* codeBlock = callFrame->codeBlock();
171
    Identifier& ident = codeBlock->identifier(property);
172
    PropertySlot slot(globalObject);
darin@apple.com's avatar
darin@apple.com committed
173
    if (globalObject->getPropertySlot(callFrame, ident, slot)) {
ggaren@apple.com's avatar
ggaren@apple.com committed
174
        JSValue result = slot.getValue(callFrame, ident);
175
        if (slot.isCacheable() && !globalObject->structure()->isDictionary() && slot.slotBase() == globalObject) {
darin@apple.com's avatar
darin@apple.com committed
176 177 178 179
            if (vPC[4].u.structure)
                vPC[4].u.structure->deref();
            globalObject->structure()->ref();
            vPC[4] = globalObject->structure();
180
            vPC[5] = slot.cachedOffset();
ggaren@apple.com's avatar
ggaren@apple.com committed
181
            callFrame[dst] = JSValue(result);
182 183 184
            return true;
        }

darin@apple.com's avatar
darin@apple.com committed
185
        exceptionValue = callFrame->globalData().exception;
186 187
        if (exceptionValue)
            return false;
ggaren@apple.com's avatar
ggaren@apple.com committed
188
        callFrame[dst] = JSValue(result);
189 190 191
        return true;
    }

192
    exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
193 194 195
    return false;
}

196
NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
197 198 199
{
    int dst = (vPC + 1)->u.operand;
    int property = (vPC + 2)->u.operand;
ggaren@apple.com's avatar
ggaren@apple.com committed
200
    callFrame[dst] = JSValue(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain()));
201 202
}

ggaren@apple.com's avatar
ggaren@apple.com committed
203
NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
204 205 206 207
{
    int baseDst = (vPC + 1)->u.operand;
    int propDst = (vPC + 2)->u.operand;
    int property = (vPC + 3)->u.operand;
208

darin@apple.com's avatar
darin@apple.com committed
209
    ScopeChainNode* scopeChain = callFrame->scopeChain();
210 211
    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
212

213
    // FIXME: add scopeDepthIsZero optimization
214

215
    ASSERT(iter != end);
216

darin@apple.com's avatar
darin@apple.com committed
217
    CodeBlock* codeBlock = callFrame->codeBlock();
218
    Identifier& ident = codeBlock->identifier(property);
219 220 221
    JSObject* base;
    do {
        base = *iter;
darin@apple.com's avatar
darin@apple.com committed
222
        PropertySlot slot(base);
darin@apple.com's avatar
darin@apple.com committed
223
        if (base->getPropertySlot(callFrame, ident, slot)) {
ggaren@apple.com's avatar
ggaren@apple.com committed
224
            JSValue result = slot.getValue(callFrame, ident);
darin@apple.com's avatar
darin@apple.com committed
225
            exceptionValue = callFrame->globalData().exception;
226 227
            if (exceptionValue)
                return false;
ggaren@apple.com's avatar
ggaren@apple.com committed
228 229
            callFrame[propDst] = JSValue(result);
            callFrame[baseDst] = JSValue(base);
230 231 232 233
            return true;
        }
        ++iter;
    } while (iter != end);
234

235
    exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
236 237 238
    return false;
}

ggaren@apple.com's avatar
ggaren@apple.com committed
239
NEVER_INLINE bool Interpreter::resolveBaseAndFunc(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
240 241 242 243 244
{
    int baseDst = (vPC + 1)->u.operand;
    int funcDst = (vPC + 2)->u.operand;
    int property = (vPC + 3)->u.operand;

darin@apple.com's avatar
darin@apple.com committed
245
    ScopeChainNode* scopeChain = callFrame->scopeChain();
246 247
    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
248

249
    // FIXME: add scopeDepthIsZero optimization
250

251
    ASSERT(iter != end);
252

darin@apple.com's avatar
darin@apple.com committed
253
    CodeBlock* codeBlock = callFrame->codeBlock();
254
    Identifier& ident = codeBlock->identifier(property);
255 256 257
    JSObject* base;
    do {
        base = *iter;
darin@apple.com's avatar
darin@apple.com committed
258
        PropertySlot slot(base);
darin@apple.com's avatar
darin@apple.com committed
259
        if (base->getPropertySlot(callFrame, ident, slot)) {            
260 261 262 263 264 265 266
            // ECMA 11.2.3 says that if we hit an activation the this value should be null.
            // However, section 10.2.3 says that in the case where the value provided
            // by the caller is null, the global object should be used. It also says
            // that the section does not apply to internal functions, but for simplicity
            // of implementation we use the global object anyway here. This guarantees
            // that in host objects you always get a valid object for this.
            // We also handle wrapper substitution for the global object at the same time.
darin@apple.com's avatar
darin@apple.com committed
267
            JSObject* thisObj = base->toThisObject(callFrame);
ggaren@apple.com's avatar
ggaren@apple.com committed
268
            JSValue result = slot.getValue(callFrame, ident);
darin@apple.com's avatar
darin@apple.com committed
269
            exceptionValue = callFrame->globalData().exception;
270 271
            if (exceptionValue)
                return false;
272

ggaren@apple.com's avatar
ggaren@apple.com committed
273 274
            callFrame[baseDst] = JSValue(thisObj);
            callFrame[funcDst] = JSValue(result);
275 276 277 278 279
            return true;
        }
        ++iter;
    } while (iter != end);

280
    exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
281 282 283
    return false;
}

284 285
#endif // USE(INTERPRETER)

286
ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
287
{
darin@apple.com's avatar
darin@apple.com committed
288
    Register* r = callFrame->registers();
289
    Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters;
290

291
    if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments
darin@apple.com's avatar
darin@apple.com committed
292 293
        if (UNLIKELY(!registerFile->grow(newEnd)))
            return 0;
294
        r += registerOffset;
295 296
    } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks
        size_t omittedArgCount = newCodeBlock->m_numParameters - argc;
297
        registerOffset += omittedArgCount;
298
        newEnd += omittedArgCount;
darin@apple.com's avatar
darin@apple.com committed
299 300
        if (!registerFile->grow(newEnd))
            return 0;
301
        r += registerOffset;
302

303 304 305 306
        Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
        for (size_t i = 0; i < omittedArgCount; ++i)
            argv[i] = jsUndefined();
    } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
307
        size_t numParameters = newCodeBlock->m_numParameters;
308
        registerOffset += numParameters;
309
        newEnd += numParameters;
310

darin@apple.com's avatar
darin@apple.com committed
311 312
        if (!registerFile->grow(newEnd))
            return 0;
313
        r += registerOffset;
314

315 316 317
        Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
        for (size_t i = 0; i < numParameters; ++i)
            argv[i + argc] = argv[i];
318
    }
319

darin@apple.com's avatar
darin@apple.com committed
320
    return CallFrame::create(r);
321 322
}

323
#if USE(INTERPRETER)
barraclough@apple.com's avatar
barraclough@apple.com committed
324
static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
325
{
weinig@apple.com's avatar
weinig@apple.com committed
326
    if (value.isObject())
327
        return false;
barraclough@apple.com's avatar
barraclough@apple.com committed
328 329 330 331 332 333 334 335 336
    exceptionData = createInvalidParamError(callFrame, "in" , value, vPC - codeBlock->instructions().begin(), codeBlock);
    return true;
}

static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
{
    if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
        return false;
    exceptionData = createInvalidParamError(callFrame, "instanceof" , value, vPC - codeBlock->instructions().begin(), codeBlock);
337 338
    return true;
}
339
#endif
340

ggaren@apple.com's avatar
ggaren@apple.com committed
341
NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue& exceptionValue)
342
{
343 344
    if (argc < 2)
        return jsUndefined();
345

ggaren@apple.com's avatar
ggaren@apple.com committed
346
    JSValue program = argv[1].jsValue();
347

weinig@apple.com's avatar
weinig@apple.com committed
348
    if (!program.isString())
349
        return program;
350

darin@apple.com's avatar
darin@apple.com committed
351
    UString programSource = asString(program)->value();
352

353
    LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
354 355 356 357
    if (JSValue parsedObject = preparser.tryLiteralParse())
        return parsedObject;
    
    
358
    ScopeChainNode* scopeChain = callFrame->scopeChain();
darin@apple.com's avatar
darin@apple.com committed
359
    CodeBlock* codeBlock = callFrame->codeBlock();
360
    RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue);
361

ggaren@apple.com's avatar
ggaren@apple.com committed
362
    JSValue result = jsUndefined();
mjs@apple.com's avatar
mjs@apple.com committed
363
    if (evalNode)
weinig@apple.com's avatar
weinig@apple.com committed
364
        result = callFrame->globalData().interpreter->execute(evalNode.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue);
365 366

    return result;
367 368
}

369
Interpreter::Interpreter()
370 371
    : m_sampler(0)
    , m_reentryDepth(0)
372
{
darin@apple.com's avatar
darin@apple.com committed
373
    privateExecute(InitializeAndReturn, 0, 0, 0);
374 375
}

376 377
#ifndef NDEBUG

378
void Interpreter::dumpCallFrame(CallFrame* callFrame)
379
{
380 381
    callFrame->codeBlock()->dump(callFrame);
    dumpRegisters(callFrame);
382 383
}

384
void Interpreter::dumpRegisters(CallFrame* callFrame)
385 386
{
    printf("Register frame: \n\n");
ggaren@apple.com's avatar
ggaren@apple.com committed
387 388 389
    printf("----------------------------------------------------\n");
    printf("            use            |   address  |   value   \n");
    printf("----------------------------------------------------\n");
390

darin@apple.com's avatar
darin@apple.com committed
391
    CodeBlock* codeBlock = callFrame->codeBlock();
ggaren@apple.com's avatar
ggaren@apple.com committed
392
    RegisterFile* registerFile = &callFrame->scopeChain()->globalObject()->globalData()->interpreter->registerFile();
393 394
    const Register* it;
    const Register* end;
395

396
    if (codeBlock->codeType() == GlobalCode) {
ggaren@apple.com's avatar
ggaren@apple.com committed
397 398 399
        it = registerFile->lastGlobal();
        end = it + registerFile->numGlobals();
        while (it != end) {
ggaren@apple.com's avatar
ggaren@apple.com committed
400
            printf("[global var]               | %10p | %10p \n", it, (*it).v());
ggaren@apple.com's avatar
ggaren@apple.com committed
401
            ++it;
402
        }
ggaren@apple.com's avatar
ggaren@apple.com committed
403 404 405
        printf("----------------------------------------------------\n");
    }
    
406
    it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters;
407
    printf("[this]                     | %10p | %10p \n", it, (*it).v()); ++it;
408
    end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this"
409 410 411 412 413 414 415 416
    if (it != end) {
        do {
            printf("[param]                    | %10p | %10p \n", it, (*it).v());
            ++it;
        } while (it != end);
    }
    printf("----------------------------------------------------\n");

417
    printf("[CodeBlock]                | %10p | %10p \n", it, (*it).v()); ++it;
ggaren@apple.com's avatar
ggaren@apple.com committed
418
    printf("[ScopeChain]               | %10p | %10p \n", it, (*it).v()); ++it;
419 420
    printf("[CallerRegisters]          | %10p | %10p \n", it, (*it).v()); ++it;
    printf("[ReturnPC]                 | %10p | %10p \n", it, (*it).v()); ++it;
ggaren@apple.com's avatar
ggaren@apple.com committed
421 422 423
    printf("[ReturnValueRegister]      | %10p | %10p \n", it, (*it).v()); ++it;
    printf("[ArgumentCount]            | %10p | %10p \n", it, (*it).v()); ++it;
    printf("[Callee]                   | %10p | %10p \n", it, (*it).v()); ++it;
424
    printf("[OptionalCalleeArguments]  | %10p | %10p \n", it, (*it).v()); ++it;
ggaren@apple.com's avatar
ggaren@apple.com committed
425 426
    printf("----------------------------------------------------\n");

427 428
    int registerCount = 0;

429
    end = it + codeBlock->m_numVars;
ggaren@apple.com's avatar
ggaren@apple.com committed
430 431
    if (it != end) {
        do {
432
            printf("[r%2d]                      | %10p | %10p \n", registerCount, it, (*it).v());
ggaren@apple.com's avatar
ggaren@apple.com committed
433
            ++it;
434
            ++registerCount;
ggaren@apple.com's avatar
ggaren@apple.com committed
435 436 437
        } while (it != end);
    }
    printf("----------------------------------------------------\n");
438

439
    end = it + codeBlock->m_numConstants;
440 441 442 443 444 445
    if (it != end) {
        do {
            printf("[r%2d]                      | %10p | %10p \n", registerCount, it, (*it).v());
            ++it;
            ++registerCount;
        } while (it != end);
446
    }
447
    printf("----------------------------------------------------\n");
448

449
    end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numConstants - codeBlock->m_numVars;
450 451
    if (it != end) {
        do {
452
            printf("[r%2d]                      | %10p | %10p \n", registerCount, it, (*it).v());
453
            ++it;
454
            ++registerCount;
455 456
        } while (it != end);
    }
457
    printf("----------------------------------------------------\n");
458 459
}

460 461
#endif

462
bool Interpreter::isOpcode(Opcode opcode)
463 464
{
#if HAVE(COMPUTED_GOTO)
465 466 467
    return opcode != HashTraits<Opcode>::emptyValue()
        && !HashTraits<Opcode>::isDeletedValue(opcode)
        && m_opcodeIDTable.contains(opcode);
468
#else
469
    return opcode >= 0 && opcode <= op_end;
470 471 472
#endif
}

ggaren@apple.com's avatar
ggaren@apple.com committed
473
NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
474 475
{
    CodeBlock* oldCodeBlock = codeBlock;
darin@apple.com's avatar
darin@apple.com committed
476
    ScopeChainNode* scopeChain = callFrame->scopeChain();
477

darin@apple.com's avatar
darin@apple.com committed
478 479 480
    if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
        DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
        if (callFrame->callee())
481
            debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine());
ggaren@apple.com's avatar
ggaren@apple.com committed
482
        else
483
            debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine());
484 485
    }

486
    if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
darin@apple.com's avatar
darin@apple.com committed
487 488
        if (callFrame->callee())
            profiler->didExecute(callFrame, callFrame->callee());
489
        else
490
            profiler->didExecute(callFrame, codeBlock->ownerNode()->sourceURL(), codeBlock->ownerNode()->lineNo());
491 492
    }

493
    // If this call frame created an activation or an 'arguments' object, tear it off.
494
    if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
495 496
        while (!scopeChain->object->isObject(&JSActivation::info))
            scopeChain = scopeChain->pop();
darin@apple.com's avatar
darin@apple.com committed
497 498
        static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments());
    } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) {
499 500
        if (!arguments->isTornOff())
            arguments->copyRegisters();
501
    }
502

503
    if (oldCodeBlock->needsFullScopeChain())
504 505
        scopeChain->deref();

darin@apple.com's avatar
darin@apple.com committed
506 507 508
    void* returnPC = callFrame->returnPC();
    callFrame = callFrame->callerFrame();
    if (callFrame->hasHostCallFrameFlag())
509
        return false;
510

darin@apple.com's avatar
darin@apple.com committed
511
    codeBlock = callFrame->codeBlock();
512
    bytecodeOffset = bytecodeOffsetForPC(callFrame, codeBlock, returnPC);
513 514 515
    return true;
}

ggaren@apple.com's avatar
ggaren@apple.com committed
516
NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset, bool explicitThrow)
517 518
{
    // Set up the exception object
519

darin@apple.com's avatar
darin@apple.com committed
520
    CodeBlock* codeBlock = callFrame->codeBlock();
weinig@apple.com's avatar
weinig@apple.com committed
521
    if (exceptionValue.isObject()) {
darin@apple.com's avatar
darin@apple.com committed
522
        JSObject* exception = asObject(exceptionValue);
523
        if (exception->isNotAnObjectErrorStub()) {
524
            exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock);
525 526
            exceptionValue = exception;
        } else {
darin@apple.com's avatar
darin@apple.com committed
527 528 529 530 531 532
            if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) && 
                !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) && 
                !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) && 
                !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) && 
                !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) && 
                !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) {
533 534 535 536
                if (explicitThrow) {
                    int startOffset = 0;
                    int endOffset = 0;
                    int divotPoint = 0;
537
                    int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset);
darin@apple.com's avatar
darin@apple.com committed
538
                    exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete);
539 540 541
                    
                    // We only hit this path for error messages and throw statements, which don't have a specific failure position
                    // So we just give the full range of the error/throw statement.
darin@apple.com's avatar
darin@apple.com committed
542 543
                    exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete);
                    exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete);
544
                } else
545
                    exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete);
546 547
                exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerNode()->sourceID()), ReadOnly | DontDelete);
                exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerNode()->sourceURL()), ReadOnly | DontDelete);
548 549 550
            }
            
            if (exception->isWatchdogException()) {
551
                while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
552 553 554
                    // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
                }
                return 0;
555 556
            }
        }
557 558
    }

darin@apple.com's avatar
darin@apple.com committed
559 560
    if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
        DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
561
        debugger->exception(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset));
562 563
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
564 565 566 567
    // If we throw in the middle of a call instruction, we need to notify
    // the profiler manually that the call instruction has returned, since
    // we'll never reach the relevant op_profile_did_call.
    if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
568
#if !ENABLE(JIT)
569
        if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode))
ggaren@apple.com's avatar
ggaren@apple.com committed
570
            profiler->didExecute(callFrame, callFrame[codeBlock->instructions()[bytecodeOffset + 2].u.operand].jsValue());
571
        else if (codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct))
ggaren@apple.com's avatar
ggaren@apple.com committed
572
            profiler->didExecute(callFrame, callFrame[codeBlock->instructions()[bytecodeOffset + 10].u.operand].jsValue());
573 574 575
#else
        int functionRegisterIndex;
        if (codeBlock->functionRegisterForBytecodeOffset(bytecodeOffset, functionRegisterIndex))
ggaren@apple.com's avatar
ggaren@apple.com committed
576
            profiler->didExecute(callFrame, callFrame[functionRegisterIndex].jsValue());
577
#endif
ggaren@apple.com's avatar
ggaren@apple.com committed
578 579
    }

580 581
    // Calculate an exception handler vPC, unwinding call frames as necessary.

582
    HandlerInfo* handler = 0;
583 584
    while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
        if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock))
585
            return 0;
586
    }
587 588

    // Now unwind the scope chain within the exception handler's call frame.
589

590 591
    ScopeChainNode* scopeChain = callFrame->scopeChain();
    ScopeChain sc(scopeChain);
592
    int scopeDelta = depth(codeBlock, sc) - handler->scopeDepth;
593 594
    ASSERT(scopeDelta >= 0);
    while (scopeDelta--)
595 596
        scopeChain = scopeChain->pop();
    callFrame->setScopeChain(scopeChain);
597

598
    return handler;
599 600
}

ggaren@apple.com's avatar
ggaren@apple.com committed
601
JSValue Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception)
602
{
darin@apple.com's avatar
darin@apple.com committed
603
    ASSERT(!scopeChain->globalData->exception);
ggaren@apple.com's avatar
ggaren@apple.com committed
604

605 606 607 608 609
    if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
        if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
            *exception = createStackOverflowError(callFrame);
            return jsNull();
        }
610 611
    }

612
    CodeBlock* codeBlock = &programNode->bytecode(scopeChain);
613

614
    Register* oldEnd = m_registerFile.end();
615
    Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
616
    if (!m_registerFile.grow(newEnd)) {
darin@apple.com's avatar
darin@apple.com committed
617
        *exception = createStackOverflowError(callFrame);
ggaren@apple.com's avatar
ggaren@apple.com committed
618
        return jsNull();
619
    }
620

darin@apple.com's avatar
darin@apple.com committed
621
    DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject());
622

ggaren@apple.com's avatar
ggaren@apple.com committed
623
    JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
darin@apple.com's avatar
darin@apple.com committed
624
    JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
ggaren@apple.com's avatar
ggaren@apple.com committed
625 626
    globalObject->copyGlobalsTo(m_registerFile);

627
    CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
ggaren@apple.com's avatar
ggaren@apple.com committed
628
    newCallFrame[codeBlock->thisRegister()] = JSValue(thisObj);
darin@apple.com's avatar
darin@apple.com committed
629
    newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0);
630

631
    if (codeBlock->needsFullScopeChain())
darin@apple.com's avatar
darin@apple.com committed
632
        scopeChain->ref();
633 634 635

    Profiler** profiler = Profiler::enabledProfilerReference();
    if (*profiler)
darin@apple.com's avatar
darin@apple.com committed
636
        (*profiler)->willExecute(newCallFrame, programNode->sourceURL(), programNode->lineNo());
637

ggaren@apple.com's avatar
ggaren@apple.com committed
638
    JSValue result;
639 640 641 642
    {
        SamplingTool::CallRecord callRecord(m_sampler);

        m_reentryDepth++;
643
#if ENABLE(JIT)
644
        result = programNode->jitCode(scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
645
#else
646
        result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
647
#endif
648 649
        m_reentryDepth--;
    }
650

kmccullough@apple.com's avatar
kmccullough@apple.com committed
651
    if (*profiler)
darin@apple.com's avatar
darin@apple.com committed
652
        (*profiler)->didExecute(callFrame, programNode->sourceURL(), programNode->lineNo());
653

654
    if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
ggaren@apple.com's avatar
ggaren@apple.com committed
655 656
        lastGlobalObject->copyGlobalsTo(m_registerFile);

657
    m_registerFile.shrink(oldEnd);
658

659 660 661
    return result;
}

ggaren@apple.com's avatar
ggaren@apple.com committed
662
JSValue Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception)
663
{
darin@apple.com's avatar
darin@apple.com committed
664
    ASSERT(!scopeChain->globalData->exception);
ggaren@apple.com's avatar
ggaren@apple.com committed
665

666 667 668 669 670
    if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
        if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
            *exception = createStackOverflowError(callFrame);
            return jsNull();
        }
671 672
    }

673
    Register* oldEnd = m_registerFile.end();
674 675
    int argc = 1 + args.size(); // implicit "this" parameter

676
    if (!m_registerFile.grow(oldEnd + argc)) {
darin@apple.com's avatar
darin@apple.com committed
677
        *exception = createStackOverflowError(callFrame);
ggaren@apple.com's avatar
ggaren@apple.com committed
678
        return jsNull();
679
    }
680

darin@apple.com's avatar
darin@apple.com committed
681
    DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject());
682

darin@apple.com's avatar
darin@apple.com committed
683
    CallFrame* newCallFrame = CallFrame::create(oldEnd);
684
    size_t dst = 0;