Commit e9743fd0 authored by oliver@apple.com's avatar oliver@apple.com
Browse files

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:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153162 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 90fce824
......@@ -542,6 +542,9 @@ if (WTF_CPU_ARM)
endif ()
elseif (WTF_CPU_MIPS)
elseif (WTF_CPU_X86)
list(APPEND JavaScriptCore_SOURCES
assembler/MacroAssemblerX86Common.cpp
)
elseif (WTF_CPU_X86_64)
if (MSVC AND ENABLE_JIT)
add_custom_command(
......@@ -552,6 +555,9 @@ elseif (WTF_CPU_X86_64)
list(APPEND JavaScriptCore_SOURCES ${DERIVED_SOURCES_DIR}/JITStubsMSVC64.obj)
endif ()
list(APPEND JavaScriptCore_SOURCES
assembler/MacroAssemblerX86Common.cpp
)
else ()
message(FATAL_ERROR "Unknown CPU")
endif ()
......
2013-05-16 Mark Lam <mark.lam@apple.com>
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:
2013-05-15 Mark Lam <mark.lam@apple.com>
Fix for broken 32-bit build in SpeculativeJIT::checkArray().
......
......@@ -79,6 +79,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h \
Source/JavaScriptCore/assembler/MacroAssemblerSH4.h \
Source/JavaScriptCore/assembler/MacroAssemblerX86.h \
Source/JavaScriptCore/assembler/MacroAssemblerX86Common.cpp \
Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h \
Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h \
Source/JavaScriptCore/assembler/MIPSAssembler.h \
......
......@@ -291,6 +291,7 @@
<ClCompile Include="..\API\OpaqueJSString.cpp" />
<ClCompile Include="..\assembler\LinkBuffer.cpp" />
<ClCompile Include="..\assembler\MacroAssembler.cpp" />
<ClInclude Include="..\assembler\MacroAssemblerX86Common.cpp" />
<ClCompile Include="..\bytecode\ArrayAllocationProfile.cpp" />
<ClCompile Include="..\bytecode\ArrayProfile.cpp" />
<ClCompile Include="..\bytecode\CallLinkInfo.cpp" />
......@@ -706,6 +707,7 @@
<ClInclude Include="..\jit\JITStubRoutine.h" />
<ClInclude Include="..\jit\JITStubs.h" />
<ClInclude Include="..\jit\JITStubsX86.h" />
<ClInclude Include="..\jit\JITStubsX86Common.h" />
<ClInclude Include="..\jit\JITStubsX86_64.h" />
<ClInclude Include="..\jit\JITThunks.h" />
<ClInclude Include="..\jit\JITWriteBarrier.h" />
......
......@@ -102,6 +102,9 @@
<ClCompile Include="..\assembler\MacroAssembler.cpp">
<Filter>assembler</Filter>
</ClCompile>
<ClCompile Include="..\assembler\MacroAssemblerX86Common.cpp">
<Filter>assembler</Filter>
</ClCompile>
<ClCompile Include="..\bytecode\ArrayAllocationProfile.cpp">
<Filter>bytecode</Filter>
</ClCompile>
......@@ -1271,6 +1274,15 @@
<ClInclude Include="..\jit\JITStubs.h">
<Filter>jit</Filter>
</ClInclude>
<ClInclude Include="..\jit\JITStubsX86.h">
<Filter>jit</Filter>
</ClInclude>
<ClInclude Include="..\jit\JITStubsX86Common.h">
<Filter>jit</Filter>
</ClInclude>
<ClInclude Include="..\jit\JITStubsX86_64.h">
<Filter>jit</Filter>
</ClInclude>
<ClInclude Include="..\jit\JITThunks.h">
<Filter>jit</Filter>
</ClInclude>
......
......@@ -777,6 +777,10 @@
A78A977F179738D5009DF744 /* FTLGeneratedFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = A78A977C179738D5009DF744 /* FTLGeneratedFunction.h */; };
A78A9780179738D5009DF744 /* FTLJITFinalizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78A977D179738D5009DF744 /* FTLJITFinalizer.cpp */; };
A78A9781179738D5009DF744 /* FTLJITFinalizer.h in Headers */ = {isa = PBXBuildFile; fileRef = A78A977E179738D5009DF744 /* FTLJITFinalizer.h */; };
A7A4AE0817973B26005612B1 /* MacroAssemblerX86Common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7A4AE0717973B26005612B1 /* MacroAssemblerX86Common.cpp */; };
A7A4AE0D17973B4D005612B1 /* JITStubsMIPS.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A4AE0917973B4D005612B1 /* JITStubsMIPS.h */; };
A7A4AE0F17973B4D005612B1 /* JITStubsSH4.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A4AE0B17973B4D005612B1 /* JITStubsSH4.h */; };
A7A4AE1017973B4D005612B1 /* JITStubsX86Common.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A4AE0C17973B4D005612B1 /* JITStubsX86Common.h */; };
A7AFC17915F7EFE30048F57B /* ResolveOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = A7AFC17715F7EFE30048F57B /* ResolveOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7B48F490EE8936F00DCBDB6 /* ExecutableAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */; };
A7B4ACAF1484C9CE00B38A36 /* JSExportMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B4ACAE1484C9CE00B38A36 /* JSExportMacros.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -1791,6 +1795,10 @@
A79E781E15EECBA80047C855 /* UnlinkedCodeBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnlinkedCodeBlock.cpp; sourceTree = "<group>"; };
A79E781F15EECBA80047C855 /* UnlinkedCodeBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnlinkedCodeBlock.h; sourceTree = "<group>"; };
A79EDB0811531CD60019E912 /* JSObjectRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSObjectRefPrivate.h; sourceTree = "<group>"; };
A7A4AE0717973B26005612B1 /* MacroAssemblerX86Common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacroAssemblerX86Common.cpp; sourceTree = "<group>"; };
A7A4AE0917973B4D005612B1 /* JITStubsMIPS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubsMIPS.h; sourceTree = "<group>"; };
A7A4AE0B17973B4D005612B1 /* JITStubsSH4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubsSH4.h; sourceTree = "<group>"; };
A7A4AE0C17973B4D005612B1 /* JITStubsX86Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubsX86Common.h; sourceTree = "<group>"; };
A7A7EE7411B98B8D0065A14F /* ASTBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTBuilder.h; sourceTree = "<group>"; };
A7A7EE7711B98B8D0065A14F /* SyntaxChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyntaxChecker.h; sourceTree = "<group>"; };
A7AFC17715F7EFE30048F57B /* ResolveOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResolveOperation.h; sourceTree = "<group>"; };
......@@ -2289,6 +2297,9 @@
1429D92C0ED22D7000B89619 /* jit */ = {
isa = PBXGroup;
children = (
A7A4AE0917973B4D005612B1 /* JITStubsMIPS.h */,
A7A4AE0B17973B4D005612B1 /* JITStubsSH4.h */,
A7A4AE0C17973B4D005612B1 /* JITStubsX86Common.h */,
0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */,
0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */,
0FD82E37141AB14200179C94 /* CompactJITCodeMap.h */,
......@@ -3121,6 +3132,7 @@
9688CB120ED12B4E001D649F /* assembler */ = {
isa = PBXGroup;
children = (
A7A4AE0717973B26005612B1 /* MacroAssemblerX86Common.cpp */,
860161DF0F3A83C100F84710 /* AbstractMacroAssembler.h */,
86D3B2BF10156BDE002865E7 /* ARMAssembler.cpp */,
86D3B2C010156BDE002865E7 /* ARMAssembler.h */,
......@@ -3336,6 +3348,7 @@
0F63948515E4811B006A597C /* DFGArrayMode.h in Headers */,
0FC0976D1468AB4E00CF2442 /* DFGAssemblyHelpers.h in Headers */,
0F714CA516EA92F200F3EBEB /* DFGBackwardsPropagationPhase.h in Headers */,
A7A4AE0D17973B4D005612B1 /* JITStubsMIPS.h in Headers */,
0F620176143FCD3B0068B77C /* DFGBasicBlock.h in Headers */,
0FFB921A16D02EC50055A5DB /* DFGBasicBlockInlines.h in Headers */,
0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */,
......@@ -3480,6 +3493,7 @@
14F97447138C853E00DA1C67 /* HeapRootVisitor.h in Headers */,
C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */,
C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */,
A7A4AE0F17973B4D005612B1 /* JITStubsSH4.h in Headers */,
0F4680D514BBD24B00BFE272 /* HostCallReturnValue.h in Headers */,
BC18C40F0E16F5CD00B34460 /* Identifier.h in Headers */,
C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */,
......@@ -3671,6 +3685,7 @@
0FF729BF166AD360000F5BA3 /* ProfilerOrigin.h in Headers */,
0FF729C0166AD360000F5BA3 /* ProfilerOriginStack.h in Headers */,
0FB1058C1675483300F8AB6E /* ProfilerOSRExit.h in Headers */,
A7A4AE1017973B4D005612B1 /* JITStubsX86Common.h in Headers */,
0FB1058E1675483A00F8AB6E /* ProfilerOSRExitSite.h in Headers */,
0F13912C16771C3D009CCB07 /* ProfilerProfiledBytecodes.h in Headers */,
A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */,
......@@ -4328,6 +4343,7 @@
862553D116136DA9009F17D0 /* JSProxy.cpp in Sources */,
14874AE515EBDE4A002E3587 /* JSScope.cpp in Sources */,
A7C0C4AD1681067E0017011D /* JSScriptRef.cpp in Sources */,
A7A4AE0817973B26005612B1 /* MacroAssemblerX86Common.cpp in Sources */,
0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */,
1428083A107EC0750013E7B2 /* JSStack.cpp in Sources */,
147F39D5107EC37600427A48 /* JSString.cpp in Sources */,
......
......@@ -51,6 +51,7 @@ SOURCES += \
assembler/LinkBuffer.cpp \
assembler/MacroAssembler.cpp \
assembler/MacroAssemblerARM.cpp \
assembler/MacroAssemblerX86Common.cpp \
bytecode/ArrayAllocationProfile.cpp \
bytecode/ArrayProfile.cpp \
bytecode/CallLinkInfo.cpp \
......
/*
* Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -571,7 +571,9 @@ public:
{
return MacroAssemblerBase::branchTest8(cond, Address(address.base, address.offset), mask);
}
#else
#else // !CPU(X86_64)
void addPtr(RegisterID src, RegisterID dest)
{
add64(src, dest);
......@@ -1067,7 +1069,7 @@ public:
store64(imm.asTrustedImm64(), dest);
}
#endif
#endif // ENABLE(JIT_CONSTANT_BLINDING)
#endif // !CPU(X86_64)
......@@ -1079,7 +1081,7 @@ public:
// Debug always blind all constants, if only so we know
// if we've broken blinding during patch development.
return true;
#else
#else // ENABLE(FORCED_JIT_BLINDING)
// First off we'll special case common, "safe" values to avoid hurting
// performance too much
......@@ -1100,7 +1102,7 @@ public:
return false;
return shouldBlindForSpecificArch(value);
#endif
#endif // ENABLE(FORCED_JIT_BLINDING)
}
struct BlindedImm32 {
......@@ -1271,7 +1273,7 @@ public:
{
store64(value, addressForPoke(index));
}
#endif
#endif // CPU(X86_64)
void store32(Imm32 imm, Address dest)
{
......@@ -1280,7 +1282,7 @@ public:
BlindedImm32 blind = xorBlindConstant(imm);
store32(blind.value1, dest);
xor32(blind.value2, dest);
#else
#else // CPU(X86) || CPU(X86_64)
if (RegisterID scratchRegister = (RegisterID)scratchRegisterForBlinding()) {
loadXorBlindedConstant(xorBlindConstant(imm), scratchRegister);
store32(scratchRegister, dest);
......@@ -1292,7 +1294,7 @@ public:
nop();
store32(imm.asTrustedImm32(), dest);
}
#endif
#endif // CPU(X86) || CPU(X86_64)
} else
store32(imm.asTrustedImm32(), dest);
}
......@@ -1440,7 +1442,7 @@ public:
{
urshift32(src, trustedImm32ForShift(amount), dest);
}
#endif
#endif // ENABLE(JIT_CONSTANT_BLINDING)
};
} // namespace JSC
......
......@@ -30,6 +30,10 @@
#include "MacroAssemblerX86Common.h"
#if USE(MASM_PROBE)
#include <wtf/StdLibExtras.h>
#endif
namespace JSC {
class MacroAssemblerX86 : public MacroAssemblerX86Common {
......@@ -287,6 +291,26 @@ public:
X86Assembler::revertJumpTo_cmpl_im_force32(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), 0, address.base);
}
#if USE(MASM_PROBE)
// This function emits code to preserve the CPUState (e.g. registers),
// call a user supplied probe function, and restore the CPUState before
// continuing with other JIT generated code.
//
// The user supplied probe function will be called with a single pointer to
// a ProbeContext struct (defined above) which contains, among other things,
// the preserved CPUState. This allows the user probe function to inspect
// the CPUState at that point in the JIT generated code.
//
// If the user probe function alters the register values in the ProbeContext,
// the altered values will be loaded into the CPU registers when the probe
// returns.
//
// The ProbeContext is stack allocated and is only valid for the duration
// of the call to the user probe function.
void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0);
#endif // USE(MASM_PROBE)
private:
friend class LinkBuffer;
friend class RepatchBuffer;
......@@ -305,8 +329,81 @@ private:
{
X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
}
#if USE(MASM_PROBE)
inline TrustedImm32 trustedImm32FromPtr(void* ptr)
{
return TrustedImm32(TrustedImmPtr(ptr));
}
inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function)
{
return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
}
inline TrustedImm32 trustedImm32FromPtr(void (*function)())
{
return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
}
#endif
};
#if USE(MASM_PROBE)
extern "C" void ctiMasmProbeTrampoline();
// What code is emitted for the probe?
// ==================================
// We want to keep the size of the emitted probe invocation code as compact as
// possible to minimize the perturbation to the JIT generated code. However,
// we also need to preserve the CPU registers and set up the ProbeContext to be
// passed to the user probe function.
//
// Hence, we do only the minimum here to preserve the eax (to be used as a
// scratch register) and esp registers, and pass the probe arguments. We'll let
// the ctiMasmProbeTrampoline handle the rest of the probe invocation work
// i.e. saving the CPUState (and setting up the ProbeContext), calling the user
// probe function, and restoring the CPUState before returning to JIT generated
// code.
//
// What values are in the saved registers?
// ======================================
// Conceptually, the saved registers should contain values as if the probe
// is not present in the JIT generated code. Hence, they should contain values
// that are expected at the start of the instruction immediately following the
// probe.
//
// Specifcally, the saved esp will point to the stack position before we
// push the ProbeContext frame. The saved eip will point to the address of
// the instruction immediately following the probe.
inline void MacroAssemblerX86::probe(MacroAssemblerX86::ProbeFunction function, void* arg1, void* arg2)
{
RegisterID esp = RegisterID::esp;
#define probeContextField(field) Address(esp, offsetof(ProbeContext, field))
// The X86_64 ABI specifies that the worse case stack alignment requirement
// is 32 bytes.
const int probeFrameSize = WTF::roundUpToMultipleOf(32, sizeof(ProbeContext));
sub32(TrustedImm32(probeFrameSize), esp);
store32(RegisterID::eax, probeContextField(cpu.eax));
move(TrustedImm32(probeFrameSize), RegisterID::eax);
add32(esp, RegisterID::eax);
store32(RegisterID::eax, probeContextField(cpu.esp));
store32(trustedImm32FromPtr(function), probeContextField(probeFunction));
store32(trustedImm32FromPtr(arg1), probeContextField(arg1));
store32(trustedImm32FromPtr(arg2), probeContextField(arg2));
move(trustedImm32FromPtr(ctiMasmProbeTrampoline), RegisterID::eax);
call(RegisterID::eax);
#undef probeContextField
}
#endif // USE(MASM_PROBE)
} // namespace JSC
#endif // ENABLE(ASSEMBLER)
......
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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 "MacroAssemblerX86Common.h"
namespace JSC {
#if USE(MASM_PROBE)
void MacroAssemblerX86Common::ProbeContext::dumpCPURegisters(const char* indentation)
{
#if CPU(X86)
#define DUMP_GPREGISTER(_type, _regName) { \
int32_t value = reinterpret_cast<int32_t>(cpu._regName); \
dataLogF("%s %4s: 0x%08x %d\n", indentation, #_regName, value, value) ; \
}
#elif CPU(X86_64)
#define DUMP_GPREGISTER(_type, _regName) { \
int64_t value = reinterpret_cast<int64_t>(cpu._regName); \
dataLogF("%s %4s: 0x%016llx %lld\n", indentation, #_regName, value, value) ; \
}
#endif
FOR_EACH_CPU_GPREGISTER(DUMP_GPREGISTER)
#undef DUMP_GPREGISTER
#define DUMP_FPREGISTER(_type, _regName) { \
uint32_t* u = reinterpret_cast<uint32_t*>(&cpu._regName); \
double* d = reinterpret_cast<double*>(&cpu._regName); \
dataLogF("%s %s: 0x%08x%08x 0x%08x%08x %12g %12g\n", \
indentation, #_regName, u[3], u[2], u[1], u[0], d[1], d[0]); \
}
FOR_EACH_CPU_FPREGISTER(DUMP_FPREGISTER)
#undef DUMP_FPREGISTER
}
void MacroAssemblerX86Common::ProbeContext::dump(const char* indentation)
{
if (!indentation)
indentation = "";
dataLogF("%sProbeContext %p {\n", indentation, this);
dataLogF("%s probeFunction: %p\n", indentation, probeFunction);
dataLogF("%s arg1: %p %llu\n", indentation, arg1, reinterpret_cast<int64_t>(arg1));
dataLogF("%s arg2: %p %llu\n", indentation, arg2, reinterpret_cast<int64_t>(arg2));
dataLogF("%s jitStackFrame: %p\n", indentation, jitStackFrame);
dataLogF("%s cpu: {\n", indentation);
dumpCPURegisters(indentation);
dataLogF("%s }\n", indentation);
dataLogF("%s}\n", indentation);
}
#endif // USE(MASM_PROBE)
} // namespace JSC
......@@ -33,6 +33,8 @@
namespace JSC {
struct JITStackFrame;
class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> {
protected:
#if CPU(X86_64)
......@@ -1439,6 +1441,30 @@ public:
return X86Assembler::maxJumpReplacementSize();
}
#if USE(MASM_PROBE)
struct CPUState {
#define DECLARE_REGISTER(_type, _regName) \
_type _regName;
FOR_EACH_CPU_REGISTER(DECLARE_REGISTER)
#undef DECLARE_REGISTER
};
struct ProbeContext;
typedef void (*ProbeFunction)(struct ProbeContext*);
struct ProbeContext {
ProbeFunction probeFunction;
void* arg1;
void* arg2;
JITStackFrame* jitStackFrame;
CPUState cpu;
void dump(const char* indentation = 0);
private:
void dumpCPURegisters(const char* indentation);
};
#endif // USE(MASM_PROBE)
protected:
X86Assembler::Condition x86Condition(RelationalCondition cond)
{
......
......@@ -30,6 +30,10 @@
#include "MacroAssemblerX86Common.h"
#if USE(MASM_PROBE)
#include <wtf/StdLibExtras.h>
#endif
#define REPTACH_OFFSET_CALL_R11 3
namespace JSC {
......@@ -612,6 +616,26 @@ public:
X86Assembler::revertJumpTo_movq_i64r(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), scratchRegister);
}
#if USE(MASM_PROBE)
// This function emits code to preserve the CPUState (e.g. registers),
// call a user supplied probe function, and restore the CPUState before
// continuing with other JIT generated code.
//
// The user supplied probe function will be called with a single pointer to
// a ProbeContext struct (defined above) which contains, among other things,
// the preserved CPUState. This allows the user probe function to inspect
// the CPUState at that point in the JIT generated code.
//
// If the user probe function alters the register values in the ProbeContext,
// the altered values will be loaded into the CPU registers when the probe
// returns.
//
// The ProbeContext is stack allocated and is only valid for the duration
// of the call to the user probe function.
void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0);
#endif // USE(MASM_PROBE)
private:
friend class LinkBuffer;
friend class RepatchBuffer;
......@@ -634,8 +658,80 @@ private:
X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
}
#if USE(MASM_PROBE)
inline TrustedImm64 trustedImm64FromPtr(void* ptr)
{
return TrustedImm64(TrustedImmPtr(ptr));
}
inline TrustedImm64 trustedImm64FromPtr(ProbeFunction function)
{
return TrustedImm64(TrustedImmPtr(reinterpret_cast<void*>(function)));