📄 codeblock.cpp
字号:
/* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "CodeBlock.h"#include "JIT.h"#include "JSValue.h"#include "Interpreter.h"#include "Debugger.h"#include "BytecodeGenerator.h"#include <stdio.h>#include <wtf/StringExtras.h>#define DUMP_CODE_BLOCK_STATISTICS 0namespace JSC {#if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)static UString escapeQuotes(const UString& str){ UString result = str; int pos = 0; while ((pos = result.find('\"', pos)) >= 0) { result = result.substr(0, pos) + "\"\\\"\"" + result.substr(pos + 1); pos += 4; } return result;}static UString valueToSourceString(ExecState* exec, JSValuePtr val){ if (val.isString()) { UString result("\""); result += escapeQuotes(val.toString(exec)) + "\""; return result; } return val.toString(exec);}static CString registerName(int r){ if (r == missingThisObjectMarker()) return "<null>"; return (UString("r") + UString::from(r)).UTF8String();}static CString constantName(ExecState* exec, int k, JSValuePtr value){ return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String();}static CString idName(int id0, const Identifier& ident){ return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String();}static UString regexpToSourceString(RegExp* regExp){ UString pattern = UString("/") + regExp->pattern() + "/"; if (regExp->global()) pattern += "g"; if (regExp->ignoreCase()) pattern += "i"; if (regExp->multiline()) pattern += "m"; return pattern;}static CString regexpName(int re, RegExp* regexp){ return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();}static UString pointerToSourceString(void* p){ char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0 snprintf(buffer, sizeof(buffer), "%p", p); return buffer;}NEVER_INLINE static const char* debugHookName(int debugHookID){ 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"; } ASSERT_NOT_REACHED(); return "";}static int locationForOffset(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset){ return it - begin + offset;}static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op){ int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str());}static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op){ int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());}static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op){ int r0 = (++it)->u.operand; int offset = (++it)->u.operand; printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(r0).c_str(), offset, locationForOffset(begin, it, offset));}static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op){ int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; 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()); it += 4;}static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op){ int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; 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()); it += 4;}#if ENABLE(JIT)static bool isGlobalResolve(OpcodeID opcodeID){ return opcodeID == op_resolve_global;}static bool isPropertyAccess(OpcodeID opcodeID){ switch (opcodeID) { case op_get_by_id_self: case op_get_by_id_proto: case op_get_by_id_chain: case op_get_by_id_self_list: case op_get_by_id_proto_list: case op_put_by_id_transition: case op_put_by_id_replace: case op_get_by_id: case op_put_by_id: case op_get_by_id_generic: case op_put_by_id_generic: case op_get_array_length: case op_get_string_length: return true; default: return false; }}static unsigned instructionOffsetForNth(ExecState* exec, const Vector<Instruction>& instructions, int nth, bool (*predicate)(OpcodeID)){ size_t i = 0; while (i < instructions.size()) { OpcodeID currentOpcode = exec->interpreter()->getOpcodeID(instructions[i].u.opcode); if (predicate(currentOpcode)) { if (!--nth) return i; } i += opcodeLengths[currentOpcode]; } ASSERT_NOT_REACHED(); return 0;}static void printGlobalResolveInfo(const GlobalResolveInfo& resolveInfo, unsigned instructionOffset){ printf(" [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).UTF8String().c_str());}static void printStructureStubInfo(const StructureStubInfo& stubInfo, unsigned instructionOffset){ switch (stubInfo.opcodeID) { case op_get_by_id_self: printf(" [%4d] %s: %s\n", instructionOffset, "get_by_id_self", pointerToSourceString(stubInfo.u.getByIdSelf.baseObjectStructure).UTF8String().c_str()); return; case op_get_by_id_proto: printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(stubInfo.u.getByIdProto.baseObjectStructure).UTF8String().c_str(), pointerToSourceString(stubInfo.u.getByIdProto.prototypeStructure).UTF8String().c_str()); return; case op_get_by_id_chain: printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(stubInfo.u.getByIdChain.baseObjectStructure).UTF8String().c_str(), pointerToSourceString(stubInfo.u.getByIdChain.chain).UTF8String().c_str()); return; case op_get_by_id_self_list: printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_self_list", pointerToSourceString(stubInfo.u.getByIdSelfList.structureList).UTF8String().c_str(), stubInfo.u.getByIdSelfList.listSize); return; case op_get_by_id_proto_list: printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_proto_list", pointerToSourceString(stubInfo.u.getByIdProtoList.structureList).UTF8String().c_str(), stubInfo.u.getByIdProtoList.listSize); return; case op_put_by_id_transition: printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(stubInfo.u.putByIdTransition.previousStructure).UTF8String().c_str(), pointerToSourceString(stubInfo.u.putByIdTransition.structure).UTF8String().c_str(), pointerToSourceString(stubInfo.u.putByIdTransition.chain).UTF8String().c_str()); return; case op_put_by_id_replace: printf(" [%4d] %s: %s\n", instructionOffset, "put_by_id_replace", pointerToSourceString(stubInfo.u.putByIdReplace.baseObjectStructure).UTF8String().c_str()); return; case op_get_by_id: printf(" [%4d] %s\n", instructionOffset, "get_by_id"); return; case op_put_by_id: printf(" [%4d] %s\n", instructionOffset, "put_by_id"); return; case op_get_by_id_generic: printf(" [%4d] %s\n", instructionOffset, "op_get_by_id_generic"); return; case op_put_by_id_generic: printf(" [%4d] %s\n", instructionOffset, "op_put_by_id_generic"); return; case op_get_array_length: printf(" [%4d] %s\n", instructionOffset, "op_get_array_length"); return; case op_get_string_length: printf(" [%4d] %s\n", instructionOffset, "op_get_string_length"); return; default: ASSERT_NOT_REACHED(); }}#endifvoid CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) const{ unsigned instructionOffset = vPC - m_instructions.begin(); printf(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).UTF8String().c_str());}void CodeBlock::printStructures(const Instruction* vPC) const{ Interpreter* interpreter = m_globalData->interpreter; unsigned instructionOffset = vPC - m_instructions.begin(); if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id)) { printStructure("get_by_id", vPC, 4); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) { printStructure("get_by_id_self", vPC, 4); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) { 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()); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) { printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[6].u.structureChain).UTF8String().c_str()); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) { 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()); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) { printStructure("put_by_id", vPC, 4); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) { printStructure("put_by_id_replace", vPC, 4); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) { printStructure("resolve_global", vPC, 4); return; } // These m_instructions doesn't ref Structures. 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));}void CodeBlock::dump(ExecState* exec) const{ if (m_instructions.isEmpty()) { printf("No instructions available.\n"); return; } size_t instructionCount = 0; for (size_t i = 0; i < m_instructions.size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(m_instructions[i].u.opcode)]) ++instructionCount; printf("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n", static_cast<unsigned long>(instructionCount), static_cast<unsigned long>(m_instructions.size() * sizeof(Instruction)),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -