Skip to content

Commit

Permalink
Populate all outgoing call registers in JIT emitted code
Browse files Browse the repository at this point in the history
Summary:
Populate the registers in the emitted code instead of the handler, so
that we can make calls to JIT functions directly in a later diff.

Reviewed By: tmikov

Differential Revision: D64275850

fbshipit-source-id: 3d4505863e88e8e8355a46f01c3a64ffe1eb4f85
  • Loading branch information
neildhar authored and facebook-github-bot committed Nov 13, 2024
1 parent 205d228 commit 4986b03
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 15 deletions.
37 changes: 35 additions & 2 deletions lib/VM/JIT/arm64/JitEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3629,6 +3629,37 @@ void Emitter::callImpl(FR frRes, FR frCallee) {
calleeFrameArg, calleeReg, frameRegs_[frCallee.index()].localType);
}

static_assert(
HERMESVALUE_VERSION == 1,
"Native pointers must be encoded without modification");

FR previousFrameArg{nRegs + hbc::StackFrameLayout::PreviousFrame};
// Free any existing temp so we store directly.
freeFRTemp(previousFrameArg);
movFRFromHW(previousFrameArg, HWReg(xFrame), FRType::OtherNonPtr);

FR savedIPArg{nRegs + hbc::StackFrameLayout::SavedIP};
// Since we need a register to compute the IP in anyway, it is convenient to
// just use any existing one for the SavedIP slot, and let the syncAllFRTemp
// below write it to memory.
auto savedIPReg = getOrAllocFRInGpX(savedIPArg, false);

// Save the current IP in both the SavedIP slot and the runtime.
getBytecodeIP(savedIPReg.a64GpX());
frUpdatedWithHW(savedIPArg, savedIPReg, FRType::OtherNonPtr);
a.str(savedIPReg.a64GpX(), a64::Mem(xRuntime, offsetof(Runtime, currentIP_)));

FR savedCodeBlockArg = FR{nRegs + hbc::StackFrameLayout::SavedCodeBlock};
// TODO: We should be able to directly store xzr.
auto savedCodeBlockReg = getOrAllocFRInGpX(savedCodeBlockArg, false);
frUpdatedWithHW(savedCodeBlockArg, savedCodeBlockReg, FRType::OtherNonPtr);
a.mov(savedCodeBlockReg.a64GpX(), 0);

FR shLocalsArg{nRegs + hbc::StackFrameLayout::SHLocals};
// Free any existing temp so we store directly.
freeFRTemp(shLocalsArg);
movFRFromHW(shLocalsArg, savedCodeBlockReg, FRType::OtherNonPtr);

#ifndef NDEBUG
// No need to sync the set up call stack to the frame memory,
// because it these registers can't have global registers.
Expand All @@ -3643,8 +3674,10 @@ void Emitter::callImpl(FR frRes, FR frCallee) {
freeAllFRTempExcept({});

a.mov(a64::x0, xRuntime);
a.mov(a64::x1, xFrame);
EMIT_RUNTIME_CALL(
loadFrameAddr(
a64::x1,
FR(frameRegs_.size() + hbc::StackFrameLayout::CalleeClosureOrCB));
EMIT_RUNTIME_CALL_WITHOUT_SAVED_IP(
*this,
SHLegacyValue(*)(SHRuntime *, SHLegacyValue *),
_jit_dispatch_call);
Expand Down
14 changes: 4 additions & 10 deletions lib/VM/JIT/arm64/JitHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,18 +264,12 @@ void *_jit_find_catch_target(
_sh_throw_current(shr);
}

SHLegacyValue _jit_dispatch_call(SHRuntime *shr, SHLegacyValue *frame) {
SHLegacyValue _jit_dispatch_call(
SHRuntime *shr,
SHLegacyValue *callTargetSHLV) {
Runtime &runtime = getRuntime(shr);

// TODO: Move this call setup and the fast path into the emitted JIT code.
StackFramePtr newFrame(runtime.getStackPointer());
newFrame.getPreviousFrameRef() = HermesValue::encodeNativePointer(frame);
newFrame.getSavedIPRef() =
HermesValue::encodeNativePointer(runtime.getCurrentIP());
newFrame.getSavedCodeBlockRef() = HermesValue::encodeNativePointer(nullptr);
newFrame.getSHLocalsRef() = HermesValue::encodeNativePointer(nullptr);

auto *callTarget = &newFrame.getCalleeClosureOrCBRef();
auto *callTarget = toPHV(callTargetSHLV);
if (vmisa<JSFunction>(*callTarget)) {
JSFunction *jsFunc = vmcast<JSFunction>(*callTarget);
if (auto *fnPtr = jsFunc->getCodeBlock()->getJITCompiled())
Expand Down
5 changes: 2 additions & 3 deletions lib/VM/JIT/arm64/JitHandlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ void *_jit_find_catch_target(
[[noreturn]] void _sh_throw_register_stack_overflow(SHRuntime *shr);

/// Call the closure stored in the outgoing registers of the current frame. The
/// caller is responsible for setting up the callee closure, arg count, and
/// new.target registers.
SHLegacyValue _jit_dispatch_call(SHRuntime *, SHLegacyValue *frame);
/// caller is responsible for setting up the outgoing registers.
SHLegacyValue _jit_dispatch_call(SHRuntime *, SHLegacyValue *callTargetSHLV);

} // namespace hermes::vm

0 comments on commit 4986b03

Please sign in to comment.