Ignore:
Timestamp:
Jul 24, 2013, 9:00:16 PM (12 years ago)
Author:
[email protected]
Message:

fourthTier: Implement a probe mechanism for JIT generated code.
https://bugs.webkit.org/show_bug.cgi?id=115705.

Reviewed by Geoffrey Garen.

The probe is in the form of a MacroAssembler pseudo instruction.
It takes 3 arguments: a ProbeFunction, and 2 void* args.

When inserted into the JIT at some code generation site, the probe
pseudo "instruction" will emit a minimal amount of code to save the
stack pointer, 1 (or more) scratch register(s), and the probe
arguments into a ProbeContext record on the stack. The emitted code
will then call a probe trampoline to do the rest of the work, which
consists of:

  1. saving the remaining registers into the ProbeContext.
  2. calling the ProbeFunction, and passing it the ProbeContext pointer.
  3. restoring the registers from the ProbeContext after the ProbeFunction returns, and then returning to the JIT generated code.

The ProbeContext is stack allocated and is only valid for the duration
that the ProbeFunction is executing.

If the user supplied ProbeFunction alters the register values in the
ProbeContext, the new values will be installed into the registers upon
returning from the probe. This can be useful for some debugging or
testing purposes.

The probe mechanism is built conditional on USE(MASM_PROBE) which is
defined in config.h. USE(MASM_PROBE) will off by default.

This changeset only implements the probe mechanism for X86 and X86_64.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • assembler/MacroAssembler.h:

(MacroAssembler):
(JSC::MacroAssembler::shouldBlind):
(JSC::MacroAssembler::store32):

  • assembler/MacroAssemblerX86.h:

(MacroAssemblerX86):
(JSC::MacroAssemblerX86::trustedImm32FromPtr):
(JSC::MacroAssemblerX86::probe):

  • assembler/MacroAssemblerX86Common.cpp: Added.

(JSC::MacroAssemblerX86Common::ProbeContext::dumpCPURegisters):

  • CPU specific register dumper called by ProbeContext::dump().

(JSC::MacroAssemblerX86Common::ProbeContext::dump):

  • Prints the ProbeContext to the DataLog.
  • assembler/MacroAssemblerX86Common.h:

(MacroAssemblerX86Common):
(CPUState): Added.
(ProbeContext): Added.

  • assembler/MacroAssemblerX86_64.h:

(MacroAssemblerX86_64):
(JSC::MacroAssemblerX86_64::trustedImm64FromPtr):
(JSC::MacroAssemblerX86_64::probe):

  • assembler/X86Assembler.h:
  • config.h: Added WTF_USE_MASM_PROBE flag.
  • jit/JITStubs.cpp:
  • jit/JITStubs.h:
  • jit/JITStubsX86.h:
  • jit/JITStubsX86Common.h: Added.
  • jit/JITStubsX86_64.h:
Location:
trunk/Source/JavaScriptCore/assembler
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/assembler/MacroAssembler.h

    r143408 r153162  
    11/*
    2  * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    572572        return MacroAssemblerBase::branchTest8(cond, Address(address.base, address.offset), mask);
    573573    }
    574 #else
     574
     575#else // !CPU(X86_64)
     576
    575577    void addPtr(RegisterID src, RegisterID dest)
    576578    {
     
    10681070    }
    10691071
    1070 #endif
     1072#endif // ENABLE(JIT_CONSTANT_BLINDING)
    10711073
    10721074#endif // !CPU(X86_64)
     
    10801082        // if we've broken blinding during patch development.
    10811083        return true;
    1082 #else
     1084#else // ENABLE(FORCED_JIT_BLINDING)
    10831085
    10841086        // First off we'll special case common, "safe" values to avoid hurting
     
    11011103
    11021104        return shouldBlindForSpecificArch(value);
    1103 #endif
     1105#endif // ENABLE(FORCED_JIT_BLINDING)
    11041106    }
    11051107
     
    12721274        store64(value, addressForPoke(index));
    12731275    }
    1274 #endif
     1276#endif // CPU(X86_64)
    12751277   
    12761278    void store32(Imm32 imm, Address dest)
     
    12811283            store32(blind.value1, dest);
    12821284            xor32(blind.value2, dest);
    1283 #else
     1285#else // CPU(X86) || CPU(X86_64)
    12841286            if (RegisterID scratchRegister = (RegisterID)scratchRegisterForBlinding()) {
    12851287                loadXorBlindedConstant(xorBlindConstant(imm), scratchRegister);
     
    12931295                store32(imm.asTrustedImm32(), dest);
    12941296            }
    1295 #endif
     1297#endif // CPU(X86) || CPU(X86_64)
    12961298        } else
    12971299            store32(imm.asTrustedImm32(), dest);
     
    14411443        urshift32(src, trustedImm32ForShift(amount), dest);
    14421444    }
    1443 #endif
     1445#endif // ENABLE(JIT_CONSTANT_BLINDING)
    14441446};
    14451447
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86.h

    r135330 r153162  
    3131#include "MacroAssemblerX86Common.h"
    3232
     33#if USE(MASM_PROBE)
     34#include <wtf/StdLibExtras.h>
     35#endif
     36
    3337namespace JSC {
    3438
     
    288292    }
    289293
     294#if USE(MASM_PROBE)
     295    // This function emits code to preserve the CPUState (e.g. registers),
     296    // call a user supplied probe function, and restore the CPUState before
     297    // continuing with other JIT generated code.
     298    //
     299    // The user supplied probe function will be called with a single pointer to
     300    // a ProbeContext struct (defined above) which contains, among other things,
     301    // the preserved CPUState. This allows the user probe function to inspect
     302    // the CPUState at that point in the JIT generated code.
     303    //
     304    // If the user probe function alters the register values in the ProbeContext,
     305    // the altered values will be loaded into the CPU registers when the probe
     306    // returns.
     307    //
     308    // The ProbeContext is stack allocated and is only valid for the duration
     309    // of the call to the user probe function.
     310
     311    void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0);
     312#endif // USE(MASM_PROBE)
     313
    290314private:
    291315    friend class LinkBuffer;
     
    306330        X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
    307331    }
     332
     333#if USE(MASM_PROBE)
     334    inline TrustedImm32 trustedImm32FromPtr(void* ptr)
     335    {
     336        return TrustedImm32(TrustedImmPtr(ptr));
     337    }
     338
     339    inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function)
     340    {
     341        return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
     342    }
     343
     344    inline TrustedImm32 trustedImm32FromPtr(void (*function)())
     345    {
     346        return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
     347    }
     348#endif
    308349};
    309350
     351#if USE(MASM_PROBE)
     352
     353extern "C" void ctiMasmProbeTrampoline();
     354
     355// What code is emitted for the probe?
     356// ==================================
     357// We want to keep the size of the emitted probe invocation code as compact as
     358// possible to minimize the perturbation to the JIT generated code. However,
     359// we also need to preserve the CPU registers and set up the ProbeContext to be
     360// passed to the user probe function.
     361//
     362// Hence, we do only the minimum here to preserve the eax (to be used as a
     363// scratch register) and esp registers, and pass the probe arguments. We'll let
     364// the ctiMasmProbeTrampoline handle the rest of the probe invocation work
     365// i.e. saving the CPUState (and setting up the ProbeContext), calling the user
     366// probe function, and restoring the CPUState before returning to JIT generated
     367// code.
     368//
     369// What values are in the saved registers?
     370// ======================================
     371// Conceptually, the saved registers should contain values as if the probe
     372// is not present in the JIT generated code. Hence, they should contain values
     373// that are expected at the start of the instruction immediately following the
     374// probe.
     375//
     376// Specifcally, the saved esp will point to the stack position before we
     377// push the ProbeContext frame. The saved eip will point to the address of
     378// the instruction immediately following the probe.
     379
     380inline void MacroAssemblerX86::probe(MacroAssemblerX86::ProbeFunction function, void* arg1, void* arg2)
     381{
     382    RegisterID esp = RegisterID::esp;
     383    #define probeContextField(field) Address(esp, offsetof(ProbeContext, field))
     384
     385    // The X86_64 ABI specifies that the worse case stack alignment requirement
     386    // is 32 bytes.
     387    const int probeFrameSize = WTF::roundUpToMultipleOf(32, sizeof(ProbeContext));
     388    sub32(TrustedImm32(probeFrameSize), esp);
     389
     390    store32(RegisterID::eax, probeContextField(cpu.eax));
     391
     392    move(TrustedImm32(probeFrameSize), RegisterID::eax);
     393    add32(esp, RegisterID::eax);
     394    store32(RegisterID::eax, probeContextField(cpu.esp));
     395
     396    store32(trustedImm32FromPtr(function), probeContextField(probeFunction));
     397    store32(trustedImm32FromPtr(arg1), probeContextField(arg1));
     398    store32(trustedImm32FromPtr(arg2), probeContextField(arg2));
     399
     400    move(trustedImm32FromPtr(ctiMasmProbeTrampoline), RegisterID::eax);
     401    call(RegisterID::eax);
     402
     403    #undef probeContextField
     404}
     405#endif // USE(MASM_PROBE)
     406
    310407} // namespace JSC
    311408
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r153121 r153162  
    3434namespace JSC {
    3535
     36struct JITStackFrame;
     37
    3638class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> {
    3739protected:
     
    14391441        return X86Assembler::maxJumpReplacementSize();
    14401442    }
     1443
     1444#if USE(MASM_PROBE)
     1445    struct CPUState {
     1446        #define DECLARE_REGISTER(_type, _regName) \
     1447            _type _regName;
     1448        FOR_EACH_CPU_REGISTER(DECLARE_REGISTER)
     1449        #undef DECLARE_REGISTER
     1450    };
     1451
     1452    struct ProbeContext;
     1453    typedef void (*ProbeFunction)(struct ProbeContext*);
     1454
     1455    struct ProbeContext {
     1456        ProbeFunction probeFunction;
     1457        void* arg1;
     1458        void* arg2;
     1459        JITStackFrame* jitStackFrame;
     1460        CPUState cpu;
     1461
     1462        void dump(const char* indentation = 0);
     1463    private:
     1464        void dumpCPURegisters(const char* indentation);
     1465    };
     1466#endif // USE(MASM_PROBE)
    14411467
    14421468protected:
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h

    r135330 r153162  
    3131#include "MacroAssemblerX86Common.h"
    3232
     33#if USE(MASM_PROBE)
     34#include <wtf/StdLibExtras.h>
     35#endif
     36
    3337#define REPTACH_OFFSET_CALL_R11 3
    3438
     
    613617    }
    614618
     619#if USE(MASM_PROBE)
     620    // This function emits code to preserve the CPUState (e.g. registers),
     621    // call a user supplied probe function, and restore the CPUState before
     622    // continuing with other JIT generated code.
     623    //
     624    // The user supplied probe function will be called with a single pointer to
     625    // a ProbeContext struct (defined above) which contains, among other things,
     626    // the preserved CPUState. This allows the user probe function to inspect
     627    // the CPUState at that point in the JIT generated code.
     628    //
     629    // If the user probe function alters the register values in the ProbeContext,
     630    // the altered values will be loaded into the CPU registers when the probe
     631    // returns.
     632    //
     633    // The ProbeContext is stack allocated and is only valid for the duration
     634    // of the call to the user probe function.
     635
     636    void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0);
     637#endif // USE(MASM_PROBE)
     638
    615639private:
    616640    friend class LinkBuffer;
     
    635659    }
    636660
     661#if USE(MASM_PROBE)
     662    inline TrustedImm64 trustedImm64FromPtr(void* ptr)
     663    {
     664        return TrustedImm64(TrustedImmPtr(ptr));
     665    }
     666
     667    inline TrustedImm64 trustedImm64FromPtr(ProbeFunction function)
     668    {
     669        return TrustedImm64(TrustedImmPtr(reinterpret_cast<void*>(function)));
     670    }
     671
     672    inline TrustedImm64 trustedImm64FromPtr(void (*function)())
     673    {
     674        return TrustedImm64(TrustedImmPtr(reinterpret_cast<void*>(function)));
     675    }
     676#endif
    637677};
    638678
     679#if USE(MASM_PROBE)
     680
     681extern "C" void ctiMasmProbeTrampoline();
     682
     683// What code is emitted for the probe?
     684// ==================================
     685// We want to keep the size of the emitted probe invocation code as compact as
     686// possible to minimize the perturbation to the JIT generated code. However,
     687// we also need to preserve the CPU registers and set up the ProbeContext to be
     688// passed to the user probe function.
     689//
     690// Hence, we do only the minimum here to preserve the rax (to be used as a
     691// scratch register) and rsp registers, and pass the probe arguments. We'll let
     692// the ctiMasmProbeTrampoline handle the rest of the probe invocation work
     693// i.e. saving the CPUState (and setting up the ProbeContext), calling the user
     694// probe function, and restoring the CPUState before returning to JIT generated
     695// code.
     696//
     697// What values are in the saved registers?
     698// ======================================
     699// Conceptually, the saved registers should contain values as if the probe
     700// is not present in the JIT generated code. Hence, they should contain values
     701// that are expected at the start of the instruction immediately following the
     702// probe.
     703//
     704// Specifcally, the saved rsp will point to the stack position before we
     705// push the ProbeContext frame. The saved rip will point to the address of
     706// the instruction immediately following the probe.
     707
     708inline void MacroAssemblerX86_64::probe(MacroAssemblerX86_64::ProbeFunction function, void* arg1, void* arg2)
     709{
     710    RegisterID esp = RegisterID::esp;
     711    #define probeContextField(field) Address(esp, offsetof(ProbeContext, field))
     712
     713    // The X86_64 ABI specifies that the worse case stack alignment requirement
     714    // is 32 bytes.
     715    const int probeFrameSize = WTF::roundUpToMultipleOf(32, sizeof(ProbeContext));
     716    sub64(TrustedImm32(probeFrameSize), esp);
     717
     718    store64(RegisterID::eax, probeContextField(cpu.eax));
     719
     720    move(TrustedImm32(probeFrameSize), RegisterID::eax);
     721    add64(esp, RegisterID::eax);
     722    store64(RegisterID::eax, probeContextField(cpu.esp));
     723
     724    store64(trustedImm64FromPtr(function), probeContextField(probeFunction));
     725    store64(trustedImm64FromPtr(arg1), probeContextField(arg1));
     726    store64(trustedImm64FromPtr(arg2), probeContextField(arg2));
     727
     728    move(trustedImm64FromPtr(ctiMasmProbeTrampoline), RegisterID::eax);
     729    call(RegisterID::eax);
     730
     731    #undef probeContextField
     732}
     733#endif // USE(MASM_PROBE)
     734
    639735} // namespace JSC
    640736
  • trunk/Source/JavaScriptCore/assembler/X86Assembler.h

    r148696 r153162  
    11/*
    2  * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3535#include <wtf/Vector.h>
    3636
     37#if USE(MASM_PROBE)
     38#include <xmmintrin.h>
     39#endif
     40
    3741namespace JSC {
    3842
     
    7276        xmm7,
    7377    } XMMRegisterID;
     78
     79#if USE(MASM_PROBE)
     80    #define FOR_EACH_CPU_REGISTER(V) \
     81        FOR_EACH_CPU_GPREGISTER(V) \
     82        FOR_EACH_CPU_FPREGISTER(V)
     83
     84    #define FOR_EACH_CPU_GPREGISTER(V) \
     85        V(void*, eax) \
     86        V(void*, ecx) \
     87        V(void*, edx) \
     88        V(void*, ebx) \
     89        V(void*, esp) \
     90        V(void*, ebp) \
     91        V(void*, esi) \
     92        V(void*, edi) \
     93        FOR_EACH_X86_64_CPU_GPREGISTER(V) \
     94        V(void*, eip)
     95
     96    #define FOR_EACH_CPU_FPREGISTER(V) \
     97        V(__m128, xmm0) \
     98        V(__m128, xmm1) \
     99        V(__m128, xmm2) \
     100        V(__m128, xmm3) \
     101        V(__m128, xmm4) \
     102        V(__m128, xmm5) \
     103        V(__m128, xmm6) \
     104        V(__m128, xmm7)
     105
     106#if CPU(X86)
     107    #define FOR_EACH_X86_64_CPU_GPREGISTER(V) // Nothing to add.
     108#elif CPU(X86_64)
     109    #define FOR_EACH_X86_64_CPU_GPREGISTER(V) \
     110        V(void*, r8) \
     111        V(void*, r9) \
     112        V(void*, r10) \
     113        V(void*, r11) \
     114        V(void*, r12) \
     115        V(void*, r13) \
     116        V(void*, r14) \
     117        V(void*, r15)
     118#endif // CPU(X86_64)
     119#endif // USE(MASM_PROBE)
    74120}
    75121
Note: See TracChangeset for help on using the changeset viewer.