Ignore:
Timestamp:
Apr 21, 2017, 2:42:24 PM (8 years ago)
Author:
[email protected]
Message:

Refactor MASM probe to allow printing of custom types.
https://bugs.webkit.org/show_bug.cgi?id=171101

Reviewed by JF Bastien.

For example, this allows us to add MASM printing of CodeBlock* and Air::Args.

In general, MASM print can be used like dataLog, except that it generates JITted
code for doing the dataLogging later when the JITted code runs. MASM print can
print any value type that a specialized Printer template or a setPrinter()
function implemented for that type.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • assembler/MacroAssembler.h:
  • assembler/MacroAssemblerPrinter.cpp:

(JSC::Printer::printAllRegisters):
(JSC::Printer::printPCRegister):
(JSC::Printer::printRegisterID):
(JSC::Printer::printFPRegisterID):
(JSC::Printer::printAddress):
(JSC::Printer::printMemory):
(JSC::Printer::printCallback):
(JSC::printIndent): Deleted.
(JSC::printCPU): Deleted.
(JSC::printCPURegisters): Deleted.
(JSC::printPC): Deleted.
(JSC::printRegister): Deleted.
(JSC::printMemory): Deleted.
(JSC::MacroAssemblerPrinter::printCallback): Deleted.

  • assembler/MacroAssemblerPrinter.h:

(JSC::AllRegisters::AllRegisters):
(JSC::Printer::Printer<AllRegisters>::Printer):
(JSC::Printer::Printer<PCRegister>::Printer):
(JSC::Printer::Printer<MacroAssembler::RegisterID>::Printer):
(JSC::Printer::Printer<MacroAssembler::FPRegisterID>::Printer):
(JSC::Printer::Printer<MacroAssembler::Address>::Printer):
(JSC::Printer::Printer<Memory>::Printer):
(JSC::Printer::Printer<MemWord<IntType>>::Printer):
(JSC::MacroAssembler::print):
(JSC::MacroAssemblerPrinter::print): Deleted.
(JSC::MacroAssemblerPrinter::PrintArg::PrintArg): Deleted.
(JSC::MacroAssemblerPrinter::appendPrintArg): Deleted.

  • Refactored to move the underlying PrintRecord (and associated data structures) out to Printer.cpp/h.
  • MacroAssemblerPrinter.cpp/h now only add custom Printers for MASM types like RegisterID and Memory. It also defines the implementation of MacroAssembler::print().

As before, JIT code that wishes to use MacroAssembler::print() needs to
#include "MacroAssemblerPrinter.h".

  • Also added the ability to specify an optional indentation (in number of chars) when MASM printing AllRegisters. This is useful because AllRegisters prints a block of data unlike other printers which print inline.
  • assembler/Printer.cpp: Added.

(JSC::Printer::printConstCharString):
(JSC::Printer::printIntptr):
(JSC::Printer::printUintptr):
(JSC::Printer::printPointer):
(JSC::Printer::setPrinter):

  • assembler/Printer.h: Added.

(JSC::Printer::Context::Context):
(JSC::Printer::PrintRecord::PrintRecord):
(JSC::Printer::appendPrinter):
(JSC::Printer::makePrintRecordList):
(JSC::Printer::Printer<RawPointer>::Printer):
(JSC::Printer::setPrinter):
(JSC::Printer::Printer::Printer):

  • Data structures for creating a list of PrintRecords. Classes which wish to add custom support for MASM printing can #include "Printer.h" and implement either:
    1. a specialized Printer template, or
    2. a setPrinter() function.

See Printer<Reg> and Printer<B3::Air::Tmp> in AirPrintSpecial.h for examples of
(1). See CodeBlock's setPrinter() for an example of (2).

  • b3/B3LowerToAir.cpp:

(JSC::B3::Air::LowerToAir::print):

  • b3/air/AirPrintSpecial.cpp: Added.

(JSC::B3::Air::PrintSpecial::PrintSpecial):
(JSC::B3::Air::PrintSpecial::~PrintSpecial):
(JSC::B3::Air::PrintSpecial::forEachArg):
(JSC::B3::Air::PrintSpecial::isValid):
(JSC::B3::Air::PrintSpecial::admitsStack):
(JSC::B3::Air::PrintSpecial::reportUsedRegisters):
(JSC::B3::Air::PrintSpecial::generate):
(JSC::B3::Air::PrintSpecial::extraEarlyClobberedRegs):
(JSC::B3::Air::PrintSpecial::extraClobberedRegs):
(JSC::B3::Air::PrintSpecial::dumpImpl):
(JSC::B3::Air::PrintSpecial::deepDumpImpl):
(JSC::Printer::printAirArg):

  • b3/air/AirPrintSpecial.h: Added.

(JSC::Printer::appendAirArg):
(JSC::Printer::appendAirArgs):
(JSC::Printer::Printer<B3::Air::Tmp>::Printer):
(JSC::Printer::Printer<Reg>::Printer):

  • Add the print() operation for use in LowerToAir. print() will emit a PrintSpecial that will ultimately emit a MASM print to print what we want.
  • LowerToAir's print() adds the ability to print Air::Args.
  • Unlike in the baseline JIT and the DFG, LowerToAir's print() can perturb the usage of registers. This is because PrintSpecial is a patch point, and it prevents certain optimizations. If not used carefully, an attempt to print() an Arg by taking a Tmp, can force the B3 Value into a Tmp earlier than it would otherwise do so. So, use LowerToAir's print() with care.
  • bytecode/CodeBlock.cpp:

(JSC::setPrinter):

  • Now we can MASM print CodeBlock*.

(WTF::printInternal):

  • Now we can dataLog CodeBlock* (including null CodeBlock pointers).
  • bytecode/CodeBlock.h:
  • runtime/VM.cpp:

(JSC::VM::throwException):

  • Use the new ability to dataLog CodeBlock*. No need to do an explicit null check before printing anymore.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerPrinter.cpp

    r215592 r215642  
    3232
    3333namespace JSC {
     34namespace Printer {
    3435
    3536using CPUState = MacroAssembler::CPUState;
     
    3738using FPRegisterID = MacroAssembler::FPRegisterID;
    3839
    39 static void printIndent(int indentation)
     40void printAllRegisters(PrintStream& out, Context& context)
    4041{
    41     for (; indentation > 0; indentation--)
    42         dataLog("    ");
    43 }
     42    auto& cpu = context.probeContext.cpu;
     43    unsigned charsToIndent = context.data.as<unsigned>();
    4444
    45 #define INDENT printIndent(indentation)
    46    
    47 void printCPU(CPUState& cpu, int indentation)
    48 {
    49     INDENT, dataLog("cpu: {\n");
    50     printCPURegisters(cpu, indentation + 1);
    51     INDENT, dataLog("}\n");
    52 }
     45    auto indent = [&] () {
     46        for (unsigned i = 0; i < charsToIndent; ++i)
     47            out.print(" ");
     48    };
     49#define INDENT indent()
    5350
    54 void printCPURegisters(CPUState& cpu, int indentation)
    55 {
     51    INDENT, out.print("cpu: {\n");
     52
    5653#if USE(JSVALUE32_64)
    5754    #define INTPTR_HEX_VALUE_FORMAT "0x%08lx"
     
    6259    #define PRINT_GPREGISTER(_type, _regName) { \
    6360        intptr_t value = reinterpret_cast<intptr_t>(cpu._regName); \
    64         INDENT, dataLogF("%6s: " INTPTR_HEX_VALUE_FORMAT "  %ld\n", #_regName, value, value) ; \
     61        INDENT, out.printf("    %6s: " INTPTR_HEX_VALUE_FORMAT "  %ld\n", #_regName, value, value) ; \
    6562    }
    6663    FOR_EACH_CPU_GPREGISTER(PRINT_GPREGISTER)
     
    7269        uint64_t* u = reinterpret_cast<uint64_t*>(&cpu._regName); \
    7370        double* d = reinterpret_cast<double*>(&cpu._regName); \
    74         INDENT, dataLogF("%6s: 0x%016llx  %.13g\n", #_regName, *u, *d); \
     71        INDENT, out.printf("    %6s: 0x%016llx  %.13g\n", #_regName, *u, *d); \
    7572    }
    7673    FOR_EACH_CPU_FPREGISTER(PRINT_FPREGISTER)
    7774    #undef PRINT_FPREGISTER
     75
     76    INDENT, out.print("}\n");
     77#undef INDENT
     78
    7879}
    7980
    80 static void printPC(CPUState& cpu)
     81void printPCRegister(PrintStream& out, Context& context)
    8182{
    82     union {
    83         void* voidPtr;
    84         intptr_t intptrValue;
    85     } u;
     83    auto cpu = context.probeContext.cpu;
     84    void* value;
    8685#if CPU(X86) || CPU(X86_64)
    87     u.voidPtr = cpu.eip;
     86    value = cpu.eip;
    8887#elif CPU(ARM_TRADITIONAL) || CPU(ARM_THUMB2) || CPU(ARM64)
    89     u.voidPtr = cpu.pc;
     88    value = cpu.pc;
    9089#else
    9190#error "Unsupported CPU"
    9291#endif
    93     dataLogF("pc:<%p %ld>", u.voidPtr, u.intptrValue);
     92    out.printf("pc:<%p %ld>", value, bitwise_cast<intptr_t>(value));
    9493}
    9594
    96 void printRegister(CPUState& cpu, RegisterID regID)
     95void printRegisterID(PrintStream& out, Context& context)
    9796{
     97    RegisterID regID = context.data.as<RegisterID>();
    9898    const char* name = CPUState::gprName(regID);
    99     union {
    100         void* voidPtr;
    101         intptr_t intptrValue;
    102     } u;
    103     u.voidPtr = cpu.gpr(regID);
    104     dataLogF("%s:<%p %ld>", name, u.voidPtr, u.intptrValue);
     99    void* value = context.probeContext.gpr(regID);
     100    out.printf("%s:<%p %ld>", name, value, bitwise_cast<intptr_t>(value));
    105101}
    106102
    107 void printRegister(CPUState& cpu, FPRegisterID regID)
     103void printFPRegisterID(PrintStream& out, Context& context)
    108104{
     105    FPRegisterID regID = context.data.as<FPRegisterID>();
    109106    const char* name = CPUState::fprName(regID);
    110     union {
    111         double doubleValue;
    112         uint64_t uint64Value;
    113     } u;
    114     u.doubleValue = cpu.fpr(regID);
    115     dataLogF("%s:<0x%016llx %.13g>", name, u.uint64Value, u.doubleValue);
     107    double value = context.probeContext.fpr(regID);
     108    out.printf("%s:<0x%016llx %.13g>", name, bitwise_cast<uint64_t>(value), value);
    116109}
    117110
    118 void printMemory(CPUState& cpu, const Memory& memory)
     111void printAddress(PrintStream& out, Context& context)
    119112{
     113    MacroAssembler::Address address = context.data.as<MacroAssembler::Address>();
     114    RegisterID regID = address.base;
     115    const char* name = CPUState::gprName(regID);
     116    void* value = context.probeContext.gpr(regID);
     117    out.printf("Address{base:%s:<%p %ld>, offset:<0x%x %d>", name, value, bitwise_cast<intptr_t>(value), address.offset, address.offset);
     118}
     119
     120void printMemory(PrintStream& out, Context& context)
     121{
     122    const Memory& memory = context.data.as<Memory>();
     123
    120124    uint8_t* ptr = nullptr;
    121125    switch (memory.addressType) {
    122126    case Memory::AddressType::Address: {
    123         ptr = reinterpret_cast<uint8_t*>(cpu.gpr(memory.u.address.base));
     127        ptr = reinterpret_cast<uint8_t*>(context.probeContext.gpr(memory.u.address.base));
    124128        ptr += memory.u.address.offset;
    125129        break;
     
    134138        if (memory.numBytes == sizeof(int8_t)) {
    135139            auto p = reinterpret_cast<int8_t*>(ptr);
    136             dataLogF("%p:<0x%02x %d>", p, *p, *p);
     140            out.printf("%p:<0x%02x %d>", p, *p, *p);
    137141            return;
    138142        }
    139143        if (memory.numBytes == sizeof(int16_t)) {
    140144            auto p = reinterpret_cast<int16_t*>(ptr);
    141             dataLogF("%p:<0x%04x %d>", p, *p, *p);
     145            out.printf("%p:<0x%04x %d>", p, *p, *p);
    142146            return;
    143147        }
    144148        if (memory.numBytes == sizeof(int32_t)) {
    145149            auto p = reinterpret_cast<int32_t*>(ptr);
    146             dataLogF("%p:<0x%08x %d>", p, *p, *p);
     150            out.printf("%p:<0x%08x %d>", p, *p, *p);
    147151            return;
    148152        }
    149153        if (memory.numBytes == sizeof(int64_t)) {
    150154            auto p = reinterpret_cast<int64_t*>(ptr);
    151             dataLogF("%p:<0x%016llx %lld>", p, *p, *p);
     155            out.printf("%p:<0x%016llx %lld>", p, *p, *p);
    152156            return;
    153157        }
     
    159163    for (size_t i = 0; i < numBytes; i++) {
    160164        if (!(i % 16))
    161             dataLogF("%p: ", &ptr[i]);
     165            out.printf("%p: ", &ptr[i]);
    162166        else if (!(i % 4))
    163             dataLog(" ");
     167            out.printf(" ");
    164168
    165         dataLogF("%02x", ptr[i]);
     169        out.printf("%02x", ptr[i]);
    166170
    167171        if (i % 16 == 15)
    168             dataLog("\n");
     172            out.print("\n");
    169173    }
    170174    if (numBytes % 16 < 15)
    171         dataLog("\n");
     175        out.print("\n");
    172176}
    173177
    174 void MacroAssemblerPrinter::printCallback(ProbeContext* context)
     178void printCallback(ProbeContext* probeContext)
    175179{
    176     typedef PrintArg Arg;
    177     PrintArgsList& argsList =
    178     *reinterpret_cast<PrintArgsList*>(context->arg);
    179     for (size_t i = 0; i < argsList.size(); i++) {
    180         auto& arg = argsList[i];
    181         switch (arg.type) {
    182         case Arg::Type::AllRegisters:
    183             printCPU(context->cpu, 1);
    184             break;
    185         case Arg::Type::PCRegister:
    186             printPC(context->cpu);
    187             break;
    188         case Arg::Type::RegisterID:
    189             printRegister(context->cpu, arg.u.gpRegisterID);
    190             break;
    191         case Arg::Type::FPRegisterID:
    192             printRegister(context->cpu, arg.u.fpRegisterID);
    193             break;
    194         case Arg::Type::Memory:
    195             printMemory(context->cpu, arg.u.memory);
    196             break;
    197         case Arg::Type::ConstCharPtr:
    198             dataLog(arg.u.constCharPtr);
    199             break;
    200         case Arg::Type::ConstVoidPtr:
    201             dataLogF("%p", arg.u.constVoidPtr);
    202             break;
    203         case Arg::Type::IntptrValue:
    204             dataLog(arg.u.intptrValue);
    205             break;
    206         case Arg::Type::UintptrValue:
    207             dataLog(arg.u.uintptrValue);
    208             break;
    209         }
     180    auto& out = WTF::dataFile();
     181    PrintRecordList& list = *reinterpret_cast<PrintRecordList*>(probeContext->arg);
     182    for (size_t i = 0; i < list.size(); i++) {
     183        auto& record = list[i];
     184        Context context(*probeContext, record.data);
     185        record.printer(out, context);
    210186    }
    211187}
    212188
     189} // namespace Printer
    213190} // namespace JSC
    214191
Note: See TracChangeset for help on using the changeset viewer.