diff --git a/js/src/jit/ABIFunctionList-inl.h b/js/src/jit/ABIFunctionList-inl.h index dd70df09a393..11d434db775d 100644 --- a/js/src/jit/ABIFunctionList-inl.h +++ b/js/src/jit/ABIFunctionList-inl.h @@ -81,6 +81,10 @@ namespace jit { #define ABIFUNCTION_AND_TYPE_LIST(_) \ _(JS::ToInt32, int32_t (*)(double)) +// List of all ABI function signature which are using a computed function +// pointer instead of a statically known function pointer. +#define ABIFUNCTIONSIG_LIST(_) \ + // GCC warns when the signature does not have matching attributes (for example // MOZ_MUST_USE). Squelch this warning to avoid a GCC-only footgun. #if MOZ_IS_GCC @@ -106,6 +110,15 @@ ABIFUNCTION_LIST(DEF_TEMPLATE) ABIFUNCTION_AND_TYPE_LIST(DEF_TEMPLATE) #undef DEF_TEMPLATE +// Define a known list of function signatures. +#define DEF_TEMPLATE(...) \ + template <> \ + struct ABIFunctionSignatureData<__VA_ARGS__> { \ + static constexpr bool registered = true; \ + }; +ABIFUNCTIONSIG_LIST(DEF_TEMPLATE) +#undef DEF_TEMPLATE + #if MOZ_IS_GCC # pragma GCC diagnostic pop #endif diff --git a/js/src/jit/ABIFunctions.h b/js/src/jit/ABIFunctions.h index 1de799cecbef..4fc2d84615e5 100644 --- a/js/src/jit/ABIFunctions.h +++ b/js/src/jit/ABIFunctions.h @@ -34,6 +34,37 @@ struct ABIFunction { "ABI function is not registered."); }; +template +struct ABIFunctionSignatureData { + static const bool registered = false; +}; + +template +struct ABIFunctionSignature { + void* address(Sig fun) const { return JS_FUNC_TO_DATA_PTR(void*, fun); } + + // If this assertion fails, you are likely in the context of a + // `DynamicFunction(fn)` call. This error indicates that + // ABIFunctionSignature has not been specialized for `Sig` by the time of this + // call. + // + // This can be fixed by adding the function signature to ABIFUNCTIONSIG_LIST + // within `ABIFunctionList-inl.h` and to add an `#include` statement of this + // header in the file which is making the call to `DynamicFunction(fn)`. + static_assert(ABIFunctionSignatureData::registered, + "ABI function signature is not registered."); +}; + +// This is a structure created to ensure that the dynamically computed +// function pointer is well typed. +// +// It is meant to be created only through DynamicFunction function calls. In +// extremelly rare cases, such as VMFunctions, it might be produced as a result +// of GetVMFunctionTarget. +struct DynFn { + void* address; +}; + } // namespace jit } // namespace js diff --git a/js/src/jit/JitRealm.h b/js/src/jit/JitRealm.h index 8fc239ad1743..f3030f23fe2b 100644 --- a/js/src/jit/JitRealm.h +++ b/js/src/jit/JitRealm.h @@ -15,6 +15,7 @@ #include #include "builtin/TypedObject.h" +#include "jit/ABIFunctions.h" #include "jit/BaselineICList.h" #include "jit/BaselineJIT.h" #include "jit/CompileInfo.h" @@ -273,7 +274,7 @@ class JitRuntime { JitCode* generateDebugTrapHandler(JSContext* cx, DebugTrapHandlerKind kind); bool generateVMWrapper(JSContext* cx, MacroAssembler& masm, - const VMFunctionData& f, void* nativeFun, + const VMFunctionData& f, DynFn nativeFun, uint32_t* wrapperOffset); template diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index 66006cbe765b..96e90d0f9794 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -38,6 +38,12 @@ namespace js { namespace jit { +template +DynFn DynamicFunction(Sig fun) { + ABIFunctionSignature sig; + return DynFn{sig.address(fun)}; +} + //{{{ check_macroassembler_style // =============================================================== // Stack manipulation functions. @@ -101,6 +107,12 @@ void MacroAssembler::callWithABI(void* fun, MoveOp::Type result, callWithABINoProfiler(fun, result, check); } +void MacroAssembler::callWithABI(DynFn fun, MoveOp::Type result, + CheckUnsafeCallWithABI check) { + AutoProfilerCallInstrumentation profiler(*this); + callWithABINoProfiler(fun.address, result, check); +} + template void MacroAssembler::callWithABI(MoveOp::Type result, CheckUnsafeCallWithABI check) { diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 0736cb1918e2..cda08a0e1c59 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -228,6 +228,12 @@ enum class CheckUnsafeCallWithABI { DontCheckOther, }; +// This is a global function made to create the DynFn type in a controlled +// environment which would check if the function signature has been registered +// as an ABI function signature. +template +static inline DynFn DynamicFunction(Sig fun); + enum class CharEncoding { Latin1, TwoByte }; // The public entrypoint for emitting assembly. Note that a MacroAssembler can @@ -620,6 +626,9 @@ class MacroAssembler : public MacroAssemblerSpecific { inline void callWithABI( void* fun, MoveOp::Type result = MoveOp::GENERAL, CheckUnsafeCallWithABI check = CheckUnsafeCallWithABI::Check); + inline void callWithABI( + DynFn fun, MoveOp::Type result = MoveOp::GENERAL, + CheckUnsafeCallWithABI check = CheckUnsafeCallWithABI::Check); template inline void callWithABI( MoveOp::Type result = MoveOp::GENERAL, diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 7e496c3e2a21..ad994079058e 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -131,12 +131,12 @@ const VMFunctionData& GetVMFunction(TailCallVMFunctionId id) { return tailCallVMFunctions[size_t(id)]; } -static void* GetVMFunctionTarget(VMFunctionId id) { - return vmFunctionTargets[size_t(id)]; +static DynFn GetVMFunctionTarget(VMFunctionId id) { + return DynFn{vmFunctionTargets[size_t(id)]}; } -static void* GetVMFunctionTarget(TailCallVMFunctionId id) { - return tailCallVMFunctionTargets[size_t(id)]; +static DynFn GetVMFunctionTarget(TailCallVMFunctionId id) { + return DynFn{tailCallVMFunctionTargets[size_t(id)]}; } template diff --git a/js/src/jit/arm/Trampoline-arm.cpp b/js/src/jit/arm/Trampoline-arm.cpp index d1cfd4cbbe52..ed3a434ebf66 100644 --- a/js/src/jit/arm/Trampoline-arm.cpp +++ b/js/src/jit/arm/Trampoline-arm.cpp @@ -736,7 +736,7 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm, } bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm, - const VMFunctionData& f, void* nativeFun, + const VMFunctionData& f, DynFn nativeFun, uint32_t* wrapperOffset) { *wrapperOffset = startTrampolineCode(masm); diff --git a/js/src/jit/arm64/Trampoline-arm64.cpp b/js/src/jit/arm64/Trampoline-arm64.cpp index 86a7154991ff..2d70eb81059b 100644 --- a/js/src/jit/arm64/Trampoline-arm64.cpp +++ b/js/src/jit/arm64/Trampoline-arm64.cpp @@ -563,7 +563,7 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm, } bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm, - const VMFunctionData& f, void* nativeFun, + const VMFunctionData& f, DynFn nativeFun, uint32_t* wrapperOffset) { *wrapperOffset = startTrampolineCode(masm); diff --git a/js/src/jit/mips32/Trampoline-mips32.cpp b/js/src/jit/mips32/Trampoline-mips32.cpp index 2dbd14c7ebde..98b8ed44a25c 100644 --- a/js/src/jit/mips32/Trampoline-mips32.cpp +++ b/js/src/jit/mips32/Trampoline-mips32.cpp @@ -705,7 +705,7 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm, } bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm, - const VMFunctionData& f, void* nativeFun, + const VMFunctionData& f, DynFn nativeFun, uint32_t* wrapperOffset) { *wrapperOffset = startTrampolineCode(masm); diff --git a/js/src/jit/mips64/Trampoline-mips64.cpp b/js/src/jit/mips64/Trampoline-mips64.cpp index c127db36a8da..590ed1a3d29f 100644 --- a/js/src/jit/mips64/Trampoline-mips64.cpp +++ b/js/src/jit/mips64/Trampoline-mips64.cpp @@ -684,7 +684,7 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm, } bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm, - const VMFunctionData& f, void* nativeFun, + const VMFunctionData& f, DynFn nativeFun, uint32_t* wrapperOffset) { *wrapperOffset = startTrampolineCode(masm); diff --git a/js/src/jit/x64/Trampoline-x64.cpp b/js/src/jit/x64/Trampoline-x64.cpp index 7e10d682c367..2d5f2a646fd5 100644 --- a/js/src/jit/x64/Trampoline-x64.cpp +++ b/js/src/jit/x64/Trampoline-x64.cpp @@ -625,7 +625,7 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm, } bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm, - const VMFunctionData& f, void* nativeFun, + const VMFunctionData& f, DynFn nativeFun, uint32_t* wrapperOffset) { *wrapperOffset = startTrampolineCode(masm); diff --git a/js/src/jit/x86/Trampoline-x86.cpp b/js/src/jit/x86/Trampoline-x86.cpp index 529899bbed30..0aa99f78d635 100644 --- a/js/src/jit/x86/Trampoline-x86.cpp +++ b/js/src/jit/x86/Trampoline-x86.cpp @@ -641,7 +641,7 @@ void JitRuntime::generateBailoutHandler(MacroAssembler& masm, } bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm, - const VMFunctionData& f, void* nativeFun, + const VMFunctionData& f, DynFn nativeFun, uint32_t* wrapperOffset) { *wrapperOffset = startTrampolineCode(masm);