CodeBlock.cpp 127 KB
Newer Older
1
/*
2
 * Copyright (C) 2008, 2009, 2010, 2012, 2013 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 31 32
 * 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 "CodeBlock.h"

33
#include "BytecodeGenerator.h"
34
#include "CallLinkStatus.h"
35
#include "DFGCapabilities.h"
36
#include "DFGCommon.h"
37
#include "DFGDriver.h"
38
#include "DFGNode.h"
39
#include "DFGRepatch.h"
40
#include "DFGWorklist.h"
41
#include "Debugger.h"
ggaren@apple.com's avatar
ggaren@apple.com committed
42
#include "Interpreter.h"
43
#include "JIT.h"
44
#include "JITStubs.h"
45
#include "JSActivation.h"
46
#include "JSCJSValue.h"
47
#include "JSFunction.h"
48
#include "JSNameScope.h"
49
#include "LowLevelInterpreter.h"
50
#include "Operations.h"
51
#include "PolymorphicPutByIdList.h"
52
#include "ReduceWhitespace.h"
53
#include "RepatchBuffer.h"
54
#include "SlotVisitorInlines.h"
55
#include <stdio.h>
56
#include <wtf/CommaPrinter.h>
aroben@apple.com's avatar
aroben@apple.com committed
57
#include <wtf/StringExtras.h>
58
#include <wtf/StringPrintStream.h>
59

60 61 62 63
#if ENABLE(DFG_JIT)
#include "DFGOperations.h"
#endif

64 65 66 67
#if ENABLE(FTL_JIT)
#include "FTLJITCode.h"
#endif

68 69
#define DUMP_CODE_BLOCK_STATISTICS 0

70
namespace JSC {
71

72
CString CodeBlock::inferredName() const
73 74 75 76 77 78 79
{
    switch (codeType()) {
    case GlobalCode:
        return "<global>";
    case EvalCode:
        return "<eval>";
    case FunctionCode:
80
        return jsCast<FunctionExecutable*>(ownerExecutable())->inferredName().utf8();
81 82
    default:
        CRASH();
83
        return CString("", 0);
84 85 86
    }
}

87 88 89 90 91 92 93 94 95 96
bool CodeBlock::hasHash() const
{
    return !!m_hash;
}

bool CodeBlock::isSafeToComputeHash() const
{
    return !isCompilationThread();
}

97 98
CodeBlockHash CodeBlock::hash() const
{
99
    if (!m_hash) {
100
        RELEASE_ASSERT(isSafeToComputeHash());
101 102 103
        m_hash = CodeBlockHash(ownerExecutable()->source(), specializationKind());
    }
    return m_hash;
104 105
}

106
CString CodeBlock::sourceCodeForTools() const
107 108
{
    if (codeType() != FunctionCode)
109
        return ownerExecutable()->source().toUTF8();
110 111 112 113 114 115 116
    
    SourceProvider* provider = source();
    FunctionExecutable* executable = jsCast<FunctionExecutable*>(ownerExecutable());
    UnlinkedFunctionExecutable* unlinked = executable->unlinkedExecutable();
    unsigned unlinkedStartOffset = unlinked->startOffset();
    unsigned linkedStartOffset = executable->source().startOffset();
    int delta = linkedStartOffset - unlinkedStartOffset;
117 118 119 120 121
    unsigned rangeStart = delta + unlinked->functionStartOffset();
    unsigned rangeEnd = delta + unlinked->startOffset() + unlinked->sourceLength();
    return toCString(
        "function ",
        provider->source().impl()->utf8ForRange(rangeStart, rangeEnd - rangeStart));
122 123
}

124
CString CodeBlock::sourceCodeOnOneLine() const
125 126 127 128
{
    return reduceWhitespace(sourceCodeForTools());
}

129 130
void CodeBlock::dumpAssumingJITType(PrintStream& out, JITCode::JITType jitType) const
{
131 132 133 134 135
    if (hasHash() || isSafeToComputeHash())
        out.print(inferredName(), "#", hash(), ":[", RawPointer(this), "->", RawPointer(ownerExecutable()), ", ", jitType, codeType());
    else
        out.print(inferredName(), "#<no-hash>:[", RawPointer(this), "->", RawPointer(ownerExecutable()), ", ", jitType, codeType());

136 137
    if (codeType() == FunctionCode)
        out.print(specializationKind());
138
    if (this->jitType() == JITCode::BaselineJIT && m_shouldAlwaysBeInlined)
139
        out.print(" (SABI)");
140 141
    if (ownerExecutable()->neverInline())
        out.print(" (NeverInline)");
142 143
    if (ownerExecutable()->isStrictMode())
        out.print(" (StrictMode)");
144 145 146 147 148
    out.print("]");
}

void CodeBlock::dump(PrintStream& out) const
{
149
    dumpAssumingJITType(out, jitType());
150 151
}

152
static CString constantName(int k, JSValue value)
153
{
154
    return toCString(value, "(@k", k - FirstConstantRegisterIndex, ")");
155 156 157 158
}

static CString idName(int id0, const Identifier& ident)
{
159
    return toCString(ident.impl(), "(@id", id0, ")");
160 161
}

162
CString CodeBlock::registerName(int r) const
163 164 165 166 167
{
    if (r == missingThisObjectMarker())
        return "<null>";

    if (isConstantRegisterIndex(r))
168
        return constantName(r, getConstant(r));
169

170
    if (operandIsArgument(r)) {
171
        if (!operandToArgument(r))
172
            return "this";
173
        return toCString("arg", operandToArgument(r));
174 175
    }

176
    return toCString("loc", operandToLocal(r));
177 178
}

179
static CString regexpToSourceString(RegExp* regExp)
180 181 182 183 184 185 186 187 188 189
{
    char postfix[5] = { '/', 0, 0, 0, 0 };
    int index = 1;
    if (regExp->global())
        postfix[index++] = 'g';
    if (regExp->ignoreCase())
        postfix[index++] = 'i';
    if (regExp->multiline())
        postfix[index] = 'm';

190
    return toCString("/", regExp->pattern().impl(), postfix);
191 192 193 194
}

static CString regexpName(int re, RegExp* regexp)
{
195
    return toCString(regexpToSourceString(regexp), "(@re", re, ")");
196 197
}

ggaren@apple.com's avatar
ggaren@apple.com committed
198
NEVER_INLINE static const char* debugHookName(int debugHookID)
199
{
200 201 202 203 204 205 206 207 208 209 210 211 212
    switch (static_cast<DebugHookID>(debugHookID)) {
        case DidEnterCallFrame:
            return "didEnterCallFrame";
        case WillLeaveCallFrame:
            return "willLeaveCallFrame";
        case WillExecuteStatement:
            return "willExecuteStatement";
        case WillExecuteProgram:
            return "willExecuteProgram";
        case DidExecuteProgram:
            return "didExecuteProgram";
        case DidReachBreakpoint:
            return "didReachBreakpoint";
213
    }
214

215
    RELEASE_ASSERT_NOT_REACHED();
ggaren@apple.com's avatar
ggaren@apple.com committed
216
    return "";
217 218
}

219
void CodeBlock::printUnaryOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op)
220 221 222 223
{
    int r0 = (++it)->u.operand;
    int r1 = (++it)->u.operand;

224 225
    printLocationAndOp(out, exec, location, it, op);
    out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
226 227
}

228
void CodeBlock::printBinaryOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op)
229 230 231 232
{
    int r0 = (++it)->u.operand;
    int r1 = (++it)->u.operand;
    int r2 = (++it)->u.operand;
233 234
    printLocationAndOp(out, exec, location, it, op);
    out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
235 236
}

237
void CodeBlock::printConditionalJump(PrintStream& out, ExecState* exec, const Instruction*, const Instruction*& it, int location, const char* op)
238 239 240
{
    int r0 = (++it)->u.operand;
    int offset = (++it)->u.operand;
241 242
    printLocationAndOp(out, exec, location, it, op);
    out.printf("%s, %d(->%d)", registerName(r0).data(), offset, location + offset);
243 244
}

245
void CodeBlock::printGetByIdOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it)
weinig@apple.com's avatar
weinig@apple.com committed
246
{
247 248 249 250 251
    const char* op;
    switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
    case op_get_by_id:
        op = "get_by_id";
        break;
252 253 254
    case op_get_by_id_out_of_line:
        op = "get_by_id_out_of_line";
        break;
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    case op_get_by_id_self:
        op = "get_by_id_self";
        break;
    case op_get_by_id_proto:
        op = "get_by_id_proto";
        break;
    case op_get_by_id_chain:
        op = "get_by_id_chain";
        break;
    case op_get_by_id_getter_self:
        op = "get_by_id_getter_self";
        break;
    case op_get_by_id_getter_proto:
        op = "get_by_id_getter_proto";
        break;
    case op_get_by_id_getter_chain:
        op = "get_by_id_getter_chain";
        break;
    case op_get_by_id_custom_self:
        op = "get_by_id_custom_self";
        break;
    case op_get_by_id_custom_proto:
        op = "get_by_id_custom_proto";
        break;
    case op_get_by_id_custom_chain:
        op = "get_by_id_custom_chain";
        break;
    case op_get_by_id_generic:
        op = "get_by_id_generic";
        break;
    case op_get_array_length:
        op = "array_length";
        break;
    case op_get_string_length:
        op = "string_length";
        break;
    default:
292
        RELEASE_ASSERT_NOT_REACHED();
293 294
        op = 0;
    }
weinig@apple.com's avatar
weinig@apple.com committed
295 296 297
    int r0 = (++it)->u.operand;
    int r1 = (++it)->u.operand;
    int id0 = (++it)->u.operand;
298 299
    printLocationAndOp(out, exec, location, it, op);
    out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
300
    it += 4; // Increment up to the value profiler.
weinig@apple.com's avatar
weinig@apple.com committed
301 302
}

303
#if ENABLE(JIT) || ENABLE(LLINT) // unused in some configurations
304
static void dumpStructure(PrintStream& out, const char* name, ExecState* exec, Structure* structure, const Identifier& ident)
305 306 307 308
{
    if (!structure)
        return;
    
309
    out.printf("%s = %p", name, structure);
310
    
311
    PropertyOffset offset = structure->getConcurrently(exec->vm(), ident.impl());
312
    if (offset != invalidOffset)
313
        out.printf(" (offset = %d)", offset);
314
}
315
#endif
316

317
#if ENABLE(JIT) // unused when not ENABLE(JIT), leading to silly warnings
318
static void dumpChain(PrintStream& out, ExecState* exec, StructureChain* chain, const Identifier& ident)
319
{
320
    out.printf("chain = %p: [", chain);
321 322 323 324 325 326 327
    bool first = true;
    for (WriteBarrier<Structure>* currentStructure = chain->head();
         *currentStructure;
         ++currentStructure) {
        if (first)
            first = false;
        else
328
            out.printf(", ");
329
        dumpStructure(out, "struct", exec, currentStructure->get(), ident);
330
    }
331
    out.printf("]");
332
}
333
#endif
334

335
void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int location)
336 337 338
{
    Instruction* instruction = instructions().begin() + location;

339
    const Identifier& ident = identifier(instruction[3].u.operand);
340
    
341 342
    UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
    
343
#if ENABLE(LLINT)
344
    if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_get_array_length)
345
        out.printf(" llint(array_length)");
346
    else if (Structure* structure = instruction[4].u.structure.get()) {
347 348 349
        out.printf(" llint(");
        dumpStructure(out, "struct", exec, structure, ident);
        out.printf(")");
350
    }
351 352 353 354 355
#endif

#if ENABLE(JIT)
    if (numberOfStructureStubInfos()) {
        StructureStubInfo& stubInfo = getStubInfo(location);
356 357 358
        if (stubInfo.seen) {
            out.printf(" jit(");
            
359 360 361 362 363 364 365 366
            Structure* baseStructure = 0;
            Structure* prototypeStructure = 0;
            StructureChain* chain = 0;
            PolymorphicAccessStructureList* structureList = 0;
            int listSize = 0;
            
            switch (stubInfo.accessType) {
            case access_get_by_id_self:
367
                out.printf("self");
368 369 370
                baseStructure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
                break;
            case access_get_by_id_proto:
371
                out.printf("proto");
372 373 374 375
                baseStructure = stubInfo.u.getByIdProto.baseObjectStructure.get();
                prototypeStructure = stubInfo.u.getByIdProto.prototypeStructure.get();
                break;
            case access_get_by_id_chain:
376
                out.printf("chain");
377 378 379 380
                baseStructure = stubInfo.u.getByIdChain.baseObjectStructure.get();
                chain = stubInfo.u.getByIdChain.chain.get();
                break;
            case access_get_by_id_self_list:
381
                out.printf("self_list");
382 383 384 385
                structureList = stubInfo.u.getByIdSelfList.structureList;
                listSize = stubInfo.u.getByIdSelfList.listSize;
                break;
            case access_get_by_id_proto_list:
386
                out.printf("proto_list");
387 388 389 390
                structureList = stubInfo.u.getByIdProtoList.structureList;
                listSize = stubInfo.u.getByIdProtoList.listSize;
                break;
            case access_unset:
391
                out.printf("unset");
392 393
                break;
            case access_get_by_id_generic:
394
                out.printf("generic");
395 396
                break;
            case access_get_array_length:
397
                out.printf("array_length");
398 399
                break;
            case access_get_string_length:
400
                out.printf("string_length");
401 402
                break;
            default:
403
                RELEASE_ASSERT_NOT_REACHED();
404 405 406 407
                break;
            }
            
            if (baseStructure) {
408 409
                out.printf(", ");
                dumpStructure(out, "struct", exec, baseStructure, ident);
410 411 412
            }
            
            if (prototypeStructure) {
413 414
                out.printf(", ");
                dumpStructure(out, "prototypeStruct", exec, baseStructure, ident);
415 416 417
            }
            
            if (chain) {
418 419
                out.printf(", ");
                dumpChain(out, exec, chain, ident);
420 421 422
            }
            
            if (structureList) {
423
                out.printf(", list = %p: [", structureList);
424 425
                for (int i = 0; i < listSize; ++i) {
                    if (i)
426 427 428
                        out.printf(", ");
                    out.printf("(");
                    dumpStructure(out, "base", exec, structureList->list[i].base.get(), ident);
429 430
                    if (structureList->list[i].isChain) {
                        if (structureList->list[i].u.chain.get()) {
431 432
                            out.printf(", ");
                            dumpChain(out, exec, structureList->list[i].u.chain.get(), ident);
433 434 435
                        }
                    } else {
                        if (structureList->list[i].u.proto.get()) {
436 437
                            out.printf(", ");
                            dumpStructure(out, "proto", exec, structureList->list[i].u.proto.get(), ident);
438 439
                        }
                    }
440
                    out.printf(")");
441
                }
442
                out.printf("]");
443
            }
444
            out.printf(")");
445 446 447 448 449
        }
    }
#endif
}

450
void CodeBlock::printCallOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op, CacheDumpMode cacheDumpMode, bool& hasPrintedProfiling)
451
{
452
    int dst = (++it)->u.operand;
453 454 455
    int func = (++it)->u.operand;
    int argCount = (++it)->u.operand;
    int registerOffset = (++it)->u.operand;
456 457
    printLocationAndOp(out, exec, location, it, op);
    out.printf("%s, %s, %d, %d", registerName(dst).data(), registerName(func).data(), argCount, registerOffset);
458 459 460 461
    if (cacheDumpMode == DumpCaches) {
#if ENABLE(LLINT)
        LLIntCallLinkInfo* callLinkInfo = it[1].u.callLinkInfo;
        if (callLinkInfo->lastSeenCallee) {
462 463 464 465
            out.printf(
                " llint(%p, exec %p)",
                callLinkInfo->lastSeenCallee.get(),
                callLinkInfo->lastSeenCallee->executable());
466
        }
467 468
#endif
#if ENABLE(JIT)
469 470 471
        if (numberOfCallLinkInfos()) {
            JSFunction* target = getCallLinkInfo(location).lastSeenCallee.get();
            if (target)
472
                out.printf(" jit(%p, exec %p)", target, target->executable());
473
        }
474
#endif
475
        out.print(" status(", CallLinkStatus::computeFor(this, location), ")");
476
    }
477 478 479
    ++it;
    dumpArrayProfiling(out, it, hasPrintedProfiling);
    dumpValueProfiling(out, it, hasPrintedProfiling);
480 481
}

482
void CodeBlock::printPutByIdOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op)
weinig@apple.com's avatar
weinig@apple.com committed
483 484 485 486
{
    int r0 = (++it)->u.operand;
    int id0 = (++it)->u.operand;
    int r1 = (++it)->u.operand;
487 488
    printLocationAndOp(out, exec, location, it, op);
    out.printf("%s, %s, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data());
489
    it += 5;
weinig@apple.com's avatar
weinig@apple.com committed
490 491
}

492
void CodeBlock::dumpBytecode(PrintStream& out)
493
{
494 495 496 497
    // We only use the ExecState* for things that don't actually lead to JS execution,
    // like converting a JSString to a String. Hence the globalExec is appropriate.
    ExecState* exec = m_globalObject->globalExec();
    
498
    size_t instructionCount = 0;
499

500
    for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)])
501
        ++instructionCount;
502

503 504
    out.print(*this);
    out.printf(
505
        ": %lu m_instructions; %lu bytes; %d parameter(s); %d callee register(s); %d variable(s)",
506
        static_cast<unsigned long>(instructions().size()),
507
        static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
508
        m_numParameters, m_numCalleeRegisters, m_numVars);
509 510 511
    if (symbolTable() && symbolTable()->captureCount()) {
        out.printf(
            "; %d captured var(s) (from r%d to r%d, inclusive)",
512
            symbolTable()->captureCount(), symbolTable()->captureStart(), symbolTable()->captureEnd() + 1);
513
    }
514
    if (usesArguments()) {
515
        out.printf(
516
            "; uses arguments, in r%d, r%d",
517 518
            argumentsRegister(),
            unmodifiedArgumentsRegister(argumentsRegister()));
519 520
    }
    if (needsFullScopeChain() && codeType() == FunctionCode)
521
        out.printf("; activation in r%d", activationRegister());
522 523
    out.printf("\n");
    
524 525 526
    const Instruction* begin = instructions().begin();
    const Instruction* end = instructions().end();
    for (const Instruction* it = begin; it != end; ++it)
527
        dumpBytecode(out, exec, begin, it);
528

529
    if (numberOfIdentifiers()) {
530
        out.printf("\nIdentifiers:\n");
531 532
        size_t i = 0;
        do {
533
            out.printf("  id%u = %s\n", static_cast<unsigned>(i), identifier(i).string().utf8().data());
534
            ++i;
535
        } while (i != numberOfIdentifiers());
536 537
    }

538
    if (!m_constantRegisters.isEmpty()) {
539
        out.printf("\nConstants:\n");
540 541
        size_t i = 0;
        do {
542
            out.printf("   k%u = %s\n", static_cast<unsigned>(i), toCString(m_constantRegisters[i].get()).data());
543
            ++i;
544
        } while (i < m_constantRegisters.size());
545 546
    }

547
    if (size_t count = m_unlinkedCode->numberOfRegExps()) {
548
        out.printf("\nm_regexps:\n");
549 550
        size_t i = 0;
        do {
551
            out.printf("  re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_unlinkedCode->regexp(i)).data());
552
            ++i;
553
        } while (i < count);
554 555
    }

556
#if ENABLE(JIT)
557
    if (!m_structureStubInfos.isEmpty())
558
        out.printf("\nStructures:\n");
559
#endif
560

561
    if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
562
        out.printf("\nException Handlers:\n");
563 564
        unsigned i = 0;
        do {
565
            out.printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] depth: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target, m_rareData->m_exceptionHandlers[i].scopeDepth);
566
            ++i;
567
        } while (i < m_rareData->m_exceptionHandlers.size());
568
    }
oliver@apple.com's avatar
oliver@apple.com committed
569
    
570 571
    if (m_rareData && !m_rareData->m_switchJumpTables.isEmpty()) {
        out.printf("Switch Jump Tables:\n");
oliver@apple.com's avatar
oliver@apple.com committed
572 573
        unsigned i = 0;
        do {
574
            out.printf("  %1d = {\n", i);
oliver@apple.com's avatar
oliver@apple.com committed
575
            int entry = 0;
576 577
            Vector<int32_t>::const_iterator end = m_rareData->m_switchJumpTables[i].branchOffsets.end();
            for (Vector<int32_t>::const_iterator iter = m_rareData->m_switchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
weinig@apple.com's avatar
weinig@apple.com committed
578 579
                if (!*iter)
                    continue;
580
                out.printf("\t\t%4d => %04d\n", entry + m_rareData->m_switchJumpTables[i].min, *iter);
weinig@apple.com's avatar
weinig@apple.com committed
581
            }
582
            out.printf("      }\n");
oliver@apple.com's avatar
oliver@apple.com committed
583
            ++i;
584
        } while (i < m_rareData->m_switchJumpTables.size());
oliver@apple.com's avatar
oliver@apple.com committed
585 586
    }
    
587
    if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
588
        out.printf("\nString Switch Jump Tables:\n");
oliver@apple.com's avatar
oliver@apple.com committed
589 590
        unsigned i = 0;
        do {
591
            out.printf("  %1d = {\n", i);
592 593
            StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
            for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
594 595
                out.printf("\t\t\"%s\" => %04d\n", String(iter->key).utf8().data(), iter->value.branchOffset);
            out.printf("      }\n");
oliver@apple.com's avatar
oliver@apple.com committed
596
            ++i;
597
        } while (i < m_rareData->m_stringSwitchJumpTables.size());
oliver@apple.com's avatar
oliver@apple.com committed
598 599
    }

600
    out.printf("\n");
601 602
}

603 604 605 606 607 608 609 610 611 612 613 614
void CodeBlock::beginDumpProfiling(PrintStream& out, bool& hasPrintedProfiling)
{
    if (hasPrintedProfiling) {
        out.print("; ");
        return;
    }
    
    out.print("    ");
    hasPrintedProfiling = true;
}

void CodeBlock::dumpValueProfiling(PrintStream& out, const Instruction*& it, bool& hasPrintedProfiling)
615
{
616
    ConcurrentJITLocker locker(m_lock);
617
    
618 619
    ++it;
#if ENABLE(VALUE_PROFILER)
620
    CString description = it->u.profile->briefDescription(locker);
621 622
    if (!description.length())
        return;
623 624
    beginDumpProfiling(out, hasPrintedProfiling);
    out.print(description);
625 626
#else
    UNUSED_PARAM(out);
627
    UNUSED_PARAM(hasPrintedProfiling);
628 629 630
#endif
}

631
void CodeBlock::dumpArrayProfiling(PrintStream& out, const Instruction*& it, bool& hasPrintedProfiling)
632
{
633
    ConcurrentJITLocker locker(m_lock);
634
    
635 636
    ++it;
#if ENABLE(VALUE_PROFILER)
637 638
    if (!it->u.arrayProfile)
        return;
639
    CString description = it->u.arrayProfile->briefDescription(locker, this);
640 641
    if (!description.length())
        return;
642 643
    beginDumpProfiling(out, hasPrintedProfiling);
    out.print(description);
644 645
#else
    UNUSED_PARAM(out);
646
    UNUSED_PARAM(hasPrintedProfiling);
647 648 649
#endif
}

650 651 652 653 654 655 656 657 658 659 660
#if ENABLE(VALUE_PROFILER)
void CodeBlock::dumpRareCaseProfile(PrintStream& out, const char* name, RareCaseProfile* profile, bool& hasPrintedProfiling)
{
    if (!profile || !profile->m_counter)
        return;

    beginDumpProfiling(out, hasPrintedProfiling);
    out.print(name, profile->m_counter);
}
#endif

661
void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instruction* begin, const Instruction*& it)
662 663
{
    int location = it - begin;
664
    bool hasPrintedProfiling = false;
665
    switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
mjs@apple.com's avatar
mjs@apple.com committed
666
        case op_enter: {
667
            printLocationAndOp(out, exec, location, it, "enter");
668 669
            break;
        }
670
        case op_create_activation: {
671
            int r0 = (++it)->u.operand;
672
            printLocationOpAndRegisterOperand(out, exec, location, it, "create_activation", r0);
673 674
            break;
        }
675
        case op_create_arguments: {
676
            int r0 = (++it)->u.operand;
677
            printLocationOpAndRegisterOperand(out, exec, location, it, "create_arguments", r0);
678 679
            break;
        }
680
        case op_init_lazy_reg: {
681
            int r0 = (++it)->u.operand;
682
            printLocationOpAndRegisterOperand(out, exec, location, it, "init_lazy_reg", r0);
683 684
            break;
        }
685 686
        case op_get_callee: {
            int r0 = (++it)->u.operand;
687
            printLocationOpAndRegisterOperand(out, exec, location, it, "get_callee", r0);
688
            ++it;
689 690
            break;
        }
barraclough@apple.com's avatar
barraclough@apple.com committed
691 692
        case op_create_this: {
            int r0 = (++it)->u.operand;
693
            int r1 = (++it)->u.operand;
694
            unsigned inferredInlineCapacity = (++it)->u.operand;
695 696
            printLocationAndOp(out, exec, location, it, "create_this");
            out.printf("%s, %s, %u", registerName(r0).data(), registerName(r1).data(), inferredInlineCapacity);
barraclough@apple.com's avatar
barraclough@apple.com committed
697 698
            break;
        }
699
        case op_to_this: {
mjs@apple.com's avatar
mjs@apple.com committed
700
            int r0 = (++it)->u.operand;
701
            printLocationOpAndRegisterOperand(out, exec, location, it, "to_this", r0);
702
            ++it; // Skip value profile.
mjs@apple.com's avatar
mjs@apple.com committed
703 704
            break;
        }
705 706
        case op_new_object: {
            int r0 = (++it)->u.operand;
707
            unsigned inferredInlineCapacity = (++it)->u.operand;
708 709
            printLocationAndOp(out, exec, location, it, "new_object");
            out.printf("%s, %u", registerName(r0).data(), inferredInlineCapacity);
710
            ++it; // Skip object allocation profile.
711 712 713
            break;
        }
        case op_new_array: {
714 715 716
            int dst = (++it)->u.operand;
            int argv = (++it)->u.operand;
            int argc = (++it)->u.operand;
717 718
            printLocationAndOp(out, exec, location, it, "new_array");
            out.printf("%s, %s, %d", registerName(dst).data(), registerName(argv).data(), argc);
719
            ++it; // Skip array allocation profile.
720 721
            break;
        }
722 723 724
        case op_new_array_with_size: {
            int dst = (++it)->u.operand;
            int length = (++it)->u.operand;
725 726
            printLocationAndOp(out, exec, location, it, "new_array_with_size");
            out.printf("%s, %s", registerName(dst).data(), registerName(length).data());
727
            ++it; // Skip array allocation profile.
728 729
            break;
        }
730 731 732 733
        case op_new_array_buffer: {
            int dst = (++it)->u.operand;
            int argv = (++it)->u.operand;
            int argc = (++it)->u.operand;
734 735
            printLocationAndOp(out, exec, location, it, "new_array_buffer");
            out.printf("%s, %d, %d", registerName(dst).data(), argv, argc);
736
            ++it; // Skip array allocation profile.
737 738
            break;
        }
739 740 741
        case op_new_regexp: {
            int r0 = (++it)->u.operand;
            int re0 = (++it)->u.operand;
742 743
            printLocationAndOp(out, exec, location, it, "new_regexp");
            out.printf("%s, ", registerName(r0).data());
744
            if (r0 >=0 && r0 < (int)m_unlinkedCode->numberOfRegExps())
745
                out.printf("%s", regexpName(re0, regexp(re0)).data());
746
            else
747
                out.printf("bad_regexp(%d)", re0);
748 749
            break;
        }
750 751 752
        case op_mov: {
            int r0 = (++it)->u.operand;
            int r1 = (++it)->u.operand;
753 754
            printLocationAndOp(out, exec, location, it, "mov");
            out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
755 756 757
            break;
        }
        case op_not: {
758
            printUnaryOp(out, exec, location, it, "not");
759 760 761
            break;
        }
        case op_eq: {
762
            printBinaryOp(out, exec, location, it, "eq");
763 764
            break;
        }
765
        case op_eq_null: {
766
            printUnaryOp(out, exec, location, it, "eq_null");
767 768
            break;
        }
769
        case op_neq: {
770
            printBinaryOp(out, exec, location, it, "neq");
771 772
            break;
        }
773
        case op_neq_null: {
774
            printUnaryOp(out, exec, location, it, "neq_null");
775 776
            break;
        }
777
        case op_stricteq: {