diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 74bb7ab615e8..c0e83a2589ab 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -7,6 +7,8 @@ #ifndef jit_VMFunctions_h #define jit_VMFunctions_h +#include "mozilla/Attributes.h" + #include "jspubtd.h" #include "jit/CompileInfo.h" @@ -440,176 +442,114 @@ template <> struct MatchContext { static const bool valid = true; }; -#define FOR_EACH_ARGS_1(Macro, Sep, Last) Macro(1) Last(1) -#define FOR_EACH_ARGS_2(Macro, Sep, Last) FOR_EACH_ARGS_1(Macro, Sep, Sep) Macro(2) Last(2) -#define FOR_EACH_ARGS_3(Macro, Sep, Last) FOR_EACH_ARGS_2(Macro, Sep, Sep) Macro(3) Last(3) -#define FOR_EACH_ARGS_4(Macro, Sep, Last) FOR_EACH_ARGS_3(Macro, Sep, Sep) Macro(4) Last(4) -#define FOR_EACH_ARGS_5(Macro, Sep, Last) FOR_EACH_ARGS_4(Macro, Sep, Sep) Macro(5) Last(5) -#define FOR_EACH_ARGS_6(Macro, Sep, Last) FOR_EACH_ARGS_5(Macro, Sep, Sep) Macro(6) Last(6) -#define FOR_EACH_ARGS_7(Macro, Sep, Last) FOR_EACH_ARGS_6(Macro, Sep, Sep) Macro(7) Last(7) +// Extract the last element of a list of types. +template +struct LastArg; -#define COMPUTE_INDEX(NbArg) NbArg -#define COMPUTE_OUTPARAM_RESULT(NbArg) OutParamToDataType::result -#define COMPUTE_OUTPARAM_ROOT(NbArg) OutParamToRootType::result -#define COMPUTE_ARG_PROP(NbArg) (TypeToArgProperties::result << (2 * (NbArg - 1))) -#define COMPUTE_ARG_ROOT(NbArg) (uint64_t(TypeToRootType::result) << (3 * (NbArg - 1))) -#define COMPUTE_ARG_FLOAT(NbArg) (TypeToPassInFloatReg::result) << (NbArg - 1) -#define SEP_OR(_) | -#define NOTHING(_) - -#define FUNCTION_INFO_STRUCT_BODY(ForEachNb) \ - static inline DataType returnType() { \ - return TypeToDataType::result; \ - } \ - static inline DataType outParam() { \ - return ForEachNb(NOTHING, NOTHING, COMPUTE_OUTPARAM_RESULT); \ - } \ - static inline RootType outParamRootType() { \ - return ForEachNb(NOTHING, NOTHING, COMPUTE_OUTPARAM_ROOT); \ - } \ - static inline size_t NbArgs() { \ - return ForEachNb(NOTHING, NOTHING, COMPUTE_INDEX); \ - } \ - static inline size_t explicitArgs() { \ - return NbArgs() - (outParam() != Type_Void ? 1 : 0); \ - } \ - static inline uint32_t argumentProperties() { \ - return ForEachNb(COMPUTE_ARG_PROP, SEP_OR, NOTHING); \ - } \ - static inline uint32_t argumentPassedInFloatRegs() { \ - return ForEachNb(COMPUTE_ARG_FLOAT, SEP_OR, NOTHING); \ - } \ - static inline uint64_t argumentRootTypes() { \ - return ForEachNb(COMPUTE_ARG_ROOT, SEP_OR, NOTHING); \ - } \ - explicit FunctionInfo(pf fun, MaybeTailCall expectTailCall, \ - PopValues extraValuesToPop = PopValues(0)) \ - : VMFunction(JS_FUNC_TO_DATA_PTR(void*, fun), explicitArgs(), \ - argumentProperties(), argumentPassedInFloatRegs(), \ - argumentRootTypes(), outParam(), outParamRootType(), \ - returnType(), extraValuesToPop.numValues, expectTailCall) \ - { \ - static_assert(MatchContext::valid, "Invalid cx type in VMFunction"); \ - } \ - explicit FunctionInfo(pf fun, PopValues extraValuesToPop = PopValues(0)) \ - : VMFunction(JS_FUNC_TO_DATA_PTR(void*, fun), explicitArgs(), \ - argumentProperties(), argumentPassedInFloatRegs(), \ - argumentRootTypes(), outParam(), outParamRootType(), \ - returnType(), extraValuesToPop.numValues, NonTailCall) \ - { \ - static_assert(MatchContext::valid, "Invalid cx type in VMFunction"); \ - } - -template -struct FunctionInfo { +template <> +struct LastArg<> +{ + typedef void Type; + static MOZ_CONSTEXPR_VAR size_t nbArgs = 0; }; -// VMFunction wrapper with no explicit arguments. -template -struct FunctionInfo : public VMFunction { - typedef R (*pf)(Context); +template +struct LastArg +{ + typedef HeadType Type; + static MOZ_CONSTEXPR_VAR size_t nbArgs = 1; +}; + +template +struct LastArg +{ + typedef typename LastArg::Type Type; + static MOZ_CONSTEXPR_VAR size_t nbArgs = LastArg::nbArgs + 1; +}; + +// Construct a bit mask from a list of types. The mask is constructed as an OR +// of the mask produced for each argument. The result of each argument is +// shifted by its index, such that the result of the first argument is on the +// low bits of the mask, and the result of the last argument in part of the +// high bits of the mask. +template class Each, typename ResultType, size_t Shift, + typename... Args> +struct BitMask; + +template class Each, typename ResultType, size_t Shift> +struct BitMask +{ + static MOZ_CONSTEXPR_VAR ResultType result = ResultType(); +}; + +template class Each, typename ResultType, size_t Shift, + typename HeadType, typename... TailTypes> +struct BitMask +{ + static_assert(ResultType(Each::result) < (1 << Shift), + "not enough bits reserved by the shift for individual results"); + static_assert(LastArg::nbArgs < (8 * sizeof(ResultType) / Shift), + "not enough bits in the result type to store all bit masks"); + + static MOZ_CONSTEXPR_VAR ResultType result = + ResultType(Each::result) | + (BitMask::result << Shift); +}; + +// Extract VMFunction properties based on the signature of the function. The +// properties are used to generate the logic for calling the VM function, and +// also for marking the stack during GCs. +template +struct FunctionInfo; + +template +struct FunctionInfo : public VMFunction +{ + typedef R (*pf)(Context, Args...); static inline DataType returnType() { return TypeToDataType::result; } static inline DataType outParam() { - return Type_Void; + return OutParamToDataType::Type>::result; } static inline RootType outParamRootType() { - return RootNone; + return OutParamToRootType::Type>::result; + } + static inline size_t NbArgs() { + return LastArg::nbArgs; } static inline size_t explicitArgs() { - return 0; + return NbArgs() - (outParam() != Type_Void ? 1 : 0); } static inline uint32_t argumentProperties() { - return 0; + return BitMask::result; } static inline uint32_t argumentPassedInFloatRegs() { - return 0; + return BitMask::result; } static inline uint64_t argumentRootTypes() { - return 0; + return BitMask::result; } - explicit FunctionInfo(pf fun) - : VMFunction(JS_FUNC_TO_DATA_PTR(void*, fun), explicitArgs(), - argumentProperties(), argumentPassedInFloatRegs(), - argumentRootTypes(), outParam(), outParamRootType(), - returnType(), 0, NonTailCall) + explicit FunctionInfo(pf fun, PopValues extraValuesToPop = PopValues(0)) + : VMFunction(JS_FUNC_TO_DATA_PTR(void*, fun), explicitArgs(), + argumentProperties(), argumentPassedInFloatRegs(), + argumentRootTypes(), outParam(), outParamRootType(), + returnType(), extraValuesToPop.numValues, NonTailCall) { static_assert(MatchContext::valid, "Invalid cx type in VMFunction"); } - explicit FunctionInfo(pf fun, MaybeTailCall expectTailCall) - : VMFunction(JS_FUNC_TO_DATA_PTR(void*, fun), explicitArgs(), - argumentProperties(), argumentPassedInFloatRegs(), - argumentRootTypes(), outParam(), outParamRootType(), - returnType(), expectTailCall) + explicit FunctionInfo(pf fun, MaybeTailCall expectTailCall, + PopValues extraValuesToPop = PopValues(0)) + : VMFunction(JS_FUNC_TO_DATA_PTR(void*, fun), explicitArgs(), + argumentProperties(), argumentPassedInFloatRegs(), + argumentRootTypes(), outParam(), outParamRootType(), + returnType(), extraValuesToPop.numValues, expectTailCall) { static_assert(MatchContext::valid, "Invalid cx type in VMFunction"); } }; -// Specialize the class for each number of argument used by VMFunction. -// Keep it verbose unless you find a readable macro for it. -template -struct FunctionInfo : public VMFunction { - typedef R (*pf)(Context, A1); - FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_1) -}; - -template -struct FunctionInfo : public VMFunction { - typedef R (*pf)(Context, A1, A2); - FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_2) -}; - -template -struct FunctionInfo : public VMFunction { - typedef R (*pf)(Context, A1, A2, A3); - FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_3) -}; - -template -struct FunctionInfo : public VMFunction { - typedef R (*pf)(Context, A1, A2, A3, A4); - FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_4) -}; - -template - struct FunctionInfo : public VMFunction { - typedef R (*pf)(Context, A1, A2, A3, A4, A5); - FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_5) -}; - -template - struct FunctionInfo : public VMFunction { - typedef R (*pf)(Context, A1, A2, A3, A4, A5, A6); - FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_6) -}; - -template - struct FunctionInfo : public VMFunction { - typedef R (*pf)(Context, A1, A2, A3, A4, A5, A6, A7); - FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_7) -}; - -#undef FUNCTION_INFO_STRUCT_BODY - -#undef FOR_EACH_ARGS_7 -#undef FOR_EACH_ARGS_6 -#undef FOR_EACH_ARGS_5 -#undef FOR_EACH_ARGS_4 -#undef FOR_EACH_ARGS_3 -#undef FOR_EACH_ARGS_2 -#undef FOR_EACH_ARGS_1 - -#undef COMPUTE_INDEX -#undef COMPUTE_OUTPARAM_RESULT -#undef COMPUTE_OUTPARAM_ROOT -#undef COMPUTE_ARG_PROP -#undef COMPUTE_ARG_FLOAT -#undef SEP_OR -#undef NOTHING - class AutoDetectInvalidation { JSContext* cx_;