Ignore:
Timestamp:
Aug 20, 2017, 9:26:40 PM (8 years ago)
Author:
[email protected]
Message:

Enhance MacroAssembler::probe() to allow the probe function to resize the stack frame and alter stack data in one pass.
https://bugs.webkit.org/show_bug.cgi?id=175688
<rdar://problem/33436870>

Reviewed by JF Bastien.

With this patch, the clients of the MacroAssembler::probe() can now change
stack values without having to worry about whether there is enough room in the
current stack frame for it or not. This is done using the Probe::Context's stack
member like so:

jit.probe([] (Probe::Context& context) {

auto cpu = context.cpu;
auto stack = context.stack();
uintptr_t* currentSP = cpu.sp<uintptr_t*>();

Get a value at the current stack pointer location.
auto value = stack.get<uintptr_t>(currentSP);

Set a value above the current stack pointer (within current frame).
stack.set<uintptr_t>(currentSP + 10, value);

Set a value below the current stack pointer (out of current frame).
stack.set<uintptr_t>(currentSP - 10, value);

Set the new stack pointer.
cpu.sp() = currentSP - 20;

});

What happens behind the scene:

  1. the generated JIT probe code will now call Probe::executeProbe(), and Probe::executeProbe() will in turn call the client's probe function.

Probe::executeProbe() receives the Probe::State on the machine stack passed
to it by the probe trampoline. Probe::executeProbe() will instantiate a
Probe::Context to be passed to the client's probe function. The client will
no longer see the Probe::State directly.

  1. The Probe::Context comes with a Probe::Stack which serves as a manager of stack pages. Currently, each page is 1K in size. Probe::Context::stack() returns a reference to an instance of Probe::Stack.
  1. Invoking get() of set() on Probe::Stack with an address will lead to the following:
  1. the address will be decoded to a baseAddress that points to the 1K page that contains that address.
  1. the Probe::Stack will check if it already has a cached 1K page for that baseAddress. If so, go to step (f). Else, continue with step (c).
  1. the Probe::Stack will malloc a 1K mirror page, and memcpy the 1K stack page for that specified baseAddress to this mirror page.
  1. the mirror page will be added to the ProbeStack's m_pages HashMap, keyed on the baseAddress.
  1. the ProbeStack will also cache the last baseAddress and its corresponding mirror page in use. With memory accesses tending to be localized, this will save us from having to look up the page in the HashMap.
  1. get() will map the requested address to a physical address in the mirror page, and return the value at that location.
  1. set() will map the requested address to a physical address in the mirror page, and set the value at that location in the mirror page.

set() will also set a dirty bit corresponding to the "cache line" that
was modified in the mirror page.

  1. When the client's probe function returns, Probe::executeProbe() will check if there are stack changes that need to be applied. If stack changes are needed:
  1. Probe::executeProbe() will adjust the stack pointer to ensure enough stack space is available to flush the dirty stack pages. It will also register a flushStackDirtyPages callback function in the Probe::State. Thereafter, Probe::executeProbe() returns to the probe trampoline.
  1. the probe trampoline adjusts the stack pointer, moves the Probe::State to a safe place if needed, and then calls the flushStackDirtyPages callback if needed.
  1. the flushStackDirtyPages() callback iterates the Probe::Stack's m_pages HashMap and flush all dirty "cache lines" to the machine stack. Thereafter, flushStackDirtyPages() returns to the probe trampoline.
  1. lastly, the probe trampoline will restore all register values and return to the pc set in the Probe::State.

To make this patch work, I also had to do the following work:

  1. Refactor MacroAssembler::CPUState into Probe::CPUState. Mainly, this means moving the code over to ProbeContext.h. I also added some convenience accessor methods for spr registers.

Moved Probe::Context over to its own file ProbeContext.h/cpp.

  1. Fix all probe trampolines to pass the address of Probe::executeProbe in addition to the client's probe function and arg.

I also took this opportunity to optimize the generated JIT probe code to
minimize the amount of memory stores needed.

  1. Simplified the ARM64 probe trampoline. The ARM64 probe only supports changing either lr or pc (or neither), but not both at in the same probe invocation. The ARM64 probe trampoline used to have to check for this invariant in the assembly trampoline code. With the introduction of Probe::executeProbe(), we can now do it there and simplify the trampoline.
  1. Fix a bug in the old ARM64 probe trampoline for the case where the client changes lr. That code path never worked before, but has now been fixed.
  1. Removed trustedImm32FromPtr() helper functions in MacroAssemblerARM and MacroAssemblerARMv7.

We can now use move() with TrustedImmPtr, and it does the same thing but in a
more generic way.

  1. ARMv7's move() emitter may encode a T1 move instruction, which happens to have

the same semantics as movs (according to the Thumb spec). This means these
instructions may trash the APSR flags before we have a chance to preserve them.

This patch changes MacroAssemblerARMv7's probe() to preserve the APSR register
early on. This entails adding support for the mrs instruction in the
ARMv7Assembler.

  1. Change testmasm's testProbeModifiesStackValues() to now modify stack values

the easy way.

Also fixed testmasm tests which check flag registers to only compare the
portions that are modifiable by the client i.e. some masking is applied.

This patch has passed the testmasm tests on x86, x86_64, arm64, and armv7.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • assembler/ARMv7Assembler.h:

(JSC::ARMv7Assembler::mrs):

  • assembler/AbstractMacroAssembler.h:
  • assembler/MacroAssembler.cpp:

(JSC::stdFunctionCallback):
(JSC::MacroAssembler::probe):

  • assembler/MacroAssembler.h:

(JSC::MacroAssembler::CPUState::gprName): Deleted.
(JSC::MacroAssembler::CPUState::sprName): Deleted.
(JSC::MacroAssembler::CPUState::fprName): Deleted.
(JSC::MacroAssembler::CPUState::gpr): Deleted.
(JSC::MacroAssembler::CPUState::spr): Deleted.
(JSC::MacroAssembler::CPUState::fpr): Deleted.
(JSC:: const): Deleted.
(JSC::MacroAssembler::CPUState::fpr const): Deleted.
(JSC::MacroAssembler::CPUState::pc): Deleted.
(JSC::MacroAssembler::CPUState::fp): Deleted.
(JSC::MacroAssembler::CPUState::sp): Deleted.
(JSC::MacroAssembler::CPUState::pc const): Deleted.
(JSC::MacroAssembler::CPUState::fp const): Deleted.
(JSC::MacroAssembler::CPUState::sp const): Deleted.
(JSC::Probe::State::gpr): Deleted.
(JSC::Probe::State::spr): Deleted.
(JSC::Probe::State::fpr): Deleted.
(JSC::Probe::State::gprName): Deleted.
(JSC::Probe::State::sprName): Deleted.
(JSC::Probe::State::fprName): Deleted.
(JSC::Probe::State::pc): Deleted.
(JSC::Probe::State::fp): Deleted.
(JSC::Probe::State::sp): Deleted.

  • assembler/MacroAssemblerARM.cpp:

(JSC::MacroAssembler::probe):

  • assembler/MacroAssemblerARM.h:

(JSC::MacroAssemblerARM::trustedImm32FromPtr): Deleted.

  • assembler/MacroAssemblerARM64.cpp:

(JSC::MacroAssembler::probe):
(JSC::arm64ProbeError): Deleted.

  • assembler/MacroAssemblerARMv7.cpp:

(JSC::MacroAssembler::probe):

  • assembler/MacroAssemblerARMv7.h:

(JSC::MacroAssemblerARMv7::armV7Condition):
(JSC::MacroAssemblerARMv7::trustedImm32FromPtr): Deleted.

  • assembler/MacroAssemblerPrinter.cpp:

(JSC::Printer::printCallback):

  • assembler/MacroAssemblerPrinter.h:
  • assembler/MacroAssemblerX86Common.cpp:

(JSC::ctiMasmProbeTrampoline):
(JSC::MacroAssembler::probe):

  • assembler/Printer.h:

(JSC::Printer::Context::Context):

  • assembler/ProbeContext.cpp: Added.

(JSC::Probe::executeProbe):
(JSC::Probe::handleProbeStackInitialization):
(JSC::Probe::probeStateForContext):

  • assembler/ProbeContext.h: Added.

(JSC::Probe::CPUState::gprName):
(JSC::Probe::CPUState::sprName):
(JSC::Probe::CPUState::fprName):
(JSC::Probe::CPUState::gpr):
(JSC::Probe::CPUState::spr):
(JSC::Probe::CPUState::fpr):
(JSC::Probe:: const):
(JSC::Probe::CPUState::fpr const):
(JSC::Probe::CPUState::pc):
(JSC::Probe::CPUState::fp):
(JSC::Probe::CPUState::sp):
(JSC::Probe::CPUState::pc const):
(JSC::Probe::CPUState::fp const):
(JSC::Probe::CPUState::sp const):
(JSC::Probe::Context::Context):
(JSC::Probe::Context::gpr):
(JSC::Probe::Context::spr):
(JSC::Probe::Context::fpr):
(JSC::Probe::Context::gprName):
(JSC::Probe::Context::sprName):
(JSC::Probe::Context::fprName):
(JSC::Probe::Context::pc):
(JSC::Probe::Context::fp):
(JSC::Probe::Context::sp):
(JSC::Probe::Context::stack):
(JSC::Probe::Context::hasWritesToFlush):
(JSC::Probe::Context::releaseStack):

  • assembler/ProbeStack.cpp: Added.

(JSC::Probe::Page::Page):
(JSC::Probe::Page::flushWrites):
(JSC::Probe::Stack::Stack):
(JSC::Probe::Stack::hasWritesToFlush):
(JSC::Probe::Stack::flushWrites):
(JSC::Probe::Stack::ensurePageFor):

  • assembler/ProbeStack.h: Added.

(JSC::Probe::Page::baseAddressFor):
(JSC::Probe::Page::chunkAddressFor):
(JSC::Probe::Page::baseAddress):
(JSC::Probe::Page::get):
(JSC::Probe::Page::set):
(JSC::Probe::Page::hasWritesToFlush const):
(JSC::Probe::Page::flushWritesIfNeeded):
(JSC::Probe::Page::dirtyBitFor):
(JSC::Probe::Page::physicalAddressFor):
(JSC::Probe::Stack::Stack):
(JSC::Probe::Stack::lowWatermark):
(JSC::Probe::Stack::get):
(JSC::Probe::Stack::set):
(JSC::Probe::Stack::newStackPointer const):
(JSC::Probe::Stack::setNewStackPointer):
(JSC::Probe::Stack::isValid):
(JSC::Probe::Stack::pageFor):

  • assembler/testmasm.cpp:

(JSC::testProbeReadsArgumentRegisters):
(JSC::testProbeWritesArgumentRegisters):
(JSC::testProbePreservesGPRS):
(JSC::testProbeModifiesStackPointer):
(JSC::testProbeModifiesStackPointerToInsideProbeStateOnStack):
(JSC::testProbeModifiesStackPointerToNBytesBelowSP):
(JSC::testProbeModifiesProgramCounter):
(JSC::testProbeModifiesStackValues):
(JSC::run):
(): Deleted.
(JSC::fillStack): Deleted.
(JSC::testProbeModifiesStackWithCallback): Deleted.

File:
1 edited

Legend:

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

    r220926 r220958  
    3232#include "InitializeThreading.h"
    3333#include "LinkBuffer.h"
     34#include "ProbeContext.h"
    3435#include <wtf/Compiler.h>
    3536#include <wtf/DataLog.h>
     
    6263#endif // ENABLE(MASM_PROBE)
    6364
     65namespace JSC {
     66namespace Probe {
     67
     68JS_EXPORT_PRIVATE void* probeStateForContext(Probe::Context&);
     69
     70} // namespace Probe
     71} // namespace JSC
     72
    6473using namespace JSC;
    6574
     
    6776
    6877#if ENABLE(MASM_PROBE)
    69 using CPUState = MacroAssembler::CPUState;
     78using CPUState = Probe::CPUState;
    7079#endif
    7180
     
    185194#endif
    186195
    187         jit.probe([&] (Probe::State* context) {
    188             auto& cpu = context->cpu;
     196        jit.probe([&] (Probe::Context& context) {
     197            auto& cpu = context.cpu;
    189198            probeWasCalled = true;
    190199            CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR0), testWord(0));
     
    227236
    228237        // Write expected values.
    229         jit.probe([&] (Probe::State* context) {
    230             auto& cpu = context->cpu;
     238        jit.probe([&] (Probe::Context& context) {
     239            auto& cpu = context.cpu;
    231240            probeCallCount++;
    232241            cpu.gpr(GPRInfo::argumentGPR0) = testWord(0);
     
    240249
    241250        // Validate that expected values were written.
    242         jit.probe([&] (Probe::State* context) {
    243             auto& cpu = context->cpu;
     251        jit.probe([&] (Probe::Context& context) {
     252            auto& cpu = context.cpu;
    244253            probeCallCount++;
    245254            CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR0), testWord(0));
     
    283292
    284293        // Write expected values into the registers (except for sp, fp, and pc).
    285         jit.probe([&] (Probe::State* context) {
    286             auto& cpu = context->cpu;
     294        jit.probe([&] (Probe::Context& context) {
     295            auto& cpu = context.cpu;
    287296            probeCallCount++;
    288297            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     
    299308
    300309        // Invoke the probe to call a lot of functions and trash register values.
    301         jit.probe([&] (Probe::State*) {
     310        jit.probe([&] (Probe::Context&) {
    302311            probeCallCount++;
    303312            CHECK_EQ(testFunctionToTrashGPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), 10);
     
    306315
    307316        // Validate that the registers have the expected values.
    308         jit.probe([&] (Probe::State* context) {
    309             auto& cpu = context->cpu;
     317        jit.probe([&] (Probe::Context& context) {
     318            auto& cpu = context.cpu;
    310319            probeCallCount++;
    311320            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     
    323332
    324333        // Restore the original state.
    325         jit.probe([&] (Probe::State* context) {
    326             auto& cpu = context->cpu;
     334        jit.probe([&] (Probe::Context& context) {
     335            auto& cpu = context.cpu;
    327336            probeCallCount++;
    328337            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     
    336345
    337346        // Validate that the original state was restored.
    338         jit.probe([&] (Probe::State* context) {
    339             auto& cpu = context->cpu;
     347        jit.probe([&] (Probe::Context& context) {
     348            auto& cpu = context.cpu;
    340349            probeCallCount++;
    341350            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     
    354363}
    355364
    356 void testProbeModifiesStackPointer(WTF::Function<void*(Probe::State*)> computeModifiedStack)
     365void testProbeModifiesStackPointer(WTF::Function<void*(Probe::Context&)> computeModifiedStackPointer)
    357366{
    358367    unsigned probeCallCount = 0;
     
    367376#elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
    368377    auto flagsSPR = ARMRegisters::apsr;
    369     uintptr_t flagsMask = 0xf0000000;
     378    uintptr_t flagsMask = 0xf8000000;
    370379#elif CPU(ARM64)
    371380    auto flagsSPR = ARM64Registers::nzcv;
     
    378387        // Preserve original stack pointer and modify the sp, and
    379388        // write expected values into other registers (except for fp, and pc).
    380         jit.probe([&] (Probe::State* context) {
    381             auto& cpu = context->cpu;
     389        jit.probe([&] (Probe::Context& context) {
     390            auto& cpu = context.cpu;
    382391            probeCallCount++;
    383392            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     
    397406
    398407            originalSP = cpu.sp();
    399             modifiedSP = computeModifiedStack(context);
     408            modifiedSP = computeModifiedStackPointer(context);
    400409            cpu.sp() = modifiedSP;
    401410        });
    402411
    403412        // Validate that the registers have the expected values.
    404         jit.probe([&] (Probe::State* context) {
    405             auto& cpu = context->cpu;
     413        jit.probe([&] (Probe::Context& context) {
     414            auto& cpu = context.cpu;
    406415            probeCallCount++;
    407416            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     
    416425            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
    417426                CHECK_EQ(cpu.fpr<uint64_t>(id), testWord64(id));
    418             CHECK_EQ(cpu.spr(flagsSPR), modifiedFlags);
     427            CHECK_EQ(cpu.spr(flagsSPR) & flagsMask, modifiedFlags & flagsMask);
    419428            CHECK_EQ(cpu.sp(), modifiedSP);
    420429        });
    421430
    422431        // Restore the original state.
    423         jit.probe([&] (Probe::State* context) {
    424             auto& cpu = context->cpu;
     432        jit.probe([&] (Probe::Context& context) {
     433            auto& cpu = context.cpu;
    425434            probeCallCount++;
    426435            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     
    436445
    437446        // Validate that the original state was restored.
    438         jit.probe([&] (Probe::State* context) {
    439             auto& cpu = context->cpu;
     447        jit.probe([&] (Probe::Context& context) {
     448            auto& cpu = context.cpu;
    440449            probeCallCount++;
    441450            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     
    446455            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
    447456                CHECK_EQ(cpu.fpr<uint64_t>(id), originalState.fpr<uint64_t>(id));
    448             CHECK_EQ(cpu.spr(flagsSPR), originalState.spr(flagsSPR));
     457            CHECK_EQ(cpu.spr(flagsSPR) & flagsMask, originalState.spr(flagsSPR) & flagsMask);
    449458            CHECK_EQ(cpu.sp(), originalSP);
    450459        });
     
    464473#endif
    465474    for (size_t offset = 0; offset < sizeof(Probe::State); offset += increment) {
    466         testProbeModifiesStackPointer([=] (Probe::State* context) -> void* {
    467             return reinterpret_cast<uint8_t*>(context) + offset;
     475        testProbeModifiesStackPointer([=] (Probe::Context& context) -> void* {
     476            return reinterpret_cast<uint8_t*>(probeStateForContext(context)) + offset;
     477
    468478        });
    469479    }
     
    478488#endif
    479489    for (size_t offset = 0; offset < 1 * KB; offset += increment) {
    480         testProbeModifiesStackPointer([=] (Probe::State* context) -> void* {
    481             return reinterpret_cast<uint8_t*>(context->cpu.sp()) - offset;
     490        testProbeModifiesStackPointer([=] (Probe::Context& context) -> void* {
     491            return context.cpu.sp<uint8_t*>() - offset;
    482492        });
    483493    }
     
    494504    MacroAssemblerCodeRef continuation = compile([&] (CCallHelpers& jit) {
    495505        // Validate that we reached the continuation.
    496         jit.probe([&] (Probe::State*) {
     506        jit.probe([&] (Probe::Context&) {
    497507            probeCallCount++;
    498508            continuationWasReached = true;
     
    507517
    508518        // Write expected values into the registers.
    509         jit.probe([&] (Probe::State* context) {
    510             probeCallCount++;
    511             context->pc() = continuation.code().executableAddress();
     519        jit.probe([&] (Probe::Context& context) {
     520            probeCallCount++;
     521            context.cpu.pc() = continuation.code().executableAddress();
    512522        });
    513523
     
    518528}
    519529
    520 struct FillStackData {
     530void testProbeModifiesStackValues()
     531{
     532    unsigned probeCallCount = 0;
    521533    CPUState originalState;
    522534    void* originalSP { nullptr };
    523535    void* newSP { nullptr };
    524536    uintptr_t modifiedFlags { 0 };
    525     MacroAssembler::SPRegisterID flagsSPR;
    526 };
    527 
    528 static void fillStack(Probe::State* context)
    529 {
    530     auto& cpu = context->cpu;
    531 
    532     FillStackData& data = *reinterpret_cast<FillStackData*>(context->initializeStackArg);
    533     CPUState& originalState = data.originalState;
    534     void*& originalSP = data.originalSP;
    535     void*& newSP = data.newSP;
    536     uintptr_t& modifiedFlags = data.modifiedFlags;
    537     MacroAssembler::SPRegisterID& flagsSPR = data.flagsSPR;
    538 
    539     CHECK_EQ(reinterpret_cast<void*>(context->initializeStackFunction), reinterpret_cast<void*>(fillStack));
    540     CHECK_EQ(cpu.sp(), newSP);
    541 
    542     // Verify that the probe has put the Probe::State out of harm's way.
    543     CHECK_EQ((reinterpret_cast<void*>(context + 1) <= cpu.sp()), true);
    544 
    545     // Verify the CPU state.
    546     for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
    547         if (isFP(id)) {
    548             CHECK_EQ(cpu.gpr(id), originalState.gpr(id));
    549             continue;
    550         }
    551         if (isSpecialGPR(id))
    552             continue;
    553         CHECK_EQ(cpu.gpr(id), testWord(id));
    554     }
    555     for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
    556         CHECK_EQ(cpu.fpr<uint64_t>(id), testWord64(id));
    557     CHECK_EQ(cpu.spr(flagsSPR), modifiedFlags);
    558 
    559     // Fill the stack with values.
    560     uintptr_t* p = reinterpret_cast<uintptr_t*>(newSP);
    561     int count = 0;
    562     while (p < reinterpret_cast<uintptr_t*>(originalSP))
    563         *p++ = testWord(count++);
    564 };
    565 
    566 void testProbeModifiesStackWithCallback()
    567 {
    568     unsigned probeCallCount = 0;
    569     FillStackData data;
    570     CPUState& originalState = data.originalState;
    571     void*& originalSP = data.originalSP;
    572     void*& newSP = data.newSP;
    573     uintptr_t& modifiedFlags = data.modifiedFlags;
    574     size_t numberOfExtraEntriesToWrite = 10; // ARM64 requires that this be 2 word aligned.
    575     MacroAssembler::SPRegisterID& flagsSPR = data.flagsSPR;
     537    size_t numberOfExtraEntriesToWrite { 10 }; // ARM64 requires that this be 2 word aligned.
    576538
    577539#if CPU(X86) || CPU(X86_64)
    578     flagsSPR = X86Registers::eflags;
     540    MacroAssembler::SPRegisterID flagsSPR = X86Registers::eflags;
    579541    uintptr_t flagsMask = 0xc5;
    580542#elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
    581     flagsSPR = ARMRegisters::apsr;
    582     uintptr_t flagsMask = 0xf0000000;
     543    MacroAssembler::SPRegisterID flagsSPR = ARMRegisters::apsr;
     544    uintptr_t flagsMask = 0xf8000000;
    583545#elif CPU(ARM64)
    584     flagsSPR = ARM64Registers::nzcv;
     546    MacroAssembler::SPRegisterID flagsSPR = ARM64Registers::nzcv;
    585547    uintptr_t flagsMask = 0xf0000000;
    586548#endif
     
    590552
    591553        // Write expected values into the registers.
    592         jit.probe([&] (Probe::State* context) {
    593             auto& cpu = context->cpu;
     554        jit.probe([&] (Probe::Context& context) {
     555            auto& cpu = context.cpu;
     556            auto& stack = context.stack();
    594557            probeCallCount++;
    595558
     
    609572            cpu.spr(flagsSPR) = modifiedFlags;
    610573
    611             CHECK_EQ(reinterpret_cast<void*>(context->initializeStackFunction), 0);
    612 
    613             // Prepare for initializeStack callback.
    614             context->initializeStackFunction = fillStack;
    615             context->initializeStackArg = &data;
    616 
    617574            // Ensure that we'll be writing over the regions of the stack where the Probe::State is.
    618575            originalSP = cpu.sp();
    619             newSP = reinterpret_cast<uintptr_t*>(context) - numberOfExtraEntriesToWrite;
     576            newSP = reinterpret_cast<uintptr_t*>(probeStateForContext(context)) - numberOfExtraEntriesToWrite;
    620577            cpu.sp() = newSP;
     578
     579            // Fill the stack with values.
     580            uintptr_t* p = reinterpret_cast<uintptr_t*>(newSP);
     581            int count = 0;
     582            stack.set<double>(p++, 1.23456789);
     583            if (is32Bit())
     584                p++; // On 32-bit targets, a double takes up 2 uintptr_t.
     585            while (p < reinterpret_cast<uintptr_t*>(originalSP))
     586                stack.set<uintptr_t>(p++, testWord(count++));
    621587        });
    622588
    623589        // Validate that the registers and stack have the expected values.
    624         jit.probe([&] (Probe::State* context) {
    625             auto& cpu = context->cpu;
     590        jit.probe([&] (Probe::Context& context) {
     591            auto& cpu = context.cpu;
     592            auto& stack = context.stack();
    626593            probeCallCount++;
    627594
     
    638605            for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
    639606                CHECK_EQ(cpu.fpr<uint64_t>(id), testWord64(id));
    640             CHECK_EQ(cpu.spr(flagsSPR), modifiedFlags);
     607            CHECK_EQ(cpu.spr(flagsSPR) & flagsMask, modifiedFlags & flagsMask);
    641608            CHECK_EQ(cpu.sp(), newSP);
    642609
    643             // Validate the stack with values.
     610            // Validate the stack values.
    644611            uintptr_t* p = reinterpret_cast<uintptr_t*>(newSP);
    645612            int count = 0;
     613            CHECK_EQ(stack.get<double>(p++), 1.23456789);
     614            if (is32Bit())
     615                p++; // On 32-bit targets, a double takes up 2 uintptr_t.
    646616            while (p < reinterpret_cast<uintptr_t*>(originalSP))
    647                 CHECK_EQ(*p++, testWord(count++));
     617                CHECK_EQ(stack.get<uintptr_t>(p++), testWord(count++));
    648618        });
    649619
    650620        // Restore the original state.
    651         jit.probe([&] (Probe::State* context) {
    652             auto& cpu = context->cpu;
     621        jit.probe([&] (Probe::Context& context) {
     622            auto& cpu = context.cpu;
    653623            probeCallCount++;
    654624            for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
     
    708678    RUN(testProbeModifiesStackPointerToNBytesBelowSP());
    709679    RUN(testProbeModifiesProgramCounter());
    710     RUN(testProbeModifiesStackWithCallback());
     680    RUN(testProbeModifiesStackValues());
    711681#endif // ENABLE(MASM_PROBE)
    712682
Note: See TracChangeset for help on using the changeset viewer.