Ignore:
Timestamp:
Dec 12, 2008, 12:02:09 AM (16 years ago)
Author:
[email protected]
Message:

2008-12-11 Sam Weinig <[email protected]>

Reviewed by Geoffrey Garen.

Remove dependancy on having the Instruction buffer in order to
deref Structures used for property access and global resolves.
Instead, we put references to the necessary Structures in axillary
data structures on the CodeBlock. This is not an ideal solution,
as we still pay for having the Structures in two places and we
would like to eventually just hold on to offsets into the machine
code buffer.

  • Also removes CodeBlock bloat in non-JIT by #ifdefing the JIT only data structures.
  • GNUmakefile.am:
  • JavaScriptCore.pri:
  • JavaScriptCore.scons:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • bytecode/CodeBlock.cpp: (JSC::isGlobalResolve): (JSC::isPropertyAccess): (JSC::instructionOffsetForNth): (JSC::printGlobalResolveInfo): (JSC::printStructureStubInfo): (JSC::CodeBlock::printStructures): (JSC::CodeBlock::dump): (JSC::CodeBlock::~CodeBlock): (JSC::CodeBlock::shrinkToFit):
  • bytecode/CodeBlock.h: (JSC::GlobalResolveInfo::GlobalResolveInfo): (JSC::getNativePC): (JSC::CodeBlock::instructions): (JSC::CodeBlock::getStubInfo): (JSC::CodeBlock::getBytecodeIndex): (JSC::CodeBlock::addPropertyAccessInstruction): (JSC::CodeBlock::addGlobalResolveInstruction): (JSC::CodeBlock::numberOfStructureStubInfos): (JSC::CodeBlock::addStructureStubInfo): (JSC::CodeBlock::structureStubInfo): (JSC::CodeBlock::addGlobalResolveInfo): (JSC::CodeBlock::globalResolveInfo): (JSC::CodeBlock::numberOfCallLinkInfos): (JSC::CodeBlock::addCallLinkInfo): (JSC::CodeBlock::callLinkInfo):
  • bytecode/Instruction.h: (JSC::PolymorphicAccessStructureList::PolymorphicStubInfo::set): (JSC::PolymorphicAccessStructureList::PolymorphicAccessStructureList):
  • bytecode/Opcode.h: (JSC::):
  • bytecode/StructureStubInfo.cpp: Copied from bytecode/CodeBlock.cpp. (JSC::StructureStubInfo::deref):
  • bytecode/StructureStubInfo.h: Copied from bytecode/CodeBlock.h. (JSC::StructureStubInfo::StructureStubInfo): (JSC::StructureStubInfo::initGetByIdSelf): (JSC::StructureStubInfo::initGetByIdProto): (JSC::StructureStubInfo::initGetByIdChain): (JSC::StructureStubInfo::initGetByIdSelfList): (JSC::StructureStubInfo::initGetByIdProtoList): (JSC::StructureStubInfo::initPutByIdTransition): (JSC::StructureStubInfo::initPutByIdReplace): (JSC::StructureStubInfo::):
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitResolve): (JSC::BytecodeGenerator::emitGetById): (JSC::BytecodeGenerator::emitPutById): (JSC::BytecodeGenerator::emitCall): (JSC::BytecodeGenerator::emitConstruct): (JSC::BytecodeGenerator::emitCatch):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::tryCTICachePutByID): (JSC::Interpreter::tryCTICacheGetByID): (JSC::Interpreter::cti_op_get_by_id_self_fail): (JSC::getPolymorphicAccessStructureListSlot): (JSC::Interpreter::cti_op_get_by_id_proto_list): (JSC::Interpreter::cti_op_resolve_global):
  • jit/JIT.cpp: (JSC::JIT::JIT): (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases): (JSC::JIT::privateCompile):
  • jit/JITPropertyAccess.cpp: (JSC::JIT::compileGetByIdHotPath): (JSC::JIT::compilePutByIdHotPath): (JSC::JIT::compileGetByIdSlowCase): (JSC::JIT::compilePutByIdSlowCase): (JSC::JIT::privateCompileGetByIdSelfList): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChainList):
File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/bytecode/StructureStubInfo.cpp

    r39218 r39229  
    11/*
    22 * Copyright (C) 2008 Apple Inc. All rights reserved.
    3  * Copyright (C) 2008 Cameron Zwarich <[email protected]>
    43 *
    54 * Redistribution and use in source and binary forms, with or without
    65 * modification, are permitted provided that the following conditions
    76 * are met:
     7 * 1. Redistributions of source code must retain the above copyright
     8 *    notice, this list of conditions and the following disclaimer.
     9 * 2. Redistributions in binary form must reproduce the above copyright
     10 *    notice, this list of conditions and the following disclaimer in the
     11 *    documentation and/or other materials provided with the distribution.
    812 *
    9  * 1.  Redistributions of source code must retain the above copyright
    10  *     notice, this list of conditions and the following disclaimer.
    11  * 2.  Redistributions in binary form must reproduce the above copyright
    12  *     notice, this list of conditions and the following disclaimer in the
    13  *     documentation and/or other materials provided with the distribution.
    14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
    15  *     its contributors may be used to endorse or promote products derived
    16  *     from this software without specific prior written permission.
    17  *
    18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
    19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
    22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2824 */
    2925
    3026#include "config.h"
    31 #include "CodeBlock.h"
    32 
    33 #include "JIT.h"
    34 #include "JSValue.h"
    35 #include "Interpreter.h"
    36 #include "Debugger.h"
    37 #include <stdio.h>
    38 #include <wtf/StringExtras.h>
    39 
    40 #define DUMP_CODE_BLOCK_STATISTICS 0
     27#include "StructureStubInfo.h"
    4128
    4229namespace JSC {
    4330
    44 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
    45 
    46 static UString escapeQuotes(const UString& str)
     31#if ENABLE(JIT)
     32void StructureStubInfo::deref()
    4733{
    48     UString result = str;
    49     int pos = 0;
    50     while ((pos = result.find('\"', pos)) >= 0) {
    51         result = result.substr(0, pos) + "\"\\\"\"" + result.substr(pos + 1);
    52         pos += 4;
    53     }
    54     return result;
    55 }
    56 
    57 static UString valueToSourceString(ExecState* exec, JSValue* val)
    58 {
    59     if (val->isString()) {
    60         UString result("\"");
    61         result += escapeQuotes(val->toString(exec)) + "\"";
    62         return result;
    63     }
    64 
    65     return val->toString(exec);
    66 }
    67 
    68 static CString registerName(int r)
    69 {
    70     if (r == missingThisObjectMarker())
    71         return "<null>";
    72 
    73     return (UString("r") + UString::from(r)).UTF8String();
    74 }
    75 
    76 static CString constantName(ExecState* exec, int k, JSValue* value)
    77 {
    78     return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String();
    79 }
    80 
    81 static CString idName(int id0, const Identifier& ident)
    82 {
    83     return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String();
    84 }
    85 
    86 static UString regexpToSourceString(RegExp* regExp)
    87 {
    88     UString pattern = UString("/") + regExp->pattern() + "/";
    89     if (regExp->global())
    90         pattern += "g";
    91     if (regExp->ignoreCase())
    92         pattern += "i";
    93     if (regExp->multiline())
    94         pattern += "m";
    95 
    96     return pattern;
    97 }
    98 
    99 static CString regexpName(int re, RegExp* regexp)
    100 {
    101     return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
    102 }
    103 
    104 static UString pointerToSourceString(void* p)
    105 {
    106     char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
    107     snprintf(buffer, sizeof(buffer), "%p", p);
    108     return buffer;
    109 }
    110 
    111 NEVER_INLINE static const char* debugHookName(int debugHookID)
    112 {
    113     switch (static_cast<DebugHookID>(debugHookID)) {
    114         case DidEnterCallFrame:
    115             return "didEnterCallFrame";
    116         case WillLeaveCallFrame:
    117             return "willLeaveCallFrame";
    118         case WillExecuteStatement:
    119             return "willExecuteStatement";
    120         case WillExecuteProgram:
    121             return "willExecuteProgram";
    122         case DidExecuteProgram:
    123             return "didExecuteProgram";
    124         case DidReachBreakpoint:
    125             return "didReachBreakpoint";
    126     }
    127 
    128     ASSERT_NOT_REACHED();
    129     return "";
    130 }
    131 
    132 static int locationForOffset(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset)
    133 {
    134     return it - begin + offset;
    135 }
    136 
    137 static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
    138 {
    139     int r0 = (++it)->u.operand;
    140     int r1 = (++it)->u.operand;
    141 
    142     printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str());
    143 }
    144 
    145 static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
    146 {
    147     int r0 = (++it)->u.operand;
    148     int r1 = (++it)->u.operand;
    149     int r2 = (++it)->u.operand;
    150     printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
    151 }
    152 
    153 static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op)
    154 {
    155     int r0 = (++it)->u.operand;
    156     int offset = (++it)->u.operand;
    157     printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(r0).c_str(), offset, locationForOffset(begin, it, offset));
    158 }
    159 
    160 static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op)
    161 {
    162     int r0 = (++it)->u.operand;
    163     int r1 = (++it)->u.operand;
    164     int id0 = (++it)->u.operand;
    165     printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
    166     it += 4;
    167 }
    168 
    169 static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op)
    170 {
    171     int r0 = (++it)->u.operand;
    172     int id0 = (++it)->u.operand;
    173     int r1 = (++it)->u.operand;
    174     printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
    175     it += 4;
    176 }
    177 
    178 void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) const
    179 {
    180     unsigned instructionOffset = vPC - m_instructions.begin();
    181     printf("  [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).UTF8String().c_str());
    182 }
    183 
    184 void CodeBlock::printStructures(const Instruction* vPC) const
    185 {
    186     Interpreter* interpreter = m_globalData->interpreter;
    187     unsigned instructionOffset = vPC - m_instructions.begin();
    188 
    189     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id)) {
    190         printStructure("get_by_id", vPC, 4);
     34    switch (opcodeID) {
     35    case op_get_by_id_self:
     36        u.getByIdSelf.baseObjectStructure->deref();
     37        return;
     38    case op_get_by_id_proto:
     39        u.getByIdProto.baseObjectStructure->deref();
     40        u.getByIdProto.prototypeStructure->deref();
     41        return;
     42    case op_get_by_id_chain:
     43        u.getByIdChain.baseObjectStructure->deref();
     44        u.getByIdChain.chain->deref();
     45        return;
     46    case op_get_by_id_self_list: {
     47        PolymorphicAccessStructureList* polymorphicStructures = u.getByIdSelfList.structureList;
     48        polymorphicStructures->derefStructures(u.getByIdSelfList.listSize);
     49        delete polymorphicStructures;
    19150        return;
    19251    }
    193     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
    194         printStructure("get_by_id_self", vPC, 4);
     52    case op_get_by_id_proto_list: {
     53        PolymorphicAccessStructureList* polymorphicStructures = u.getByIdProtoList.structureList;
     54        polymorphicStructures->derefStructures(u.getByIdProtoList.listSize);
     55        delete polymorphicStructures;
    19556        return;
    19657    }
    197     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
    198         printf("  [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structure).UTF8String().c_str());
     58    case op_put_by_id_transition:
     59        u.putByIdTransition.previousStructure->deref();
     60        u.putByIdTransition.structure->deref();
     61        u.putByIdTransition.chain->deref();
    19962        return;
     63    case op_put_by_id_replace:
     64        u.putByIdReplace.baseObjectStructure->deref();
     65        return;
     66    case op_get_by_id:
     67    case op_put_by_id:
     68    case op_get_by_id_generic:
     69    case op_put_by_id_generic:
     70    case op_get_array_length:
     71    case op_get_string_length:
     72        // These instructions don't ref their Structures.
     73        return;
     74    default:
     75        ASSERT_NOT_REACHED();
    20076    }
    201     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
    202         printf("  [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_new", pointerToSourceString(vPC[4].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[6].u.structureChain).UTF8String().c_str());
    203         return;
    204     }
    205     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
    206         printf("  [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureChain).UTF8String().c_str());
    207         return;
    208     }
    209     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) {
    210         printStructure("put_by_id", vPC, 4);
    211         return;
    212     }
    213     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
    214         printStructure("put_by_id_replace", vPC, 4);
    215         return;
    216     }
    217     if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
    218         printStructure("resolve_global", vPC, 4);
    219         return;
    220     }
    221 
    222     // These m_instructions doesn't ref Structures.
    223     ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_call) || vPC[0].u.opcode == interpreter->getOpcode(op_call_eval) || vPC[0].u.opcode == interpreter->getOpcode(op_construct));
    224 }
    225 
    226 void CodeBlock::dump(ExecState* exec) const
    227 {
    228     Vector<Instruction>::const_iterator begin = m_instructions.begin();
    229     Vector<Instruction>::const_iterator end = m_instructions.end();
    230 
    231     size_t instructionCount = 0;
    232     for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
    233         if (exec->interpreter()->isOpcode(it->u.opcode))
    234             ++instructionCount;
    235 
    236     printf("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n",
    237         static_cast<unsigned long>(instructionCount),
    238         static_cast<unsigned long>(m_instructions.size() * sizeof(Instruction)),
    239         this, m_numParameters, m_numCalleeRegisters);
    240    
    241     for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
    242         dump(exec, begin, it);
    243 
    244     if (!m_identifiers.isEmpty()) {
    245         printf("\nIdentifiers:\n");
    246         size_t i = 0;
    247         do {
    248             printf("  id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ascii());
    249             ++i;
    250         } while (i != m_identifiers.size());
    251     }
    252 
    253     if (!m_constantRegisters.isEmpty()) {
    254         printf("\nConstants:\n");
    255         unsigned registerIndex = m_numVars;
    256         size_t i = 0;
    257         do {
    258             printf("   r%u = %s\n", registerIndex, valueToSourceString(exec, m_constantRegisters[i].jsValue(exec)).ascii());
    259             ++i;
    260             ++registerIndex;
    261         } while (i < m_constantRegisters.size());
    262     }
    263 
    264     if (m_rareData && !m_rareData->m_unexpectedConstants.isEmpty()) {
    265         printf("\nUnexpected Constants:\n");
    266         size_t i = 0;
    267         do {
    268             printf("  k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_rareData->m_unexpectedConstants[i]).ascii());
    269             ++i;
    270         } while (i < m_rareData->m_unexpectedConstants.size());
    271     }
    272    
    273     if (m_rareData && !m_rareData->m_regexps.isEmpty()) {
    274         printf("\nm_regexps:\n");
    275         size_t i = 0;
    276         do {
    277             printf("  re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).ascii());
    278             ++i;
    279         } while (i < m_rareData->m_regexps.size());
    280     }
    281 
    282     if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty())
    283         printf("\nStructures:\n");
    284 
    285     if (!m_globalResolveInstructions.isEmpty()) {
    286         size_t i = 0;
    287         do {
    288              printStructures(&m_instructions[m_globalResolveInstructions[i]]);
    289              ++i;
    290         } while (i < m_globalResolveInstructions.size());
    291     }
    292     if (!m_propertyAccessInstructions.isEmpty()) {
    293         size_t i = 0;
    294         do {
    295              printStructures(&m_instructions[m_propertyAccessInstructions[i].bytecodeIndex]);
    296              ++i;
    297         } while (i < m_propertyAccessInstructions.size());
    298     }
    299  
    300     if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
    301         printf("\nException Handlers:\n");
    302         unsigned i = 0;
    303         do {
    304             printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target);
    305             ++i;
    306         } while (i < m_rareData->m_exceptionHandlers.size());
    307     }
    308    
    309     if (m_rareData && !m_rareData->m_immediateSwitchJumpTables.isEmpty()) {
    310         printf("Immediate Switch Jump Tables:\n");
    311         unsigned i = 0;
    312         do {
    313             printf("  %1d = {\n", i);
    314             int entry = 0;
    315             Vector<int32_t>::const_iterator end = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.end();
    316             for (Vector<int32_t>::const_iterator iter = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
    317                 if (!*iter)
    318                     continue;
    319                 printf("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter);
    320             }
    321             printf("      }\n");
    322             ++i;
    323         } while (i < m_rareData->m_immediateSwitchJumpTables.size());
    324     }
    325    
    326     if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) {
    327         printf("\nCharacter Switch Jump Tables:\n");
    328         unsigned i = 0;
    329         do {
    330             printf("  %1d = {\n", i);
    331             int entry = 0;
    332             Vector<int32_t>::const_iterator end = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.end();
    333             for (Vector<int32_t>::const_iterator iter = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
    334                 if (!*iter)
    335                     continue;
    336                 ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF));
    337                 UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min);
    338                 printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
    339         }
    340             printf("      }\n");
    341             ++i;
    342         } while (i < m_rareData->m_characterSwitchJumpTables.size());
    343     }
    344    
    345     if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
    346         printf("\nString Switch Jump Tables:\n");
    347         unsigned i = 0;
    348         do {
    349             printf("  %1d = {\n", i);
    350             StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
    351             for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
    352                 printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second.branchOffset);
    353             printf("      }\n");
    354             ++i;
    355         } while (i < m_rareData->m_stringSwitchJumpTables.size());
    356     }
    357 
    358     printf("\n");
    359 }
    360 
    361 void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
    362 {
    363     int location = it - begin;
    364     switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
    365         case op_enter: {
    366             printf("[%4d] enter\n", location);
    367             break;
    368         }
    369         case op_enter_with_activation: {
    370             int r0 = (++it)->u.operand;
    371             printf("[%4d] enter_with_activation %s\n", location, registerName(r0).c_str());
    372             break;
    373         }
    374         case op_create_arguments: {
    375             printf("[%4d] create_arguments\n", location);
    376             break;
    377         }
    378         case op_convert_this: {
    379             int r0 = (++it)->u.operand;
    380             printf("[%4d] convert_this %s\n", location, registerName(r0).c_str());
    381             break;
    382         }
    383         case op_unexpected_load: {
    384             int r0 = (++it)->u.operand;
    385             int k0 = (++it)->u.operand;
    386             printf("[%4d] unexpected_load\t %s, %s\n", location, registerName(r0).c_str(), constantName(exec, k0, unexpectedConstant(k0)).c_str());
    387             break;
    388         }
    389         case op_new_object: {
    390             int r0 = (++it)->u.operand;
    391             printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str());
    392             break;
    393         }
    394         case op_new_array: {
    395             int dst = (++it)->u.operand;
    396             int argv = (++it)->u.operand;
    397             int argc = (++it)->u.operand;
    398             printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(dst).c_str(), registerName(argv).c_str(), argc);
    399             break;
    400         }
    401         case op_new_regexp: {
    402             int r0 = (++it)->u.operand;
    403             int re0 = (++it)->u.operand;
    404             printf("[%4d] new_regexp\t %s, %s\n", location, registerName(r0).c_str(), regexpName(re0, regexp(re0)).c_str());
    405             break;
    406         }
    407         case op_mov: {
    408             int r0 = (++it)->u.operand;
    409             int r1 = (++it)->u.operand;
    410             printf("[%4d] mov\t\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
    411             break;
    412         }
    413         case op_not: {
    414             printUnaryOp(location, it, "not");
    415             break;
    416         }
    417         case op_eq: {
    418             printBinaryOp(location, it, "eq");
    419             break;
    420         }
    421         case op_eq_null: {
    422             printUnaryOp(location, it, "eq_null");
    423             break;
    424         }
    425         case op_neq: {
    426             printBinaryOp(location, it, "neq");
    427             break;
    428         }
    429         case op_neq_null: {
    430             printUnaryOp(location, it, "neq_null");
    431             break;
    432         }
    433         case op_stricteq: {
    434             printBinaryOp(location, it, "stricteq");
    435             break;
    436         }
    437         case op_nstricteq: {
    438             printBinaryOp(location, it, "nstricteq");
    439             break;
    440         }
    441         case op_less: {
    442             printBinaryOp(location, it, "less");
    443             break;
    444         }
    445         case op_lesseq: {
    446             printBinaryOp(location, it, "lesseq");
    447             break;
    448         }
    449         case op_pre_inc: {
    450             int r0 = (++it)->u.operand;
    451             printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str());
    452             break;
    453         }
    454         case op_pre_dec: {
    455             int r0 = (++it)->u.operand;
    456             printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str());
    457             break;
    458         }
    459         case op_post_inc: {
    460             printUnaryOp(location, it, "post_inc");
    461             break;
    462         }
    463         case op_post_dec: {
    464             printUnaryOp(location, it, "post_dec");
    465             break;
    466         }
    467         case op_to_jsnumber: {
    468             printUnaryOp(location, it, "to_jsnumber");
    469             break;
    470         }
    471         case op_negate: {
    472             printUnaryOp(location, it, "negate");
    473             break;
    474         }
    475         case op_add: {
    476             printBinaryOp(location, it, "add");
    477             ++it;
    478             break;
    479         }
    480         case op_mul: {
    481             printBinaryOp(location, it, "mul");
    482             ++it;
    483             break;
    484         }
    485         case op_div: {
    486             printBinaryOp(location, it, "div");
    487             break;
    488         }
    489         case op_mod: {
    490             printBinaryOp(location, it, "mod");
    491             break;
    492         }
    493         case op_sub: {
    494             printBinaryOp(location, it, "sub");
    495             ++it;
    496             break;
    497         }
    498         case op_lshift: {
    499             printBinaryOp(location, it, "lshift");
    500             break;           
    501         }
    502         case op_rshift: {
    503             printBinaryOp(location, it, "rshift");
    504             break;
    505         }
    506         case op_urshift: {
    507             printBinaryOp(location, it, "urshift");
    508             break;
    509         }
    510         case op_bitand: {
    511             printBinaryOp(location, it, "bitand");
    512             ++it;
    513             break;
    514         }
    515         case op_bitxor: {
    516             printBinaryOp(location, it, "bitxor");
    517             ++it;
    518             break;
    519         }
    520         case op_bitor: {
    521             printBinaryOp(location, it, "bitor");
    522             ++it;
    523             break;
    524         }
    525         case op_bitnot: {
    526             printUnaryOp(location, it, "bitnot");
    527             break;
    528         }
    529         case op_instanceof: {
    530             int r0 = (++it)->u.operand;
    531             int r1 = (++it)->u.operand;
    532             int r2 = (++it)->u.operand;
    533             int r3 = (++it)->u.operand;
    534             printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), registerName(r3).c_str());
    535             break;
    536         }
    537         case op_typeof: {
    538             printUnaryOp(location, it, "typeof");
    539             break;
    540         }
    541         case op_is_undefined: {
    542             printUnaryOp(location, it, "is_undefined");
    543             break;
    544         }
    545         case op_is_boolean: {
    546             printUnaryOp(location, it, "is_boolean");
    547             break;
    548         }
    549         case op_is_number: {
    550             printUnaryOp(location, it, "is_number");
    551             break;
    552         }
    553         case op_is_string: {
    554             printUnaryOp(location, it, "is_string");
    555             break;
    556         }
    557         case op_is_object: {
    558             printUnaryOp(location, it, "is_object");
    559             break;
    560         }
    561         case op_is_function: {
    562             printUnaryOp(location, it, "is_function");
    563             break;
    564         }
    565         case op_in: {
    566             printBinaryOp(location, it, "in");
    567             break;
    568         }
    569         case op_resolve: {
    570             int r0 = (++it)->u.operand;
    571             int id0 = (++it)->u.operand;
    572             printf("[%4d] resolve\t\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str());
    573             break;
    574         }
    575         case op_resolve_skip: {
    576             int r0 = (++it)->u.operand;
    577             int id0 = (++it)->u.operand;
    578             int skipLevels = (++it)->u.operand;
    579             printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), skipLevels);
    580             break;
    581         }
    582         case op_resolve_global: {
    583             int r0 = (++it)->u.operand;
    584             JSValue* scope = static_cast<JSValue*>((++it)->u.jsCell);
    585             int id0 = (++it)->u.operand;
    586             printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), idName(id0, m_identifiers[id0]).c_str());
    587             it += 2;
    588             break;
    589         }
    590         case op_get_scoped_var: {
    591             int r0 = (++it)->u.operand;
    592             int index = (++it)->u.operand;
    593             int skipLevels = (++it)->u.operand;
    594             printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
    595             break;
    596         }
    597         case op_put_scoped_var: {
    598             int index = (++it)->u.operand;
    599             int skipLevels = (++it)->u.operand;
    600             int r0 = (++it)->u.operand;
    601             printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
    602             break;
    603         }
    604         case op_get_global_var: {
    605             int r0 = (++it)->u.operand;
    606             JSValue* scope = static_cast<JSValue*>((++it)->u.jsCell);
    607             int index = (++it)->u.operand;
    608             printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), index);
    609             break;
    610         }
    611         case op_put_global_var: {
    612             JSValue* scope = static_cast<JSValue*>((++it)->u.jsCell);
    613             int index = (++it)->u.operand;
    614             int r0 = (++it)->u.operand;
    615             printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).ascii(), index, registerName(r0).c_str());
    616             break;
    617         }
    618         case op_resolve_base: {
    619             int r0 = (++it)->u.operand;
    620             int id0 = (++it)->u.operand;
    621             printf("[%4d] resolve_base\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str());
    622             break;
    623         }
    624         case op_resolve_with_base: {
    625             int r0 = (++it)->u.operand;
    626             int r1 = (++it)->u.operand;
    627             int id0 = (++it)->u.operand;
    628             printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
    629             break;
    630         }
    631         case op_resolve_func: {
    632             int r0 = (++it)->u.operand;
    633             int r1 = (++it)->u.operand;
    634             int id0 = (++it)->u.operand;
    635             printf("[%4d] resolve_func\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
    636             break;
    637         }
    638         case op_get_by_id: {
    639             printGetByIdOp(location, it, m_identifiers, "get_by_id");
    640             break;
    641         }
    642         case op_get_by_id_self: {
    643             printGetByIdOp(location, it, m_identifiers, "get_by_id_self");
    644             break;
    645         }
    646         case op_get_by_id_self_list: {
    647             printGetByIdOp(location, it, m_identifiers, "get_by_id_self_list");
    648             break;
    649         }
    650         case op_get_by_id_proto: {
    651             printGetByIdOp(location, it, m_identifiers, "get_by_id_proto");
    652             break;
    653         }
    654         case op_get_by_id_proto_list: {
    655             printGetByIdOp(location, it, m_identifiers, "op_get_by_id_proto_list");
    656             break;
    657         }
    658         case op_get_by_id_chain: {
    659             printGetByIdOp(location, it, m_identifiers, "get_by_id_chain");
    660             break;
    661         }
    662         case op_get_by_id_generic: {
    663             printGetByIdOp(location, it, m_identifiers, "get_by_id_generic");
    664             break;
    665         }
    666         case op_get_array_length: {
    667             printGetByIdOp(location, it, m_identifiers, "get_array_length");
    668             break;
    669         }
    670         case op_get_string_length: {
    671             printGetByIdOp(location, it, m_identifiers, "get_string_length");
    672             break;
    673         }
    674         case op_put_by_id: {
    675             printPutByIdOp(location, it, m_identifiers, "put_by_id");
    676             break;
    677         }
    678         case op_put_by_id_replace: {
    679             printPutByIdOp(location, it, m_identifiers, "put_by_id_replace");
    680             break;
    681         }
    682         case op_put_by_id_transition: {
    683             printPutByIdOp(location, it, m_identifiers, "put_by_id_transition");
    684             break;
    685         }
    686         case op_put_by_id_generic: {
    687             printPutByIdOp(location, it, m_identifiers, "put_by_id_generic");
    688             break;
    689         }
    690         case op_put_getter: {
    691             int r0 = (++it)->u.operand;
    692             int id0 = (++it)->u.operand;
    693             int r1 = (++it)->u.operand;
    694             printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
    695             break;
    696         }
    697         case op_put_setter: {
    698             int r0 = (++it)->u.operand;
    699             int id0 = (++it)->u.operand;
    700             int r1 = (++it)->u.operand;
    701             printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
    702             break;
    703         }
    704         case op_del_by_id: {
    705             int r0 = (++it)->u.operand;
    706             int r1 = (++it)->u.operand;
    707             int id0 = (++it)->u.operand;
    708             printf("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
    709             break;
    710         }
    711         case op_get_by_val: {
    712             int r0 = (++it)->u.operand;
    713             int r1 = (++it)->u.operand;
    714             int r2 = (++it)->u.operand;
    715             printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
    716             break;
    717         }
    718         case op_put_by_val: {
    719             int r0 = (++it)->u.operand;
    720             int r1 = (++it)->u.operand;
    721             int r2 = (++it)->u.operand;
    722             printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
    723             break;
    724         }
    725         case op_del_by_val: {
    726             int r0 = (++it)->u.operand;
    727             int r1 = (++it)->u.operand;
    728             int r2 = (++it)->u.operand;
    729             printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
    730             break;
    731         }
    732         case op_put_by_index: {
    733             int r0 = (++it)->u.operand;
    734             unsigned n0 = (++it)->u.operand;
    735             int r1 = (++it)->u.operand;
    736             printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(r0).c_str(), n0, registerName(r1).c_str());
    737             break;
    738         }
    739         case op_jmp: {
    740             int offset = (++it)->u.operand;
    741             printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset));
    742             break;
    743         }
    744         case op_loop: {
    745             int offset = (++it)->u.operand;
    746             printf("[%4d] loop\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset));
    747             break;
    748         }
    749         case op_jtrue: {
    750             printConditionalJump(begin, it, location, "jtrue");
    751             break;
    752         }
    753         case op_loop_if_true: {
    754             printConditionalJump(begin, it, location, "loop_if_true");
    755             break;
    756         }
    757         case op_jfalse: {
    758             printConditionalJump(begin, it, location, "jfalse");
    759             break;
    760         }
    761         case op_jeq_null: {
    762             printConditionalJump(begin, it, location, "jeq_null");
    763             break;
    764         }
    765         case op_jneq_null: {
    766             printConditionalJump(begin, it, location, "jneq_null");
    767             break;
    768         }
    769         case op_jnless: {
    770             int r0 = (++it)->u.operand;
    771             int r1 = (++it)->u.operand;
    772             int offset = (++it)->u.operand;
    773             printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
    774             break;
    775         }
    776         case op_loop_if_less: {
    777             int r0 = (++it)->u.operand;
    778             int r1 = (++it)->u.operand;
    779             int offset = (++it)->u.operand;
    780             printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
    781             break;
    782         }
    783         case op_loop_if_lesseq: {
    784             int r0 = (++it)->u.operand;
    785             int r1 = (++it)->u.operand;
    786             int offset = (++it)->u.operand;
    787             printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
    788             break;
    789         }
    790         case op_switch_imm: {
    791             int tableIndex = (++it)->u.operand;
    792             int defaultTarget = (++it)->u.operand;
    793             int scrutineeRegister = (++it)->u.operand;
    794             printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
    795             break;
    796         }
    797         case op_switch_char: {
    798             int tableIndex = (++it)->u.operand;
    799             int defaultTarget = (++it)->u.operand;
    800             int scrutineeRegister = (++it)->u.operand;
    801             printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
    802             break;
    803         }
    804         case op_switch_string: {
    805             int tableIndex = (++it)->u.operand;
    806             int defaultTarget = (++it)->u.operand;
    807             int scrutineeRegister = (++it)->u.operand;
    808             printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
    809             break;
    810         }
    811         case op_new_func: {
    812             int r0 = (++it)->u.operand;
    813             int f0 = (++it)->u.operand;
    814             printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(r0).c_str(), f0);
    815             break;
    816         }
    817         case op_new_func_exp: {
    818             int r0 = (++it)->u.operand;
    819             int f0 = (++it)->u.operand;
    820             printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(r0).c_str(), f0);
    821             break;
    822         }
    823         case op_call: {
    824             int dst = (++it)->u.operand;
    825             int func = (++it)->u.operand;
    826             int argCount = (++it)->u.operand;
    827             int registerOffset = (++it)->u.operand;
    828             printf("[%4d] call\t\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
    829             break;
    830         }
    831         case op_call_eval: {
    832             int dst = (++it)->u.operand;
    833             int func = (++it)->u.operand;
    834             int argCount = (++it)->u.operand;
    835             int registerOffset = (++it)->u.operand;
    836             printf("[%4d] call_eval\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
    837             break;
    838         }
    839         case op_tear_off_activation: {
    840             int r0 = (++it)->u.operand;
    841             printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str());
    842             break;
    843         }
    844         case op_tear_off_arguments: {
    845             printf("[%4d] tear_off_arguments\n", location);
    846             break;
    847         }
    848         case op_ret: {
    849             int r0 = (++it)->u.operand;
    850             printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
    851             break;
    852         }
    853         case op_construct: {
    854             int dst = (++it)->u.operand;
    855             int func = (++it)->u.operand;
    856             int argCount = (++it)->u.operand;
    857             int registerOffset = (++it)->u.operand;
    858             int proto = (++it)->u.operand;
    859             int thisRegister = (++it)->u.operand;
    860             printf("[%4d] construct\t %s, %s, %d, %d, %s, %s\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset, registerName(proto).c_str(), registerName(thisRegister).c_str());
    861             break;
    862         }
    863         case op_construct_verify: {
    864             int r0 = (++it)->u.operand;
    865             int r1 = (++it)->u.operand;
    866             printf("[%4d] construct_verify\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
    867             break;
    868         }
    869         case op_get_pnames: {
    870             int r0 = (++it)->u.operand;
    871             int r1 = (++it)->u.operand;
    872             printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
    873             break;
    874         }
    875         case op_next_pname: {
    876             int dest = (++it)->u.operand;
    877             int iter = (++it)->u.operand;
    878             int offset = (++it)->u.operand;
    879             printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, locationForOffset(begin, it, offset));
    880             break;
    881         }
    882         case op_push_scope: {
    883             int r0 = (++it)->u.operand;
    884             printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str());
    885             break;
    886         }
    887         case op_pop_scope: {
    888             printf("[%4d] pop_scope\n", location);
    889             break;
    890         }
    891         case op_push_new_scope: {
    892             int r0 = (++it)->u.operand;
    893             int id0 = (++it)->u.operand;
    894             int r1 = (++it)->u.operand;
    895             printf("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
    896             break;
    897         }
    898         case op_jmp_scopes: {
    899             int scopeDelta = (++it)->u.operand;
    900             int offset = (++it)->u.operand;
    901             printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, locationForOffset(begin, it, offset));
    902             break;
    903         }
    904         case op_catch: {
    905             int r0 = (++it)->u.operand;
    906             printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str());
    907             break;
    908         }
    909         case op_throw: {
    910             int r0 = (++it)->u.operand;
    911             printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str());
    912             break;
    913         }
    914         case op_new_error: {
    915             int r0 = (++it)->u.operand;
    916             int errorType = (++it)->u.operand;
    917             int k0 = (++it)->u.operand;
    918             printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(r0).c_str(), errorType, constantName(exec, k0, unexpectedConstant(k0)).c_str());
    919             break;
    920         }
    921         case op_jsr: {
    922             int retAddrDst = (++it)->u.operand;
    923             int offset = (++it)->u.operand;
    924             printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(retAddrDst).c_str(), offset, locationForOffset(begin, it, offset));
    925             break;
    926         }
    927         case op_sret: {
    928             int retAddrSrc = (++it)->u.operand;
    929             printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str());
    930             break;
    931         }
    932         case op_debug: {
    933             int debugHookID = (++it)->u.operand;
    934             int firstLine = (++it)->u.operand;
    935             int lastLine = (++it)->u.operand;
    936             printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
    937             break;
    938         }
    939         case op_profile_will_call: {
    940             int function = (++it)->u.operand;
    941             printf("[%4d] profile_will_call %s\n", location, registerName(function).c_str());
    942             break;
    943         }
    944         case op_profile_did_call: {
    945             int function = (++it)->u.operand;
    946             printf("[%4d] profile_did_call\t %s\n", location, registerName(function).c_str());
    947             break;
    948         }
    949         case op_end: {
    950             int r0 = (++it)->u.operand;
    951             printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str());
    952             break;
    953         }
    954     }
    955 }
    956 
    957 #endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
    958 
    959 #if DUMP_CODE_BLOCK_STATISTICS
    960 static HashSet<CodeBlock*> liveCodeBlockSet;
    961 #endif
    962 
    963 #define FOR_EACH_MEMBER_VECTOR(macro) \
    964     macro(instructions) \
    965     macro(globalResolveInstructions) \
    966     macro(propertyAccessInstructions) \
    967     macro(callLinkInfos) \
    968     macro(linkedCallerList) \
    969     macro(identifiers) \
    970     macro(functionExpressions) \
    971     macro(constantRegisters) \
    972     macro(expressionInfo) \
    973     macro(lineInfo) \
    974     macro(pcVector)
    975 
    976 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
    977     macro(regexps) \
    978     macro(functions) \
    979     macro(unexpectedConstants) \
    980     macro(exceptionHandlers) \
    981     macro(immediateSwitchJumpTables) \
    982     macro(characterSwitchJumpTables) \
    983     macro(stringSwitchJumpTables)
    984 
    985 template<typename T>
    986 static size_t sizeInBytes(const Vector<T>& vector)
    987 {
    988     return vector.capacity() * sizeof(T);
    989 }
    990 
    991 void CodeBlock::dumpStatistics()
    992 {
    993 #if DUMP_CODE_BLOCK_STATISTICS
    994     #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
    995         FOR_EACH_MEMBER_VECTOR(DEFINE_VARS)
    996         FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS)
    997     #undef DEFINE_VARS
    998 
    999     // Non-vector data members
    1000     size_t evalCodeCacheIsNotEmpty = 0;
    1001 
    1002     size_t symbolTableIsNotEmpty = 0;
    1003     size_t symbolTableTotalSize = 0;
    1004 
    1005     size_t hasRareData = 0;
    1006 
    1007     HashSet<CodeBlock*>::const_iterator end = liveCodeBlockSet.end();
    1008     for (HashSet<CodeBlock*>::const_iterator it = liveCodeBlockSet.begin(); it != end; ++it) {
    1009         CodeBlock* codeBlock = *it;
    1010 
    1011         #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
    1012             FOR_EACH_MEMBER_VECTOR(GET_STATS)
    1013         #undef GET_STATS
    1014 
    1015         if (!codeBlock->m_symbolTable.isEmpty()) {
    1016             symbolTableIsNotEmpty++;
    1017             symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType)));
    1018         }
    1019 
    1020         if (codeBlock->m_rareData) {
    1021             hasRareData++;
    1022             #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
    1023                 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS)
    1024             #undef GET_STATS
    1025 
    1026             if (!codeBlock->m_rareData->m_evalCodeCache.isEmpty())
    1027                 evalCodeCacheIsNotEmpty++;
    1028         }
    1029     }
    1030 
    1031     printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size());
    1032     printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock));
    1033 
    1034     printf("Number of CodeBlocks with rare data: %zu\n", hasRareData);
    1035 
    1036     #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
    1037         FOR_EACH_MEMBER_VECTOR(PRINT_STATS)
    1038         FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS)
    1039     #undef PRINT_STATS
    1040 
    1041     printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
    1042     printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
    1043 
    1044     printf("Size of all symbolTables: %zu\n", symbolTableTotalSize);
    1045 
    1046 #else
    1047     printf("Dumping CodeBlock statistics is not enabled.\n");
    1048 #endif
    1049 }
    1050 
    1051 
    1052 CodeBlock::CodeBlock(ScopeNode* ownerNode, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset)
    1053     : m_numCalleeRegisters(0)
    1054     , m_numConstants(0)
    1055     , m_numVars(0)
    1056     , m_numParameters(0)
    1057     , m_ownerNode(ownerNode)
    1058     , m_globalData(0)
    1059 #if ENABLE(JIT)
    1060     , m_jitCode(0)
    1061 #endif
    1062     , m_needsFullScopeChain(ownerNode->needsActivation())
    1063     , m_usesEval(ownerNode->usesEval())
    1064     , m_codeType(codeType)
    1065     , m_source(sourceProvider)
    1066     , m_sourceOffset(sourceOffset)
    1067 {
    1068     ASSERT(m_source);
    1069 
    1070 #if DUMP_CODE_BLOCK_STATISTICS
    1071     liveCodeBlockSet.add(this);
    1072 #endif
    1073 }
    1074 
    1075 CodeBlock::~CodeBlock()
    1076 {
    1077     for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i)
    1078         derefStructures(&m_instructions[m_globalResolveInstructions[i]]);
    1079 
    1080     for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i) {
    1081         derefStructures(&m_instructions[m_propertyAccessInstructions[i].bytecodeIndex]);
    1082     }
    1083 
    1084     for (size_t size = m_callLinkInfos.size(), i = 0; i < size; ++i) {
    1085         CallLinkInfo* callLinkInfo = &m_callLinkInfos[i];
    1086         if (callLinkInfo->isLinked())
    1087             callLinkInfo->callee->removeCaller(callLinkInfo);
    1088     }
    1089 
    1090 #if ENABLE(JIT)
    1091     unlinkCallers();
    1092 #endif
    1093 
    1094 #if DUMP_CODE_BLOCK_STATISTICS
    1095     liveCodeBlockSet.remove(this);
    1096 #endif
    1097 }
    1098 
    1099 #if ENABLE(JIT)
    1100 void CodeBlock::unlinkCallers()
    1101 {
    1102     size_t size = m_linkedCallerList.size();
    1103     for (size_t i = 0; i < size; ++i) {
    1104         CallLinkInfo* currentCaller = m_linkedCallerList[i];
    1105         JIT::unlinkCall(currentCaller);
    1106         currentCaller->setUnlinked();
    1107     }
    1108     m_linkedCallerList.clear();
    110977}
    111078#endif
    111179
    1112 void CodeBlock::derefStructures(Instruction* vPC) const
    1113 {
    1114     Interpreter* interpreter = m_globalData->interpreter;
    1115 
    1116     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
    1117         vPC[4].u.structure->deref();
    1118         return;
    1119     }
    1120     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
    1121         vPC[4].u.structure->deref();
    1122         vPC[5].u.structure->deref();
    1123         return;
    1124     }
    1125     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
    1126         vPC[4].u.structure->deref();
    1127         vPC[5].u.structureChain->deref();
    1128         return;
    1129     }
    1130     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
    1131         vPC[4].u.structure->deref();
    1132         vPC[5].u.structure->deref();
    1133         vPC[6].u.structureChain->deref();
    1134         return;
    1135     }
    1136     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
    1137         vPC[4].u.structure->deref();
    1138         return;
    1139     }
    1140     if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
    1141         if(vPC[4].u.structure)
    1142             vPC[4].u.structure->deref();
    1143         return;
    1144     }
    1145     if ((vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list))
    1146         || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self_list))) {
    1147         PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures;
    1148         polymorphicStructures->derefStructures(vPC[5].u.operand);
    1149         delete polymorphicStructures;
    1150         return;
    1151     }
    1152 
    1153     // These instructions don't ref their Structures.
    1154     ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_get_array_length) || vPC[0].u.opcode == interpreter->getOpcode(op_get_string_length));
    1155 }
    1156 
    1157 void CodeBlock::refStructures(Instruction* vPC) const
    1158 {
    1159     Interpreter* interpreter = m_globalData->interpreter;
    1160 
    1161     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
    1162         vPC[4].u.structure->ref();
    1163         return;
    1164     }
    1165     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
    1166         vPC[4].u.structure->ref();
    1167         vPC[5].u.structure->ref();
    1168         return;
    1169     }
    1170     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
    1171         vPC[4].u.structure->ref();
    1172         vPC[5].u.structureChain->ref();
    1173         return;
    1174     }
    1175     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
    1176         vPC[4].u.structure->ref();
    1177         vPC[5].u.structure->ref();
    1178         vPC[6].u.structureChain->ref();
    1179         return;
    1180     }
    1181     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
    1182         vPC[4].u.structure->ref();
    1183         return;
    1184     }
    1185    
    1186     // These instructions don't ref their Structures.
    1187     ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic));
    1188 }
    1189 
    1190 void CodeBlock::mark()
    1191 {
    1192     for (size_t i = 0; i < m_constantRegisters.size(); ++i)
    1193         if (!m_constantRegisters[i].marked())
    1194             m_constantRegisters[i].mark();
    1195 
    1196     for (size_t i = 0; i < m_functionExpressions.size(); ++i)
    1197         m_functionExpressions[i]->body()->mark();
    1198 
    1199     if (m_rareData) {
    1200         for (size_t i = 0; i < m_rareData->m_functions.size(); ++i)
    1201             m_rareData->m_functions[i]->body()->mark();
    1202 
    1203         for (size_t i = 0; i < m_rareData->m_unexpectedConstants.size(); ++i) {
    1204             if (!m_rareData->m_unexpectedConstants[i]->marked())
    1205                 m_rareData->m_unexpectedConstants[i]->mark();
    1206         }
    1207     }
    1208 }
    1209 
    1210 HandlerInfo* CodeBlock::handlerForVPC(const Instruction* vPC)
    1211 {
    1212     if (!m_rareData)
    1213         return 0;
    1214 
    1215     unsigned addressOffset = vPC - m_instructions.begin();
    1216     ASSERT(addressOffset < m_instructions.size());
    1217    
    1218     Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
    1219     for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
    1220         // Handlers are ordered innermost first, so the first handler we encounter
    1221         // that contains the source address is the correct handler to use.
    1222         if (exceptionHandlers[i].start <= addressOffset && exceptionHandlers[i].end >= addressOffset)
    1223             return &exceptionHandlers[i];
    1224     }
    1225 
    1226     return 0;
    1227 }
    1228 
    1229 int CodeBlock::lineNumberForVPC(const Instruction* vPC)
    1230 {
    1231     unsigned instructionOffset = vPC - m_instructions.begin();
    1232     ASSERT(instructionOffset < m_instructions.size());
    1233 
    1234     if (!m_lineInfo.size())
    1235         return m_ownerNode->source().firstLine(); // Empty function
    1236 
    1237     int low = 0;
    1238     int high = m_lineInfo.size();
    1239     while (low < high) {
    1240         int mid = low + (high - low) / 2;
    1241         if (m_lineInfo[mid].instructionOffset <= instructionOffset)
    1242             low = mid + 1;
    1243         else
    1244             high = mid;
    1245     }
    1246    
    1247     if (!low)
    1248         return m_ownerNode->source().firstLine();
    1249     return m_lineInfo[low - 1].lineNumber;
    1250 }
    1251 
    1252 int CodeBlock::expressionRangeForVPC(const Instruction* vPC, int& divot, int& startOffset, int& endOffset)
    1253 {
    1254     unsigned instructionOffset = vPC - m_instructions.begin();
    1255     ASSERT(instructionOffset < m_instructions.size());
    1256 
    1257     if (!m_expressionInfo.size()) {
    1258         // We didn't think anything could throw.  Apparently we were wrong.
    1259         startOffset = 0;
    1260         endOffset = 0;
    1261         divot = 0;
    1262         return lineNumberForVPC(vPC);
    1263     }
    1264 
    1265     int low = 0;
    1266     int high = m_expressionInfo.size();
    1267     while (low < high) {
    1268         int mid = low + (high - low) / 2;
    1269         if (m_expressionInfo[mid].instructionOffset <= instructionOffset)
    1270             low = mid + 1;
    1271         else
    1272             high = mid;
    1273     }
    1274    
    1275     ASSERT(low);
    1276     if (!low) {
    1277         startOffset = 0;
    1278         endOffset = 0;
    1279         divot = 0;
    1280         return lineNumberForVPC(vPC);
    1281     }
    1282 
    1283     startOffset = m_expressionInfo[low - 1].startOffset;
    1284     endOffset = m_expressionInfo[low - 1].endOffset;
    1285     divot = m_expressionInfo[low - 1].divotPoint + m_sourceOffset;
    1286     return lineNumberForVPC(vPC);
    1287 }
    1288 
    1289 void CodeBlock::shrinkToFit()
    1290 {
    1291     m_instructions.shrinkToFit();
    1292 
    1293     m_globalResolveInstructions.shrinkToFit();
    1294     m_propertyAccessInstructions.shrinkToFit();
    1295     m_callLinkInfos.shrinkToFit();
    1296     m_linkedCallerList.shrinkToFit();
    1297     m_expressionInfo.shrinkToFit();
    1298     m_lineInfo.shrinkToFit();
    1299     m_identifiers.shrinkToFit();
    1300     m_functionExpressions.shrinkToFit();
    1301     m_constantRegisters.shrinkToFit();
    1302 
    1303     if (m_rareData) {
    1304         m_rareData->m_exceptionHandlers.shrinkToFit();
    1305         m_rareData->m_functions.shrinkToFit();
    1306         m_rareData->m_unexpectedConstants.shrinkToFit();
    1307         m_rareData->m_regexps.shrinkToFit();
    1308         m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
    1309         m_rareData->m_characterSwitchJumpTables.shrinkToFit();
    1310         m_rareData->m_stringSwitchJumpTables.shrinkToFit();
    1311     }
    1312 }
    1313 
    131480} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.