Machine.cpp 98 KB
Newer Older
1 2 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 31 32 33 34 35 36 37 38 39 40
/*
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 * 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"
#include "Machine.h"

#include "CodeBlock.h"
#include "DebuggerCallFrame.h"
#include "ExceptionHelpers.h"
#include "ExecState.h"
#include "JSActivation.h"
#include "JSLock.h"
#include "JSPropertyNameIterator.h"
#include "Parser.h"
41
#include "Profiler.h"
42
#include "Register.h"
43
#include "JSArray.h"
44
#include "debugger.h"
darin@apple.com's avatar
darin@apple.com committed
45 46
#include "JSFunction.h"
#include "JSString.h"
47 48
#include "object_object.h"
#include "operations.h"
darin@apple.com's avatar
darin@apple.com committed
49
#include "RegExpObject.h"
50

51 52 53 54 55 56 57 58 59 60 61 62
#if HAVE(SYS_TIME_H)
#include <sys/time.h>
#endif

#if PLATFORM(WIN_OS)
#include <windows.h>
#endif

#if PLATFORM(QT)
#include <QDateTime>
#endif

ggaren@apple.com's avatar
ggaren@apple.com committed
63 64
using namespace std;

65 66
namespace KJS {

67 68 69 70 71 72
// Default number of ticks before a timeout check should be done.
static const int initialTickCountThreshold = 255;

// Preferred number of milliseconds between each timeout check
static const int preferredScriptCheckTimeInterval = 1000;

73 74 75 76 77 78 79 80 81
#if HAVE(COMPUTED_GOTO)
static void* op_throw_end_indirect;
static void* op_call_indirect;
#endif

// Returns the depth of the scope chain within a given call frame.
static int depth(ScopeChain& sc)
{
    int scopeDepth = 0;
82 83
    ScopeChainIterator iter = sc.begin();
    ScopeChainIterator end = sc.end();
84 85 86 87 88 89
    while (!(*iter)->isVariableObject()) {
        ++iter;
        ++scopeDepth;
    }
    return scopeDepth;
}
90

91 92
static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
{
93 94 95
    if (JSImmediate::areBothImmediateNumbers(v1, v2))
        return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);

96 97 98 99 100 101 102 103 104 105
    double n1;
    double n2;
    JSValue* p1;
    JSValue* p2;
    bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
    bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);

    if (wasNotString1 | wasNotString2)
        return n1 < n2;

darin@apple.com's avatar
darin@apple.com committed
106
    return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
107 108 109 110 111 112 113 114 115 116 117 118 119 120
}

static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
{
    double n1;
    double n2;
    JSValue* p1;
    JSValue* p2;
    bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
    bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);

    if (wasNotString1 | wasNotString2)
        return n1 <= n2;

darin@apple.com's avatar
darin@apple.com committed
121
    return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
122 123 124 125 126 127 128 129 130 131 132 133
}

static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
{
    // exception for the Date exception in defaultValue()
    JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
    JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);

    if (p1->isString() || p2->isString()) {
        UString value = p1->toString(exec) + p2->toString(exec);
        if (value.isNull())
            return throwOutOfMemoryError(exec);
ap@webkit.org's avatar
ap@webkit.org committed
134
        return jsString(exec, value);
135 136
    }

ap@webkit.org's avatar
ap@webkit.org committed
137
    return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
138 139 140 141 142
}

// Fast-path choices here are based on frequency data from SunSpider:
//    <times> Add case: <t1> <t2>
//    ---------------------------
143
//    5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
ap@webkit.org's avatar
ap@webkit.org committed
144 145 146 147
//    247412  Add case: 5 5
//    20900   Add case: 5 6
//    13962   Add case: 5 3
//    4000    Add case: 3 5
148 149 150 151 152 153 154 155

static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
{
    JSType t1 = v1->type();
    JSType t2 = v2->type();
    const unsigned bothTypes = (t1 << 3) | t2;

    if (bothTypes == ((NumberType << 3) | NumberType))
ap@webkit.org's avatar
ap@webkit.org committed
156
        return jsNumber(exec, v1->uncheckedGetNumber() + v2->uncheckedGetNumber());
157
    if (bothTypes == ((StringType << 3) | StringType)) {
darin@apple.com's avatar
darin@apple.com committed
158
        UString value = static_cast<JSString*>(v1)->value() + static_cast<JSString*>(v2)->value();
159 160
        if (value.isNull())
            return throwOutOfMemoryError(exec);
ap@webkit.org's avatar
ap@webkit.org committed
161
        return jsString(exec, value);
162 163 164 165 166 167
    }

    // All other cases are pretty uncommon
    return jsAddSlowCase(exec, v1, v2);
}

ap@webkit.org's avatar
ap@webkit.org committed
168
static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
169 170 171
{
    switch (v->type()) {
        case UndefinedType:
ap@webkit.org's avatar
ap@webkit.org committed
172
            return jsString(exec, "undefined");
173
        case NullType:
ap@webkit.org's avatar
ap@webkit.org committed
174
            return jsString(exec, "object");
175
        case BooleanType:
ap@webkit.org's avatar
ap@webkit.org committed
176
            return jsString(exec, "boolean");
177
        case NumberType:
ap@webkit.org's avatar
ap@webkit.org committed
178
            return jsString(exec, "number");
179
        case StringType:
ap@webkit.org's avatar
ap@webkit.org committed
180
            return jsString(exec, "string");
181 182 183 184 185
        default:
            if (v->isObject()) {
                // Return "undefined" for objects that should be treated
                // as null when doing comparisons.
                if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
ap@webkit.org's avatar
ap@webkit.org committed
186
                    return jsString(exec, "undefined");
darin@apple.com's avatar
darin@apple.com committed
187 188
                CallData callData;
                if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
ap@webkit.org's avatar
ap@webkit.org committed
189
                    return jsString(exec, "function");
190 191
            }

ap@webkit.org's avatar
ap@webkit.org committed
192
            return jsString(exec, "object");
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
    }
}

static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
{
    int dst = (vPC + 1)->u.operand;
    int property = (vPC + 2)->u.operand;

    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
    ASSERT(iter != end);

    Identifier& ident = codeBlock->identifiers[property];
    do {
        JSObject* o = *iter;
darin@apple.com's avatar
darin@apple.com committed
208
        PropertySlot slot(o);
209
        if (o->getPropertySlot(exec, ident, slot)) {
darin@apple.com's avatar
darin@apple.com committed
210
            JSValue* result = slot.getValue(exec, ident);
211 212 213 214 215 216 217 218 219 220
            exceptionValue = exec->exception();
            if (exceptionValue)
                return false;
            r[dst].u.jsValue = result;
            return true;
        }
    } while (++iter != end);
    exceptionValue = createUndefinedVariableError(exec, ident);
    return false;
}
221

222 223 224 225 226
static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
{
    int dst = (vPC + 1)->u.operand;
    int property = (vPC + 2)->u.operand;
    int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
227

228 229 230 231 232 233 234 235 236 237
    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
    ASSERT(iter != end);
    while (skip--) {
        ++iter;
        ASSERT(iter != end);
    }
    Identifier& ident = codeBlock->identifiers[property];
    do {
        JSObject* o = *iter;
darin@apple.com's avatar
darin@apple.com committed
238
        PropertySlot slot(o);
239
        if (o->getPropertySlot(exec, ident, slot)) {
darin@apple.com's avatar
darin@apple.com committed
240
            JSValue* result = slot.getValue(exec, ident);
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
            exceptionValue = exec->exception();
            if (exceptionValue)
                return false;
            r[dst].u.jsValue = result;
            return true;
        }
    } while (++iter != end);
    exceptionValue = createUndefinedVariableError(exec, ident);
    return false;
}

static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
{
    int dst = (vPC + 1)->u.operand;
    int property = (vPC + 2)->u.operand;

    ScopeChainIterator iter = scopeChain->begin();
258 259
    ScopeChainIterator next = iter;
    ++next;
260 261 262 263 264 265
    ScopeChainIterator end = scopeChain->end();
    ASSERT(iter != end);

    PropertySlot slot;
    Identifier& ident = codeBlock->identifiers[property];
    JSObject* base;
266
    while (true) {
267
        base = *iter;
268
        if (next == end || base->getPropertySlot(exec, ident, slot)) {
269 270 271
            r[dst].u.jsValue = base;
            return;
        }
272 273 274
        iter = next;
        ++next;
    }
275 276 277 278 279 280 281
}

static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
{
    int baseDst = (vPC + 1)->u.operand;
    int propDst = (vPC + 2)->u.operand;
    int property = (vPC + 3)->u.operand;
282

283 284
    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
285

286
    // FIXME: add scopeDepthIsZero optimization
287

288
    ASSERT(iter != end);
289

290 291 292 293
    Identifier& ident = codeBlock->identifiers[property];
    JSObject* base;
    do {
        base = *iter;
darin@apple.com's avatar
darin@apple.com committed
294
        PropertySlot slot(base);
295
        if (base->getPropertySlot(exec, ident, slot)) {
darin@apple.com's avatar
darin@apple.com committed
296
            JSValue* result = slot.getValue(exec, ident);
297 298 299
            exceptionValue = exec->exception();
            if (exceptionValue)
                return false;
300
            r[propDst].u.jsValue = result;
301 302 303 304 305
            r[baseDst].u.jsValue = base;
            return true;
        }
        ++iter;
    } while (iter != end);
306

307 308 309 310 311 312 313 314 315 316 317 318
    exceptionValue = createUndefinedVariableError(exec, ident);
    return false;
}

static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
{
    int baseDst = (vPC + 1)->u.operand;
    int funcDst = (vPC + 2)->u.operand;
    int property = (vPC + 3)->u.operand;

    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
319

320
    // FIXME: add scopeDepthIsZero optimization
321

322
    ASSERT(iter != end);
323

324 325 326 327
    Identifier& ident = codeBlock->identifiers[property];
    JSObject* base;
    do {
        base = *iter;
darin@apple.com's avatar
darin@apple.com committed
328
        PropertySlot slot(base);
329 330 331 332 333 334 335 336 337
        if (base->getPropertySlot(exec, ident, slot)) {            
            // 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.
            JSObject* thisObj = base->toThisObject(exec);
darin@apple.com's avatar
darin@apple.com committed
338
            JSValue* result = slot.getValue(exec, ident);
339 340 341
            exceptionValue = exec->exception();
            if (exceptionValue)
                return false;
342

343 344 345 346 347 348 349 350 351 352 353 354 355
            r[baseDst].u.jsValue = thisObj;
            r[funcDst].u.jsValue = result;
            return true;
        }
        ++iter;
    } while (iter != end);

    exceptionValue = createUndefinedVariableError(exec, ident);
    return false;
}

ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, int registerOffset, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
{
ggaren@apple.com's avatar
ggaren@apple.com committed
356 357 358 359 360 361 362 363 364 365
    callFrame[RegisterFile::CallerCodeBlock].u.codeBlock = codeBlock;
    callFrame[RegisterFile::ReturnVPC].u.vPC = vPC + 1;
    callFrame[RegisterFile::CallerScopeChain].u.scopeChain = scopeChain;
    callFrame[RegisterFile::CallerRegisterOffset].u.i = registerOffset;
    callFrame[RegisterFile::ReturnValueRegister].u.i = returnValueRegister;
    callFrame[RegisterFile::ArgumentStartRegister].u.i = argv; // original argument vector (for the sake of the "arguments" object)
    callFrame[RegisterFile::ArgumentCount].u.i = argc; // original argument count (for the sake of the "arguments" object)
    callFrame[RegisterFile::CalledAsConstructor].u.i = calledAsConstructor;
    callFrame[RegisterFile::Callee].u.jsValue = function;
    callFrame[RegisterFile::OptionalCalleeActivation].u.jsValue = 0;
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
}

ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register** registerBase, int registerOffset, int argv, int argc, JSValue*& exceptionValue)
{
    Register* r = 0;
    int oldOffset = registerOffset;
    registerOffset += argv + newCodeBlock->numLocals;
    size_t size = registerOffset + newCodeBlock->numTemporaries;

    if (argc == newCodeBlock->numParameters) { // correct number of arguments
        if (!registerFile->grow(size)) {
            exceptionValue = createStackOverflowError(exec);
            return *registerBase + oldOffset;
        }
        r = (*registerBase) + registerOffset;
    } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
        if (!registerFile->grow(size)) {
            exceptionValue = createStackOverflowError(exec);
            return *registerBase + oldOffset;
        }
        r = (*registerBase) + registerOffset;
387

388 389 390 391 392
        int omittedArgCount = newCodeBlock->numParameters - argc;
        Register* endOfParams = r - newCodeBlock->numVars;
        for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
            (*it).u.jsValue = jsUndefined();
    } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
ggaren@apple.com's avatar
ggaren@apple.com committed
393
        int shift = argc + RegisterFile::CallFrameHeaderSize;
394 395 396 397 398 399 400 401
        registerOffset += shift;
        size += shift;

        if (!registerFile->grow(size)) {
            exceptionValue = createStackOverflowError(exec);
            return *registerBase + oldOffset;
        }
        r = (*registerBase) + registerOffset;
402

ggaren@apple.com's avatar
ggaren@apple.com committed
403 404
        Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
        Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
405 406 407
        for ( ; it != end; ++it)
            *(it + shift) = *it;
    }
408 409 410 411
    
    // initialize local variable slots
    for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
        (*it).u.jsValue = jsUndefined();
412 413 414 415

    return r;
}

ap@webkit.org's avatar
ap@webkit.org committed
416
ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register** registerBase, Register* r)
417 418
{
    if (newCodeBlock->needsFullScopeChain) {
ap@webkit.org's avatar
ap@webkit.org committed
419
        JSActivation* activation = new (exec) JSActivation(functionBodyNode, registerBase, r - (*registerBase));
ggaren@apple.com's avatar
ggaren@apple.com committed
420
        r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals].u.jsValue = activation;
421 422 423 424 425 426 427

        return callDataScopeChain->copy()->push(activation);
    }

    return callDataScopeChain;
}

428
static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock*, JSValue* value, JSValue*& exceptionData)
429 430 431
{
    if (value->isObject())
        return false;
432
    exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value);
433 434 435
    return true;
}

ggaren@apple.com's avatar
ggaren@apple.com committed
436
NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
437
{
438 439
    if (argc < 2)
        return jsUndefined();
440

441
    JSValue* program = r[argv + 1].u.jsValue;
442

443 444
    if (!program->isString())
        return program;
445

446 447 448
    Profiler** profiler = Profiler::enabledProfilerReference();
    if (*profiler)
        (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
449 450 451 452

    int sourceId;
    int errLine;
    UString errMsg;
darin@apple.com's avatar
darin@apple.com committed
453
    RefPtr<EvalNode> evalNode = exec->parser()->parse<EvalNode>(exec, UString(), 1, UStringSourceProvider::create(static_cast<JSString*>(program)->value()), &sourceId, &errLine, &errMsg);
454

455 456
    if (!evalNode) {
        exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
457 458
        if (*profiler)
            (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
459 460 461
        return 0;
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
462
    JSValue* result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - (*registerFile->basePointer()) + argv + argc, scopeChain, &exceptionValue);
463

464
    if (*profiler)
465
        (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
466 467

    return result;
468 469 470 471
}

Machine::Machine()
    : m_reentryDepth(0)
472 473 474 475 476
    , m_timeoutTime(0)
    , m_timeAtLastCheckTimeout(0)
    , m_timeExecuting(0)
    , m_timeoutCheckCount(0)
    , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
477 478 479 480 481 482 483
{
    privateExecute(InitializeAndReturn);
}

void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
{
    ScopeChain sc(scopeChain);
484
    JSGlobalObject* globalObject = sc.globalObject();
485 486 487 488 489 490 491
    codeBlock->dump(globalObject->globalExec());
    dumpRegisters(codeBlock, registerFile, r);
}

void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
{
    printf("Register frame: \n\n");
ggaren@apple.com's avatar
ggaren@apple.com committed
492 493 494
    printf("----------------------------------------------------\n");
    printf("            use            |   address  |   value   \n");
    printf("----------------------------------------------------\n");
495

496 497
    const Register* it;
    const Register* end;
498

ggaren@apple.com's avatar
ggaren@apple.com committed
499 500 501 502 503 504
    if (codeBlock->codeType == GlobalCode) {
        it = registerFile->lastGlobal();
        end = it + registerFile->numGlobals();
        while (it != end) {
            printf("[global var]               | %10p | %10p \n", it, (*it).u.jsValue);
            ++it;
505
        }
ggaren@apple.com's avatar
ggaren@apple.com committed
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
        printf("----------------------------------------------------\n");
    }
    
    it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
    printf("[CallerCodeBlock]          | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("[ReturnVPC]                | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("[CallerScopeChain]         | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("[CallerRegisterOffset]     | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("[ReturnValueRegister]      | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("[ArgumentStartRegister]    | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("[ArgumentCount]            | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("[CalledAsConstructor]      | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("[Callee]                   | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    printf("----------------------------------------------------\n");

    printf("[this]                     | %10p | %10p \n", it, (*it).u.jsValue); ++it;
    end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
    if (it != end) {
        do {
            printf("[param]                    | %10p | %10p \n", it, (*it).u.jsValue);
            ++it;
        } while (it != end);
    }
    printf("----------------------------------------------------\n");
531

ggaren@apple.com's avatar
ggaren@apple.com committed
532
    if (codeBlock->codeType != GlobalCode) {
533 534 535
        end = it + codeBlock->numVars;
        if (it != end) {
            do {
ggaren@apple.com's avatar
ggaren@apple.com committed
536
                printf("[var]                      | %10p | %10p \n", it, (*it).u.jsValue);
537 538
                ++it;
            } while (it != end);
ggaren@apple.com's avatar
ggaren@apple.com committed
539
        printf("----------------------------------------------------\n");
540 541 542 543 544 545
        }
    }

    end = it + codeBlock->numTemporaries;
    if (it != end) {
        do {
ggaren@apple.com's avatar
ggaren@apple.com committed
546
            printf("[temp]                     | %10p | %10p \n", it, (*it).u.jsValue);
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
            ++it;
        } while (it != end);
    }
}

bool Machine::isOpcode(Opcode opcode)
{
#if HAVE(COMPUTED_GOTO)
    return opcode != HashTraits<Opcode>::emptyValue()
        && !HashTraits<Opcode>::isDeletedValue(opcode)
        && m_opcodeIDTable.contains(opcode);
#else
    return opcode >= 0 && opcode <= op_end;
#endif
}

NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction*& vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
{
    CodeBlock* oldCodeBlock = codeBlock;
ggaren@apple.com's avatar
ggaren@apple.com committed
566
    Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
567

568
    if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
ap@webkit.org's avatar
ap@webkit.org committed
569
        DebuggerCallFrame debuggerCallFrame(exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
ggaren@apple.com's avatar
ggaren@apple.com committed
570
        if (callFrame[RegisterFile::Callee].u.jsObject)
571
            debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
ggaren@apple.com's avatar
ggaren@apple.com committed
572 573
        else
            debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
574 575
    }

576
    if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
ggaren@apple.com's avatar
ggaren@apple.com committed
577 578
        if (callFrame[RegisterFile::Callee].u.jsObject)
            profiler->didExecute(exec, callFrame[RegisterFile::Callee].u.jsObject);
579 580 581 582
        else
            profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
    }

583 584
    if (oldCodeBlock->needsFullScopeChain)
        scopeChain->deref();
585

586
    // If this call frame created an activation, tear it off.
ggaren@apple.com's avatar
ggaren@apple.com committed
587
    if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].u.jsValue)) {
588 589 590
        ASSERT(activation->isActivationObject());
        activation->copyRegisters();
    }
591
    
ggaren@apple.com's avatar
ggaren@apple.com committed
592
    codeBlock = callFrame[RegisterFile::CallerCodeBlock].u.codeBlock;
593 594
    if (!codeBlock)
        return false;
595 596

    k = codeBlock->jsValues.data();
ggaren@apple.com's avatar
ggaren@apple.com committed
597 598
    scopeChain = callFrame[RegisterFile::CallerScopeChain].u.scopeChain;
    int callerRegisterOffset = callFrame[RegisterFile::CallerRegisterOffset].u.i;
599
    r = (*registerBase) + callerRegisterOffset;
ggaren@apple.com's avatar
ggaren@apple.com committed
600 601
    exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
    vPC = callFrame[RegisterFile::ReturnVPC].u.vPC;
602

603 604 605 606 607 608 609 610 611
    return true;
}

NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction* vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
{
    // Set up the exception object

    if (exceptionValue->isObject()) {
        JSObject* exception = static_cast<JSObject*>(exceptionValue);
ap@webkit.org's avatar
ap@webkit.org committed
612
        if (!exception->hasProperty(exec, Identifier(exec, "line")) && !exception->hasProperty(exec, Identifier(exec, "sourceURL"))) {
ap@webkit.org's avatar
ap@webkit.org committed
613 614
            exception->put(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)));
            exception->put(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()));
615
        }
616 617 618 619 620 621 622

        if (exception->isWatchdogException()) {
            while (unwindCallFrame(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r)) {
                 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
            }
            return 0;
        }
623 624 625
    }

    if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
ap@webkit.org's avatar
ap@webkit.org committed
626
        DebuggerCallFrame debuggerCallFrame(exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
627 628 629 630 631
        debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
    }

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

632
    int scopeDepth;
633 634
    Instruction* handlerVPC;

635
    while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
636 637
        if (!unwindCallFrame(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r))
            return 0;
638
    }
639 640

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

642 643 644 645 646 647 648 649 650 651
    ScopeChain sc(scopeChain);
    int scopeDelta = depth(sc) - scopeDepth;
    ASSERT(scopeDelta >= 0);
    while (scopeDelta--)
        sc.pop();
    setScopeChain(exec, scopeChain, sc.node());

    return handlerVPC;
}

ggaren@apple.com's avatar
ggaren@apple.com committed
652
JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
653 654 655 656 657 658
{
    if (m_reentryDepth >= MaxReentryDepth) {
        *exception = createStackOverflowError(exec);
        return 0;
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
659
    CodeBlock* codeBlock = &programNode->code(scopeChain);
660

ggaren@apple.com's avatar
ggaren@apple.com committed
661 662 663
    size_t oldSize = m_registerFile.size();
    size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numTemporaries;
    if (!m_registerFile.grow(newSize)) {
664 665 666
        *exception = createStackOverflowError(exec);
        return 0;
    }
667

ggaren@apple.com's avatar
ggaren@apple.com committed
668 669 670 671 672 673 674 675 676 677 678
    JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
    JSGlobalObject* globalObject = exec->dynamicGlobalObject();
    globalObject->copyGlobalsTo(m_registerFile);

    Register* callFrame = *m_registerFile.basePointer() + oldSize;

    // a 0 codeBlock indicates a built-in caller
    initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);

    Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
    r[codeBlock->thisRegister].u.jsValue = thisObj;
679

680 681
    if (codeBlock->needsFullScopeChain)
        scopeChain = scopeChain->copy();
682

ggaren@apple.com's avatar
ggaren@apple.com committed
683
    ExecState newExec(exec, &m_registerFile, scopeChain, -1);
684

685 686 687 688
    Profiler** profiler = Profiler::enabledProfilerReference();
    if (*profiler)
        (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());

689
    m_reentryDepth++;
ggaren@apple.com's avatar
ggaren@apple.com committed
690
    JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
691 692
    m_reentryDepth--;

kmccullough@apple.com's avatar
kmccullough@apple.com committed
693
    if (*profiler) {
694
        (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
kmccullough@apple.com's avatar
kmccullough@apple.com committed
695 696 697
        if (!m_reentryDepth)
            (*profiler)->didFinishAllExecution(exec);
    }
698

ggaren@apple.com's avatar
ggaren@apple.com committed
699 700 701 702
    if (m_reentryDepth && globalObject != lastGlobalObject)
        lastGlobalObject->copyGlobalsTo(m_registerFile);

    m_registerFile.shrink(oldSize);
703 704 705
    return result;
}

ggaren@apple.com's avatar
ggaren@apple.com committed
706
JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
707 708 709 710 711 712
{
    if (m_reentryDepth >= MaxReentryDepth) {
        *exception = createStackOverflowError(exec);
        return 0;
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
713
    int argv = RegisterFile::CallFrameHeaderSize;
714
    int argc = args.size() + 1; // implicit "this" parameter
715

ggaren@apple.com's avatar
ggaren@apple.com committed
716 717
    size_t oldSize = m_registerFile.size();
    if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
718 719 720
        *exception = createStackOverflowError(exec);
        return 0;
    }
721

ggaren@apple.com's avatar
ggaren@apple.com committed
722
    Register** registerBase = m_registerFile.basePointer();
723 724 725
    int registerOffset = oldSize;
    int callFrameOffset = registerOffset;
    Register* callFrame = (*registerBase) + callFrameOffset;
726

727
    // put args in place, including "this"
ggaren@apple.com's avatar
ggaren@apple.com committed
728
    Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
729
    (*dst).u.jsValue = thisObj;
730

darin@apple.com's avatar
darin@apple.com committed
731 732
    ArgList::const_iterator end = args.end();
    for (ArgList::const_iterator it = args.begin(); it != end; ++it)
733 734
        (*++dst).u.jsValue = *it;

ggaren@apple.com's avatar
ggaren@apple.com committed
735
    // a 0 codeBlock indicates a built-in caller
736 737 738
    initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, argv, argc, 0, function);

    CodeBlock* newCodeBlock = &functionBodyNode->code(scopeChain);
ggaren@apple.com's avatar
ggaren@apple.com committed
739
    Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, registerBase, registerOffset, argv, argc, *exception);
740
    if (*exception) {
ggaren@apple.com's avatar
ggaren@apple.com committed
741
        m_registerFile.shrink(oldSize);
742 743 744
        return 0;
    }

ap@webkit.org's avatar
ap@webkit.org committed
745
    scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, registerBase, r);
746

ggaren@apple.com's avatar
ggaren@apple.com committed
747
    ExecState newExec(exec, &m_registerFile, scopeChain, callFrameOffset);
748

749 750 751
    Profiler** profiler = Profiler::enabledProfilerReference();
    if (*profiler)
        (*profiler)->willExecute(exec, function);
752 753

    m_reentryDepth++;
ggaren@apple.com's avatar
ggaren@apple.com committed
754
    JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
755 756
    m_reentryDepth--;

kmccullough@apple.com's avatar
kmccullough@apple.com committed
757 758 759
    if (*profiler && !m_reentryDepth)
        (*profiler)->didFinishAllExecution(exec);

ggaren@apple.com's avatar
ggaren@apple.com committed
760
    m_registerFile.shrink(oldSize);
761 762 763
    return result;
}

ggaren@apple.com's avatar
ggaren@apple.com committed
764
JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
765 766 767 768 769
{
    if (m_reentryDepth >= MaxReentryDepth) {
        *exception = createStackOverflowError(exec);
        return 0;
    }
770

771
    EvalCodeBlock* codeBlock = &evalNode->code(scopeChain);
772

773 774 775 776 777 778 779 780
    JSVariableObject* variableObject;
    for (ScopeChainNode* node = scopeChain; ; node = node->next) {
        ASSERT(node);
        if (node->object->isVariableObject()) {
            variableObject = static_cast<JSVariableObject*>(node->object);
            break;
        }
    }
781

782 783 784 785
    const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
    Node::VarStack::const_iterator varStackEnd = varStack.end();
    for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
        const Identifier& ident = (*it).first;
786 787 788
        if (!variableObject->hasProperty(exec, ident))
            variableObject->put(exec, ident, jsUndefined());
    }
789

790 791 792 793
    const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
    Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
    for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it)
        variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain));
794

ggaren@apple.com's avatar
ggaren@apple.com committed
795 796 797
    size_t oldSize = m_registerFile.size();
    size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
    if (!m_registerFile.grow(newSize)) {
798 799 800 801
        *exception = createStackOverflowError(exec);
        return 0;
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
802
    Register* callFrame = *m_registerFile.basePointer() + registerOffset;
803

ggaren@apple.com's avatar
ggaren@apple.com committed
804
    // a 0 codeBlock indicates a built-in caller
805 806
    initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, 0, 0, 0, 0);

ggaren@apple.com's avatar
ggaren@apple.com committed
807 808
    Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
    r[codeBlock->thisRegister].u.jsValue = thisObj;
809 810 811 812

    if (codeBlock->needsFullScopeChain)
        scopeChain = scopeChain->copy();

ggaren@apple.com's avatar
ggaren@apple.com committed
813
    ExecState newExec(exec, &m_registerFile, scopeChain, -1);
814

815 816 817 818
    Profiler** profiler = Profiler::enabledProfilerReference();
    if (*profiler)
        (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());

819
    m_reentryDepth++;
ggaren@apple.com's avatar
ggaren@apple.com committed
820
    JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
821 822
    m_reentryDepth--;

kmccullough@apple.com's avatar
kmccullough@apple.com committed
823
    if (*profiler) {
824
        (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
kmccullough@apple.com's avatar
kmccullough@apple.com committed
825 826 827
        if (!m_reentryDepth)
            (*profiler)->didFinishAllExecution(exec);
    }
828

ggaren@apple.com's avatar
ggaren@apple.com committed
829
    m_registerFile.shrink(oldSize);
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
    return result;
}

ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
{
    scopeChain = newScopeChain;
    exec->m_scopeChain = newScopeChain;
}

NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register** registerBase, Register* r)
{
    int debugHookID = (++vPC)->u.operand;
    int firstLine = (++vPC)->u.operand;
    int lastLine = (++vPC)->u.operand;

    Debugger* debugger = exec->dynamicGlobalObject()->debugger();
    if (!debugger)
        return;

ap@webkit.org's avatar
ap@webkit.org committed
849
    DebuggerCallFrame debuggerCallFrame(exec->dynamicGlobalObject(), codeBlock, scopeChain, 0, registerBase, r - *registerBase);
850 851 852 853 854 855 856 857 858 859 860 861 862 863

    switch((DebugHookID)debugHookID) {
    case DidEnterCallFrame: {
        debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
        return;
    }
    case WillLeaveCallFrame: {
        debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
        return;
    }
    case WillExecuteStatement: {
        debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
        return;
    }
ggaren@apple.com's avatar
ggaren@apple.com committed
864
    case WillExecuteProgram: {
865
        debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
ggaren@apple.com's avatar
ggaren@apple.com committed
866 867 868
        return;
    }
    case DidExecuteProgram: {
869
        debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
ggaren@apple.com's avatar
ggaren@apple.com committed
870 871
        return;
    }
872 873 874 875
    case DidReachBreakpoint: {
        debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
        return;
    }
876 877 878
    }
}

879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
void Machine::resetTimeoutCheck()
{
    m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
    m_timeAtLastCheckTimeout = 0;
    m_timeExecuting = 0;
}

// Returns the current time in milliseconds
// It doesn't matter what "current time" is here, just as long as
// it's possible to measure the time difference correctly.
// In an ideal world this would be in DateMath or some such, but unfortunately
// that's a regression.
static inline unsigned getCurrentTime()
{
#if HAVE(SYS_TIME_H)
    struct timeval tv;
    gettimeofday(&tv, 0);
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
#elif PLATFORM(QT)
    QDateTime t = QDateTime::currentDateTime();
    return t.toTime_t() * 1000 + t.time().msec();
#elif PLATFORM(WIN_OS)
    return timeGetTime();
#else
#error Platform does not have getCurrentTime function
#endif
}

// We have to return a JSValue here, gcc seems to produce worse code if 
// we attempt to return a bool
ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
{
    unsigned currentTime = getCurrentTime();
    
    if (!m_timeAtLastCheckTimeout) {
        // Suspicious amount of looping in a script -- start timing it
        m_timeAtLastCheckTimeout = currentTime;
        return 0;
    }
    
    unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
    
    if (timeDiff == 0)
        timeDiff = 1;
    
    m_timeExecuting += timeDiff;
    m_timeAtLastCheckTimeout = currentTime;
    
    // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in 
    // preferredScriptCheckTimeInterval
    m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
    // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
    // preferred script check time interval.
    if (m_ticksUntilNextTimeoutCheck == 0)
        m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
    
    if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
        if (globalObject->shouldInterruptScript())
            return jsNull(); // Appeasing GCC, all we need is a non-null js value.
        
        resetTimeoutCheck();
    }
    
    return 0;
}
    
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
{
    // One-time initialization of our address tables. We have to put this code
    // here because our labels are only in scope inside this function.
    if (flag == InitializeAndReturn) {
        #if HAVE(COMPUTED_GOTO)
            #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
                FOR_EACH_OPCODE_ID(ADD_OPCODE);
            #undef ADD_OPCODE

            #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
                FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
            #undef ADD_OPCODE
            ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
            op_throw_end_indirect = &&op_throw_end;
            op_call_indirect = &&op_call;
        #endif // HAVE(COMPUTED_GOTO)
        return 0;
    }

    JSValue* exceptionValue = 0;
    Instruction* handlerVPC = 0;
967

ggaren@apple.com's avatar
ggaren@apple.com committed
968
    Register* registerBase = *registerFile->basePointer();
969 970
    Instruction* vPC = codeBlock->instructions.begin();
    JSValue** k = codeBlock->jsValues.data();
971
    Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
972 973
    unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;

974 975 976 977 978 979 980 981
#define VM_CHECK_EXCEPTION() \
     do { \
        if (UNLIKELY(exec->hadException())) { \
            exceptionValue = exec->exception(); \
            goto vm_throw; \
        } \
    } while (0)

982 983 984
#if DUMP_OPCODE_STATS
    OpcodeStats::resetLastInstruction();
#endif
985

986 987 988 989 990 991 992
#define CHECK_FOR_TIMEOUT() \
    if (!--tickCount) { \
        if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
            goto vm_throw; \
        tickCount = m_ticksUntilNextTimeoutCheck; \
    }
    
993 994
#if HAVE(COMPUTED_GOTO)
    #define NEXT_OPCODE goto *vPC->u.opcode
995 996 997
#if DUMP_OPCODE_STATS
    #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
#else
998
    #define BEGIN_OPCODE(opcode) opcode:
999
#endif
1000 1001 1002
    NEXT_OPCODE;
#else
    #define NEXT_OPCODE continue
1003 1004 1005
#if DUMP_OPCODE_STATS
    #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
#else
1006
    #define BEGIN_OPCODE(opcode) case opcode:
1007
#endif
1008
    while (1) // iterator loop begins
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
    switch (vPC->u.opcode)
#endif
    {
    BEGIN_OPCODE(op_load) {
        /* load dst(r) src(k)

           Copies constant src to register dst.
        */
        int dst = (++vPC)->u.operand;
        int src = (++vPC)->u.operand;
        r[dst].u.jsValue = k[src];
1020

1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
        ++vPC;
        NEXT_OPCODE;
    }
    BEGIN_OPCODE(op_new_object) {
        /* new_object dst(r)

           Constructs a new empty Object instance using the original
           constructor, and puts the result in register dst.
        */
        int dst = (++vPC)->u.operand;
darin@apple.com's avatar
darin@apple.com committed
1031
        r[dst].u.jsValue = constructEmptyObject(exec);
1032

1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
        ++vPC;
        NEXT_OPCODE;
    }
    BEGIN_OPCODE(op_new_array) {
        /* new_array dst(r)

           Constructs a new empty Array instance using the original
           constructor, and puts the result in register dst.
        */
        int dst = (++vPC)->u.operand;
darin@apple.com's avatar
darin@apple.com committed
1043
        r[dst].u.jsValue = constructEmptyArray(exec);
1044

1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
        ++vPC;
        NEXT_OPCODE;
    }
    BEGIN_OPCODE(op_new_regexp) {
        /* new_regexp dst(r) regExp(re)

           Constructs a new RegExp instance using the original
           constructor from regexp regExp, and puts the result in
           register dst.
        */
        int dst = (++vPC)->u.operand;
        int regExp = (++vPC)->u.operand;
ap@webkit.org's avatar
ap@webkit.org committed
1057
        r[dst].u.jsValue = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1058 1059 1060 1061 1062 1063 1064 10