Modified: trunk/Source/_javascript_Core/ChangeLog (293091 => 293092)
--- trunk/Source/_javascript_Core/ChangeLog 2022-04-20 12:56:49 UTC (rev 293091)
+++ trunk/Source/_javascript_Core/ChangeLog 2022-04-20 13:36:57 UTC (rev 293092)
@@ -1,3 +1,49 @@
+2022-04-20 Zan Dobersek <[email protected]>
+
+ [JSC] Accommodate the RISCV64 C calling convention
+ https://bugs.webkit.org/show_bug.cgi?id=236367
+ <rdar://problem/89026012>
+
+ Reviewed by Yusuke Suzuki.
+
+ The 64-bit RISC-V (RV64) calling convention requires 32-bit arguments
+ to be sign-extended to fill out the whole 64-bit register, fitting
+ nicely with different instructions in this ISA that operate on 32-bit
+ values, and differring from other 64-bit ISAs that provide partial-sized
+ registers (which are aliased to the whole register).
+
+ JSC JIT is tailored to the other ISAs, often taking shortcuts to pack
+ non-sign-extended values into registers that are then accessed for those
+ 32-bit values through the partial-sized aliases. This can trip up RISC-V
+ execution when constructing calls that pass 32-bit values to native code
+ using the C calling convention.
+
+ To avoid this, arguments setup done through the CCallHelpers class is
+ enhanced to, after packing up arguments either into argument registers
+ or onto the stack, another pass of the argument types for the desired
+ operation is done, detecting whether the argument was supposed to be
+ packed into an GPR or an FPR destination. On RV64, when packed into a
+ GPR argument register that matches a 32-bit argument in the operation,
+ the additional sign extension is performed on that argument register.
+
+ GPR and FPR distinction for a given argument's register type is based
+ on whether or not the double type is used as the argument's type. All
+ non-double-typed arguments are passed as GPRs. Additional compile-time
+ validation is provided to ensure that's the case for every operation
+ that's having its arguments set up. This is relied upon when traversing
+ the operation's arguments and indexing every GPR argument along the way.
+
+ This approach only accommodates the RV64 calling convention for the
+ Baseline JIT level. For higher levels, similar but probably different
+ solutions will have to be crafted.
+
+ * jit/CCallHelpers.h:
+ (JSC::CCallHelpers::finalizeGPRArguments):
+ (JSC::CCallHelpers::gprArgsCount):
+ (JSC::CCallHelpers::fprArgsCount):
+ (JSC::CCallHelpers::setupArgumentsImpl):
+ (JSC::CCallHelpers::setupArgumentsEntryImpl):
+
2022-04-20 Mikhail R. Gadelha <[email protected]>
Unify calls and checks for CellTag
Modified: trunk/Source/_javascript_Core/jit/CCallHelpers.h (293091 => 293092)
--- trunk/Source/_javascript_Core/jit/CCallHelpers.h 2022-04-20 12:56:49 UTC (rev 293091)
+++ trunk/Source/_javascript_Core/jit/CCallHelpers.h 2022-04-20 13:36:57 UTC (rev 293092)
@@ -677,14 +677,65 @@
#undef CURRENT_ARGUMENT_TYPE
#undef RESULT_TYPE
+ template<typename OperationType, unsigned gprIndex>
+ constexpr void finalizeGPRArguments(std::index_sequence<>)
+ {
+ }
+
+ template<typename OperationType, unsigned gprIndex, size_t arityIndex, size_t... remainingArityIndices>
+ constexpr void finalizeGPRArguments(std::index_sequence<arityIndex, remainingArityIndices...>)
+ {
+ using NextIndexSequenceType = std::index_sequence<remainingArityIndices...>;
+ using ArgumentType = typename FunctionTraits<OperationType>::template ArgumentType<arityIndex>;
+
+ // Every non-double-typed argument should be passed in through GPRRegs, and inversely only double-typed
+ // arguments should be passed through FPRRegs. This is asserted in the invocation of the lastly-called
+ // setupArgumentsImpl(ArgCollection<>) overload, by matching the number of handled GPR and FPR arguments
+ // with the corresponding count of properly-typed arguments for this operation.
+ if (!std::is_same_v<ArgumentType, double>) {
+ // RV64 calling convention requires all 32-bit values to be sign-extended into the whole register.
+ // JSC JIT is tailored for other ISAs that pass these values in 32-bit-wide registers, which RISC-V
+ // doesn't support, so any 32-bit value passed in argument registers has to be manually sign-extended.
+ if (isRISCV64() && gprIndex < GPRInfo::numberOfArgumentRegisters
+ && std::is_integral_v<ArgumentType> && sizeof(ArgumentType) == 4) {
+ GPRReg argReg = GPRInfo::toArgumentRegister(gprIndex);
+ signExtend32ToPtr(argReg, argReg);
+ }
+
+ finalizeGPRArguments<OperationType, gprIndex + 1>(NextIndexSequenceType());
+ } else
+ finalizeGPRArguments<OperationType, gprIndex>(NextIndexSequenceType());
+ }
+
+ template<typename ArgType> using GPRArgCountValue = std::conditional_t<std::is_same_v<ArgType, double>,
+ std::integral_constant<unsigned, 0>, std::integral_constant<unsigned, 1>>;
+ template<typename ArgType> using FPRArgCountValue = std::conditional_t<std::is_same_v<ArgType, double>,
+ std::integral_constant<unsigned, 1>, std::integral_constant<unsigned, 0>>;
+
+ template<typename OperationTraitsType, size_t... argIndices>
+ static constexpr unsigned gprArgsCount(std::index_sequence<argIndices...>)
+ {
+ return (0 + ... + (GPRArgCountValue<typename OperationTraitsType::template ArgumentType<argIndices>>::value));
+ }
+
+ template<typename OperationTraitsType, size_t... argIndices>
+ static constexpr unsigned fprArgsCount(std::index_sequence<argIndices...>)
+ {
+ return (0 + ... + (FPRArgCountValue<typename OperationTraitsType::template ArgumentType<argIndices>>::value));
+ }
+
// Base case; set up the argument registers.
template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned nonArgGPRs, unsigned extraPoke>
ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, nonArgGPRs, extraPoke> argSourceRegs)
{
- static_assert(FunctionTraits<OperationType>::arity == numGPRArgs + numFPRArgs, "One last sanity check");
+ using TraitsType = FunctionTraits<OperationType>;
+ static_assert(TraitsType::arity == numGPRArgs + numFPRArgs, "One last sanity check");
#if USE(JSVALUE64)
- static_assert(FunctionTraits<OperationType>::cCallArity() == numGPRArgs + numFPRArgs + extraPoke, "Check the CCall arity");
+ static_assert(TraitsType::cCallArity() == numGPRArgs + numFPRArgs + extraPoke, "Check the CCall arity");
#endif
+ static_assert(gprArgsCount<TraitsType>(std::make_index_sequence<TraitsType::arity>()) == numGPRArgs);
+ static_assert(fprArgsCount<TraitsType>(std::make_index_sequence<TraitsType::arity>()) == numFPRArgs);
+
setupStubArgs<numGPRSources, GPRReg>(clampArrayToSize<numGPRSources, GPRReg>(argSourceRegs.gprDestinations), clampArrayToSize<numGPRSources, GPRReg>(argSourceRegs.gprSources));
#if CPU(MIPS) || (CPU(ARM_THUMB2) && !CPU(ARM_HARDFP))
setupStubCrossArgs<numCrossSources>(argSourceRegs.crossDestinations, argSourceRegs.crossSources);
@@ -711,6 +762,8 @@
#endif
setupArgumentsImpl<OperationType>(argSourceRegs, args...);
}
+
+ finalizeGPRArguments<OperationType, 0>(std::make_index_sequence<FunctionTraits<OperationType>::arity>());
}
public: