Skip to content

Instantly share code, notes, and snippets.

@hotsphink
Created October 2, 2020 21:12
Show Gist options
  • Save hotsphink/6b10862d9d6c978e91a2f06b66a0e11d to your computer and use it in GitHub Desktop.
Save hotsphink/6b10862d9d6c978e91a2f06b66a0e11d to your computer and use it in GitHub Desktop.
mkgist-created gist
# HG changeset patch
# User Steve Fink <[email protected]>
# Date 1601504771 25200
# Wed Sep 30 15:26:11 2020 -0700
# Node ID d2658c507732fb666d515e5bbe04912e91026e9a
# Parent f9261c82b0dd868417bf1eacfeda465a1542bc38
VoidStarOf is unnecessary. Just cast to `const void*`.
diff --git a/js/src/jsapi-tests/testJitABIcalls.cpp b/js/src/jsapi-tests/testJitABIcalls.cpp
--- a/js/src/jsapi-tests/testJitABIcalls.cpp
+++ b/js/src/jsapi-tests/testJitABIcalls.cpp
@@ -98,33 +98,16 @@ struct WrapForSizeOf {
};
// Given a type, return the integer type which has the same size.
template <typename T>
struct IntTypeOf {
using Res = typename IntBySize<sizeof(WrapForSizeOf<T>)>::Res;
};
-// Given a type, return a void pointer type with the same `const` qualifier.
-// This is used to later remove the const qualifier if any.
-template <typename T>
-struct VoidStarOf {
- using Res = void*;
-};
-
-template <typename T>
-struct VoidStarOf<const T> {
- using Res = const void*;
-};
-
-template <typename T>
-struct VoidStarOf<const T&> {
- using Res = const void*;
-};
-
// Concatenate 2 std::integer_sequence, and return an std::integer_sequence with
// the content of both parameters.
template <typename Before, typename After>
struct Concat;
template <typename Int, Int... Before, Int... After>
struct Concat<std::integer_sequence<Int, Before...>,
std::integer_sequence<Int, After...>> {
@@ -376,42 +359,38 @@ using TestArgsSizes = InstanceSeq<
typename ArgsBuffer<typename ArgsSizes<Args...>::Res, Args...>::Res>;
// AsInt returns the raw value of any argument as an integer value which can be
// compared with the expected values.
template <typename Type>
struct AsInt {
static typename IntTypeOf<Type>::Res Convert(Type v) {
// Simplify working with types by casting the address of the value to the
- // equivalent `void*` / `const void*`.
- auto addr = reinterpret_cast<typename VoidStarOf<Type>::Res>(&v);
- // Remove the const from `const void*` if any.
- void* address = const_cast<void*>(addr);
+ // equivalent `const void*`.
+ auto address = reinterpret_cast<const void*>(&v);
// Convert the `void*` to an integer pointer of the same size as the input
// type, and return the raw value stored in the integer interpretation.
static_assert(sizeof(WrapForSizeOf<Type>) ==
sizeof(WrapForSizeOf<typename IntTypeOf<Type>::Res>));
- return *reinterpret_cast<typename IntTypeOf<Type>::Res*>(address);
+ return *reinterpret_cast<const typename IntTypeOf<Type>::Res*>(address);
}
};
template <typename T>
struct AsInt<T&> {
using Type = T&;
static typename IntTypeOf<Type>::Res Convert(Type v) {
// Simplify working with types by casting the address of the value to the
- // equivalent `void*` / `const void*`.
- auto addr = reinterpret_cast<typename VoidStarOf<Type>::Res>(&v);
- // Remove the const from `const void*` if any.
- void* address = const_cast<void*>(addr);
+ // equivalent `const void*`.
+ auto address = reinterpret_cast<const void*>(&v);
// Convert the `void*` to an integer pointer of the same size as the input
// type, and return the raw value stored in the integer interpretation.
static_assert(sizeof(WrapForSizeOf<Type>) ==
sizeof(WrapForSizeOf<typename IntTypeOf<Type>::Res>));
- return reinterpret_cast<typename IntTypeOf<Type>::Res>(address);
+ return reinterpret_cast<const typename IntTypeOf<Type>::Res>(address);
}
};
template <typename Type>
typename IntTypeOf<Type>::Res ConvertToInt(Type v) {
return AsInt<Type>::Convert(std::forward<Type>(v));
}
# HG changeset patch
# User Steve Fink <[email protected]>
# Date 1601672191 25200
# Fri Oct 02 13:56:31 2020 -0700
# Node ID cee51d93f57a7cd37195a357d7c17bb0cd9e16fc
# Parent d2658c507732fb666d515e5bbe04912e91026e9a
First, I don't really like the name `Res`, especially since it's sometimes used for types and sometimes for values. For that, it seems preferable to use the `std` notation of `type`/`value`.
But also, the boilerplate of `typename SomeTemplate<...>::Res` is really verbose and makes things hard to read. So I switched lots of stuff to using the c++14 TEMPLATE_t and TEMPLATE_v conventions, so that the above is now `SomeTemplate_v<...>`.
This patch changes most but not all of them. I wanted to change enough that I could see how it would read after the change.
With your capitalization scheme, it would probably be better to use `Type` and `Value` in place of `type`/`value`. I used the latter to match `std`, but in retrospect that's probably not all that important. Use whichever you prefer.
diff --git a/js/src/jsapi-tests/testJitABIcalls.cpp b/js/src/jsapi-tests/testJitABIcalls.cpp
--- a/js/src/jsapi-tests/testJitABIcalls.cpp
+++ b/js/src/jsapi-tests/testJitABIcalls.cpp
@@ -63,85 +63,93 @@ using namespace js::jit;
TAIL_CALL_VMFUNCTION_LIST(PREFIX##_TC_VMFUN_TO_ALLFUN)
// Given the size in bytes of a type, return the matching integer type.
template <size_t I>
struct IntBySize;
template <>
struct IntBySize<1> {
- using Res = uint8_t;
+ using type = uint8_t;
};
template <>
struct IntBySize<2> {
- using Res = uint16_t;
+ using type = uint16_t;
};
template <>
struct IntBySize<4> {
- using Res = uint32_t;
+ using type = uint32_t;
};
template <>
struct IntBySize<8> {
- using Res = uint64_t;
+ using type = uint64_t;
};
// sizeof(const T&) is not equal to sizeof(const T*). This structure is used to
// wrap the type which size is being queried, instead of the size of the type
// referenced by it.
//
// "When applied to a reference or a reference type, the result is the size of
// the referenced type." [expr.sizeof] (5.3.3.2)
template <typename T>
struct WrapForSizeOf {
T unused_;
};
// Given a type, return the integer type which has the same size.
template <typename T>
struct IntTypeOf {
- using Res = typename IntBySize<sizeof(WrapForSizeOf<T>)>::Res;
+ using type = typename IntBySize<sizeof(WrapForSizeOf<T>)>::type;
};
+template <typename T>
+using IntTypeOf_t = typename IntTypeOf<T>::type;
+
// Concatenate 2 std::integer_sequence, and return an std::integer_sequence with
// the content of both parameters.
template <typename Before, typename After>
struct Concat;
template <typename Int, Int... Before, Int... After>
struct Concat<std::integer_sequence<Int, Before...>,
std::integer_sequence<Int, After...>> {
- using Res = std::integer_sequence<Int, Before..., After...>;
+ using type = std::integer_sequence<Int, Before..., After...>;
};
-static_assert(
- std::is_same<typename Concat<std::integer_sequence<uint8_t, 1, 2>,
- std::integer_sequence<uint8_t, 3, 4>>::Res,
- std::integer_sequence<uint8_t, 1, 2, 3, 4>>::value);
+template <typename Before, typename After>
+using Concat_t = typename Concat<Before, After>::type;
+
+static_assert(std::is_same_v<Concat_t<std::integer_sequence<uint8_t, 1, 2>,
+ std::integer_sequence<uint8_t, 3, 4>>,
+ std::integer_sequence<uint8_t, 1, 2, 3, 4>>);
// Generate an std::integer_sequence of `N` elements, where each element is an
// uint8_t integers with value `Value`.
template <size_t N, uint8_t Value>
struct CstSeq {
- using Res = typename Concat<typename CstSeq<N / 2, Value>::Res,
- typename CstSeq<N - N / 2, Value>::Res>::Res;
+ using type = Concat_t<typename CstSeq<N / 2, Value>::type,
+ typename CstSeq<N - N / 2, Value>::type>;
};
template <uint8_t Value>
struct CstSeq<0, Value> {
- using Res = std::integer_sequence<uint8_t>;
+ using type = std::integer_sequence<uint8_t>;
};
template <uint8_t Value>
struct CstSeq<1, Value> {
- using Res = std::integer_sequence<uint8_t, Value>;
+ using type = std::integer_sequence<uint8_t, Value>;
};
+template <size_t N, uint8_t Value>
+using CstSeq_t = typename CstSeq<N, Value>::type;
+
// Computes the number of bytes to add before a type in order to align it in
// memory.
#define PADDING(SIZE, ALIGN) ((ALIGN) - ((SIZE) % (ALIGN))) % (ALIGN)
// Request a minimum alignment for the values which are added in a buffer, in
// order to account for the read size used by the MoveOperand given as argument
// of passWithABI. The MoveOperand do not take into consideration the size of
// the data which is being transfered, and might load a larger amount of data.
@@ -157,104 +165,114 @@ struct CstSeq<1, Value> {
PADDING(Size, alignof(WrapForSizeOf<TYPE>)) + \
AT_LEAST_SIZE(sizeof(WrapForSizeOf<TYPE>))
// Generate an std::integer_sequence of 0 uint8_t elements of the size of the
// padding needed to align a type in memory.
template <size_t Align, size_t CurrSize>
using PadSeq = CstSeq<PADDING(CurrSize, Align), 0>;
-static_assert(std::is_same<typename PadSeq<4, 0>::Res,
- std::integer_sequence<uint8_t>>::value);
-static_assert(std::is_same<typename PadSeq<4, 3>::Res,
- std::integer_sequence<uint8_t, 0>>::value);
-static_assert(std::is_same<typename PadSeq<4, 2>::Res,
- std::integer_sequence<uint8_t, 0, 0>>::value);
-static_assert(std::is_same<typename PadSeq<4, 1>::Res,
- std::integer_sequence<uint8_t, 0, 0, 0>>::value);
+template <size_t Align, size_t CurrSize>
+using PadSeq_t = typename PadSeq<Align, CurrSize>::type;
+
+static_assert(std::is_same_v<PadSeq_t<4, 0>, std::integer_sequence<uint8_t>>);
+static_assert(
+ std::is_same_v<PadSeq_t<4, 3>, std::integer_sequence<uint8_t, 0>>);
+static_assert(
+ std::is_same_v<PadSeq_t<4, 2>, std::integer_sequence<uint8_t, 0, 0>>);
+static_assert(
+ std::is_same_v<PadSeq_t<4, 1>, std::integer_sequence<uint8_t, 0, 0, 0>>);
// Spread an integer value `Value` into a new std::integer_sequence of `N`
// uint8_t elements, using Little Endian ordering of bytes.
template <size_t N, size_t Value, uint8_t... Rest>
struct FillLESeq {
- using Res = typename FillLESeq<N - 1, (Value >> 8), Rest...,
- uint8_t(Value & 0xff)>::Res;
+ using type = typename FillLESeq<N - 1, (Value >> 8), Rest...,
+ uint8_t(Value & 0xff)>::type;
};
template <size_t Value, uint8_t... Rest>
struct FillLESeq<0, Value, Rest...> {
- using Res = std::integer_sequence<uint8_t, Rest...>;
+ using type = std::integer_sequence<uint8_t, Rest...>;
};
template <size_t N, size_t Value>
using FillSeq = FillLESeq<N, Value>;
-static_assert(std::is_same<typename FillSeq<4, 2>::Res,
- std::integer_sequence<uint8_t, 2, 0, 0, 0>>::value);
+static_assert(std::is_same_v<typename FillSeq<4, 2>::type,
+ std::integer_sequence<uint8_t, 2, 0, 0, 0>>);
// Given a list of template parameters, generate an std::integer_sequence of
// size_t, where each element is 1 larger than the previous one. The generated
// sequence starts at 0.
template <typename... Args>
struct ArgsIndexes {
- using Res = std::index_sequence_for<Args...>;
+ using type = std::index_sequence_for<Args...>;
};
-static_assert(std::is_same<typename ArgsIndexes<uint8_t, uint64_t>::Res,
- std::integer_sequence<size_t, 0, 1>>::value);
+static_assert(std::is_same_v<typename ArgsIndexes<uint8_t, uint64_t>::type,
+ std::integer_sequence<size_t, 0, 1>>);
// Extract a single bit for each element of an std::integer_sequence. This is
// used to work-around some restriction around providing boolean arguments,
// which might be truncated to a single bit.
template <size_t Bit, typename IntSeq>
struct ExtractBit;
template <size_t Bit, size_t... Values>
struct ExtractBit<Bit, std::integer_sequence<size_t, Values...>> {
- using Res = std::integer_sequence<size_t, (Values >> Bit) & 1 ...>;
+ using type = std::integer_sequence<size_t, (Values >> Bit) & 1 ...>;
};
// Generate an std::integer_sequence of indexes which are filtered for a single
// bit, such that it can be used with boolean types.
template <size_t Bit, typename... Args>
-using ArgsBitOfIndexes = ExtractBit<Bit, typename ArgsIndexes<Args...>::Res>;
+using ArgsBitOfIndexes = ExtractBit<Bit, typename ArgsIndexes<Args...>::type>;
-static_assert(std::is_same<typename ArgsBitOfIndexes<0, int, int, int, int>::Res,
- std::integer_sequence<size_t, 0, 1, 0, 1>>::value);
-static_assert(std::is_same<typename ArgsBitOfIndexes<1, int, int, int, int>::Res,
- std::integer_sequence<size_t, 0, 0, 1, 1>>::value);
+static_assert(
+ std::is_same_v<typename ArgsBitOfIndexes<0, int, int, int, int>::type,
+ std::integer_sequence<size_t, 0, 1, 0, 1>>);
+static_assert(
+ std::is_same_v<typename ArgsBitOfIndexes<1, int, int, int, int>::type,
+ std::integer_sequence<size_t, 0, 0, 1, 1>>);
// Compute the offset of each argument in a buffer produced by GenArgsBuffer,
// this is used to fill the MoveOperand displacement field when loading value
// out of the buffer produced by GenArgsBuffer.
template <size_t Size, typename... Args>
struct ArgsOffsets;
template <size_t Size>
struct ArgsOffsets<Size> {
- using Res = std::integer_sequence<size_t>;
+ using type = std::integer_sequence<size_t>;
};
template <size_t Size, typename Arg, typename... Args>
struct ArgsOffsets<Size, Arg, Args...> {
- using Res = typename Concat<
+ using type = Concat_t<
std::integer_sequence<size_t, Size + PADDING(Size, alignof(Arg))>,
- typename ArgsOffsets<Size + PADSIZE(Size, Arg), Args...>::Res>::Res;
+ typename ArgsOffsets<Size + PADSIZE(Size, Arg), Args...>::type>;
};
-static_assert(std::is_same<typename ArgsOffsets<0, uint8_t, uint64_t, bool>::Res,
- std::integer_sequence<size_t, 0, 8, 16>>::value);
+template <size_t Size, typename... Args>
+using ArgsOffsets_t = typename ArgsOffsets<Size, Args...>::type;
+
+static_assert(std::is_same_v<ArgsOffsets_t<0, uint8_t, uint64_t, bool>,
+ std::integer_sequence<size_t, 0, 8, 16>>);
// Generate an std::integer_sequence containing the size of each argument in
// memory.
template <typename... Args>
struct ArgsSizes {
- using Res = std::integer_sequence<size_t, sizeof(WrapForSizeOf<Args>)...>;
+ using type = std::integer_sequence<size_t, sizeof(WrapForSizeOf<Args>)...>;
};
+template <typename... Args>
+using ArgsSizes_t = typename ArgsSizes<Args...>::type;
+
// Given a type, return the MoveOp type used by passABIArg to know how to
// interpret the value which are given as arguments.
template <typename Type>
struct TypeToMoveOp {
static constexpr MoveOp::Type value = MoveOp::GENERAL;
};
template <>
@@ -266,159 +284,166 @@ template <>
struct TypeToMoveOp<double> {
static constexpr MoveOp::Type value = MoveOp::DOUBLE;
};
// Generate an std::integer_sequence which contains the associated MoveOp of
// each argument.
template <typename... Args>
struct ArgsMoveOps {
- using Res = std::integer_sequence<MoveOp::Type, TypeToMoveOp<Args>::value...>;
+ using type =
+ std::integer_sequence<MoveOp::Type, TypeToMoveOp<Args>::value...>;
};
+template <typename... Args>
+using ArgsMoveOps_t = typename ArgsMoveOps<Args...>::type;
+
// Generate an std::integer_sequence which corresponds to a buffer containing
// values which are spread at the location where each arguments type would be
// stored in a buffer.
template <typename Buffer, typename Values, typename... Args>
struct GenArgsBuffer;
template <uint8_t... Buffer, typename Arg, typename... Args, size_t Val,
size_t... Values>
struct GenArgsBuffer<std::integer_sequence<uint8_t, Buffer...>,
std::integer_sequence<size_t, Val, Values...>, Arg,
Args...> {
- using Res = typename GenArgsBuffer<
- typename Concat<
+ using type = typename GenArgsBuffer<
+ Concat_t<
std::integer_sequence<uint8_t, Buffer...>,
- typename Concat<
- typename PadSeq<alignof(Arg), sizeof...(Buffer)>::Res,
- typename FillSeq<AT_LEAST_SIZE(sizeof(WrapForSizeOf<Arg>)),
- Val>::Res>::Res>::Res,
- std::integer_sequence<size_t, Values...>, Args...>::Res;
+ Concat_t<PadSeq_t<alignof(Arg), sizeof...(Buffer)>,
+ typename FillSeq<AT_LEAST_SIZE(sizeof(WrapForSizeOf<Arg>)),
+ Val>::type>>,
+ std::integer_sequence<size_t, Values...>, Args...>::type;
};
template <typename Buffer>
struct GenArgsBuffer<Buffer, std::integer_sequence<size_t>> {
- using Res = Buffer;
+ using type = Buffer;
};
template <typename Values, typename... Args>
using ArgsBuffer =
GenArgsBuffer<std::integer_sequence<uint8_t>, Values, Args...>;
// NOTE: The representation of the boolean might be surpising in this test case,
// see AT_LEAST_SIZE macro for an explanation.
-static_assert(std::is_same<typename ArgsBuffer<std::integer_sequence<size_t, 42, 51>,
- uint64_t, bool>::Res,
- std::integer_sequence<uint8_t, 42, 0, 0, 0, 0, 0, 0, 0,
- 51, 0, 0, 0, 0, 0, 0, 0>>::value);
+static_assert(
+ std::is_same_v<typename ArgsBuffer<std::integer_sequence<size_t, 42, 51>,
+ uint64_t, bool>::type,
+ std::integer_sequence<uint8_t, 42, 0, 0, 0, 0, 0, 0, 0, 51,
+ 0, 0, 0, 0, 0, 0, 0>>);
// Test used to check if any of the type given as template parameter is a
// `bool`, which is a corner case where a raw integer might be truncated by the
// C++ compiler.
template <typename... Args>
struct AnyBool;
template <>
struct AnyBool<> {
static constexpr bool value = false;
};
template <typename A0, typename... Args>
struct AnyBool<A0, Args...> {
static constexpr bool value =
- std::is_same<A0, bool>::value || AnyBool<Args...>::value;
+ std::is_same_v<A0, bool> || AnyBool<Args...>::value;
};
+template <typename... Args>
+static constexpr bool AnyBool_v = AnyBool<Args...>::value;
+
// Instanciate an std::integer_sequence as a buffer which is readable and
// addressable at runtime, which is used for reading argument values from the
// generated code.
template <typename Seq>
struct InstanceSeq;
template <typename Int, Int... Values>
struct InstanceSeq<std::integer_sequence<Int, Values...>> {
static constexpr Int table[sizeof...(Values)] = {Values...};
static constexpr size_t size = sizeof...(Values);
};
// Instanciate a buffer which is used for testing the position of arguments when
// calling a function.
template <typename... Args>
using TestArgsPositions = InstanceSeq<
- typename ArgsBuffer<typename ArgsIndexes<Args...>::Res, Args...>::Res>;
+ typename ArgsBuffer<typename ArgsIndexes<Args...>::type, Args...>::type>;
// Instanciate a buffer which is used for testing the position of arguments, one
// bit at a time, when calling a function.
template <size_t Bit, typename... Args>
-using TestArgsBitOfPositions = InstanceSeq<
- typename ArgsBuffer<typename ArgsBitOfIndexes<Bit, Args...>::Res, Args...>::Res>;
+using TestArgsBitOfPositions = InstanceSeq<typename ArgsBuffer<
+ typename ArgsBitOfIndexes<Bit, Args...>::type, Args...>::type>;
// Instanciate a buffer which is used to check that the size of each argument is
// interpreted correctly when calling a function.
template <typename... Args>
-using TestArgsSizes = InstanceSeq<
- typename ArgsBuffer<typename ArgsSizes<Args...>::Res, Args...>::Res>;
+using TestArgsSizes =
+ InstanceSeq<typename ArgsBuffer<ArgsSizes_t<Args...>, Args...>::type>;
// AsInt returns the raw value of any argument as an integer value which can be
// compared with the expected values.
template <typename Type>
struct AsInt {
- static typename IntTypeOf<Type>::Res Convert(Type v) {
+ static IntTypeOf_t<Type> Convert(Type v) {
// Simplify working with types by casting the address of the value to the
// equivalent `const void*`.
auto address = reinterpret_cast<const void*>(&v);
// Convert the `void*` to an integer pointer of the same size as the input
// type, and return the raw value stored in the integer interpretation.
static_assert(sizeof(WrapForSizeOf<Type>) ==
- sizeof(WrapForSizeOf<typename IntTypeOf<Type>::Res>));
- return *reinterpret_cast<const typename IntTypeOf<Type>::Res*>(address);
+ sizeof(WrapForSizeOf<IntTypeOf_t<Type>>));
+ return *reinterpret_cast<const IntTypeOf_t<Type>*>(address);
}
};
template <typename T>
struct AsInt<T&> {
using Type = T&;
- static typename IntTypeOf<Type>::Res Convert(Type v) {
+ static IntTypeOf_t<Type> Convert(Type v) {
// Simplify working with types by casting the address of the value to the
// equivalent `const void*`.
auto address = reinterpret_cast<const void*>(&v);
// Convert the `void*` to an integer pointer of the same size as the input
// type, and return the raw value stored in the integer interpretation.
static_assert(sizeof(WrapForSizeOf<Type>) ==
- sizeof(WrapForSizeOf<typename IntTypeOf<Type>::Res>));
- return reinterpret_cast<const typename IntTypeOf<Type>::Res>(address);
+ sizeof(WrapForSizeOf<IntTypeOf_t<Type>>));
+ return reinterpret_cast<const IntTypeOf_t<Type>>(address);
}
};
template <typename Type>
-typename IntTypeOf<Type>::Res ConvertToInt(Type v) {
+IntTypeOf_t<Type> ConvertToInt(Type v) {
return AsInt<Type>::Convert(std::forward<Type>(v));
}
// Check if the raw value of arguments are equals to the numbers given in the
// std::integer_sequence given as the first argument.
template <typename Int>
bool CheckArgsEqual(std::integer_sequence<Int>) {
return true;
}
template <typename Arg0, typename Int, Int V0>
bool CheckArgsEqual(std::integer_sequence<Int, V0>, Arg0 a0) {
- using CompareInt = typename IntTypeOf<Arg0>::Res;
+ using CompareInt = IntTypeOf_t<Arg0>;
if (ConvertToInt<Arg0>(a0) != CompareInt(V0)) {
return false;
}
return true;
}
template <typename Arg0, typename... Args, typename Int, Int V0, Int... Val>
bool CheckArgsEqual(std::integer_sequence<Int, V0, Val...>, Arg0 a0,
Args... args) {
- using CompareInt = typename IntTypeOf<Arg0>::Res;
+ using CompareInt = IntTypeOf_t<Arg0>;
if (ConvertToInt<Arg0>(a0) != CompareInt(V0)) {
return false;
}
return CheckArgsEqual<Args...>(std::integer_sequence<Int, Val...>(),
std::forward<Args>(args)...);
}
// Generate code which will register the value of each argument of the called
@@ -448,63 +473,63 @@ struct DefineCheckArgs<Res (*)(Args...)>
instance_ = instance;
}
virtual void check_result(bool) = 0;
// Check that arguments are interpreted in the same order at compile time and
// at runtime.
static Res CheckArgsPositions(Args... args) {
AutoUnsafeCallWithABI unsafe;
- using Indexes = typename ArgsIndexes<Args...>::Res;
+ using Indexes = typename ArgsIndexes<Args...>::type;
bool res = CheckArgsEqual<Args...>(Indexes(), std::forward<Args>(args)...);
instance_->check_result(res);
return Res();
}
// This is the same test as above, but some compilers might clean the boolean
// values using `& 1` operations, which corrupt the operand index, thus to
// properly check for the position of boolean operands, we have to check the
// position of the boolean operand using a single bit at a time.
static Res CheckArgsPositions0(Args... args) {
AutoUnsafeCallWithABI unsafe;
- using Indexes = typename ArgsBitOfIndexes<0, Args...>::Res;
+ using Indexes = typename ArgsBitOfIndexes<0, Args...>::type;
bool res = CheckArgsEqual<Args...>(Indexes(), std::forward<Args>(args)...);
instance_->check_result(res);
return Res();
}
static Res CheckArgsPositions1(Args... args) {
AutoUnsafeCallWithABI unsafe;
- using Indexes = typename ArgsBitOfIndexes<1, Args...>::Res;
+ using Indexes = typename ArgsBitOfIndexes<1, Args...>::type;
bool res = CheckArgsEqual<Args...>(Indexes(), std::forward<Args>(args)...);
instance_->check_result(res);
return Res();
}
static Res CheckArgsPositions2(Args... args) {
AutoUnsafeCallWithABI unsafe;
- using Indexes = typename ArgsBitOfIndexes<2, Args...>::Res;
+ using Indexes = typename ArgsBitOfIndexes<2, Args...>::type;
bool res = CheckArgsEqual<Args...>(Indexes(), std::forward<Args>(args)...);
instance_->check_result(res);
return Res();
}
static Res CheckArgsPositions3(Args... args) {
AutoUnsafeCallWithABI unsafe;
- using Indexes = typename ArgsBitOfIndexes<3, Args...>::Res;
+ using Indexes = typename ArgsBitOfIndexes<3, Args...>::type;
bool res = CheckArgsEqual<Args...>(Indexes(), std::forward<Args>(args)...);
instance_->check_result(res);
return Res();
}
// Check that the size of each argument, known at compile time and at runtime
// are identical.
static Res CheckArgsSizes(Args... args) {
AutoUnsafeCallWithABI unsafe;
- using Sizes = typename ArgsSizes<Args...>::Res;
+ using Sizes = ArgsSizes_t<Args...>;
bool res = CheckArgsEqual<Args...>(Sizes(), std::forward<Args>(args)...);
instance_->check_result(res);
return Res();
}
using FunType = Res (*)(Args...);
struct Test {
const uint8_t* buffer;
@@ -530,28 +555,28 @@ struct DefineCheckArgs<Res (*)(Args...)>
{ArgsPositions0::table, ArgsPositions0::size, CheckArgsPositions0},
{ArgsPositions1::table, ArgsPositions1::size, CheckArgsPositions1},
{ArgsPositions2::table, ArgsPositions2::size, CheckArgsPositions2},
{ArgsPositions3::table, ArgsPositions3::size, CheckArgsPositions3},
{ArgsSizes::table, ArgsSizes::size, CheckArgsSizes},
};
const Test* tests = testsWithoutBoolArgs;
size_t numTests = 2;
- if (AnyBool<Args...>::value) {
+ if (AnyBool_v<Args...>) {
tests = testsWithBoolArgs;
numTests = 5;
}
for (size_t i = 0; i < numTests; i++) {
const Test& test = tests[i];
masm.movePtr(ImmPtr(test.buffer), base);
masm.setupUnalignedABICall(setup);
- using Offsets = typename ArgsOffsets<0, Args...>::Res;
- using MoveOps = typename ArgsMoveOps<Args...>::Res;
+ using Offsets = ArgsOffsets_t<0, Args...>;
+ using MoveOps = ArgsMoveOps_t<Args...>;
passABIArgs(masm, base, Offsets(), MoveOps());
masm.callWithABI(DynFn{JS_FUNC_TO_DATA_PTR(void*, test.fun)},
MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckOther);
}
}
private:
// As we are checking specific function signature, we cannot add extra
# HG changeset patch
# User Steve Fink <[email protected]>
# Date 1601596630 25200
# Thu Oct 01 16:57:10 2020 -0700
# Node ID 4383fff479c17a6e831cf098eb8e7c3ce7a54028
# Parent cee51d93f57a7cd37195a357d7c17bb0cd9e16fc
Allow JSAPI tests to opt-in to reuse a global and cx instead of tearing everything down and starting up every time.
Cons: (1) messy, (2) may be unnecessary once Stencil allows better caching of self-hosted code.
Pros: 322x faster for testJitABIcalls.
diff --git a/js/src/jsapi-tests/testJitABIcalls.cpp b/js/src/jsapi-tests/testJitABIcalls.cpp
--- a/js/src/jsapi-tests/testJitABIcalls.cpp
+++ b/js/src/jsapi-tests/testJitABIcalls.cpp
@@ -634,17 +634,17 @@ static bool Execute(JSContext* cx, Macro
// initialized with the name of the function which has the given signature.
//
// When executed, it generates the JIT code to call functions with the same
// signature and checks that the JIT interpretation of arguments location
// matches the C++ interpretation. If it differs, the test case will fail.
template <typename Sig>
class JitABICall : public JSAPITest, public DefineCheckArgs<Sig> {
public:
- JitABICall(const char* name) : name_(name) {}
+ JitABICall(const char* name) : name_(name) { reuseGlobal = true; }
virtual void check_result(bool res) override {
result_ = result_ && check_result_wrapped(res);
}
virtual const char* name() override { return name_; }
virtual bool run(JS::HandleObject) override {
this->set_instance(this);
result_ = true;
@@ -676,17 +676,17 @@ class JitABICall : public JSAPITest, pub
template <typename Sig>
bool JitABICall<Sig>::result_ = false;
// For each VMFunction and ABIFunction, create an instance of a JitABICall class
// to register a jsapi-tests test case.
#define TEST_INSTANCE(Name, Sig) \
static JitABICall<Sig> MOZ_CONCAT(MOZ_CONCAT(cls_jitabicall, __COUNTER__), \
- _instance)(Name);
+ _instance)("JITABI " Name);
#define TEST_INSTANCE_ABIFUN_TO_ALLFUN(...) \
APPLY(TEST_INSTANCE, ABIFUN_TO_ALLFUN(__VA_ARGS__))
#define TEST_INSTANCE_ABIFUN_AND_SIG_TO_ALLFUN(...) \
APPLY(TEST_INSTANCE, ABIFUN_AND_SIG_TO_ALLFUN(__VA_ARGS__))
#define TEST_INSTANCE_ABISIG_TO_ALLFUN(...) \
APPLY(TEST_INSTANCE, ABISIG_TO_ALLFUN(__VA_ARGS__))
#define TEST_INSTANCE_VMFUN_TO_ALLFUN(...) \
APPLY(TEST_INSTANCE, VMFUN_TO_ALLFUN(__VA_ARGS__))
diff --git a/js/src/jsapi-tests/tests.cpp b/js/src/jsapi-tests/tests.cpp
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -12,16 +12,25 @@
#include "js/CompilationAndEvaluation.h" // JS::Evaluate
#include "js/Initialization.h"
#include "js/RootingAPI.h"
#include "js/SourceText.h" // JS::Source{Ownership,Text}
JSAPITest* JSAPITest::list;
+bool JSAPITest::init(JSContext* reused_cx) {
+ if (reused_cx) {
+ cx = reused_cx;
+ global.init(cx, cx->global());
+ return true;
+ }
+ return init();
+}
+
bool JSAPITest::init() {
cx = createContext();
if (!cx) {
return false;
}
js::UseInternalJobQueues(cx);
if (!JS::InitSelfHostedCode(cx)) {
return false;
@@ -30,26 +39,27 @@ bool JSAPITest::init() {
createGlobal();
if (!global) {
return false;
}
JS::EnterRealm(cx, global);
return true;
}
+void JSAPITest::finish() { msgs.clear(); }
+
void JSAPITest::uninit() {
if (global) {
JS::LeaveRealm(cx, nullptr);
global = nullptr;
}
if (cx) {
destroyContext();
cx = nullptr;
}
- msgs.clear();
}
bool JSAPITest::exec(const char* utf8, const char* filename, int lineno) {
JS::CompileOptions opts(cx);
opts.setFileAndLine(filename, lineno);
JS::SourceText<mozilla::Utf8Unit> srcBuf;
JS::RootedValue v(cx);
@@ -107,26 +117,48 @@ int main(int argc, char* argv[]) {
int failures = 0;
const char* filter = (argc == 2) ? argv[1] : nullptr;
if (!JS_Init()) {
printf("TEST-UNEXPECTED-FAIL | jsapi-tests | JS_Init() failed.\n");
return 1;
}
+ if (strcmp(filter, "--list") == 0) {
+ for (JSAPITest* test = JSAPITest::list; test; test = test->next) {
+ printf("%s\n", test->name());
+ }
+ return 0;
+ }
+
+ // Reinitializing the global for every test is quite slow, due to having to
+ // recompile all self-hosted builtins. Allow tests to opt-in to reusing the
+ // global.
+ JSAPITest* reusableTest = nullptr;
+
for (JSAPITest* test = JSAPITest::list; test; test = test->next) {
const char* name = test->name();
if (filter && strstr(name, filter) == nullptr) {
continue;
}
total += 1;
printf("%s\n", name);
- if (!test->init()) {
+ JSContext* reusedContext = nullptr;
+ if (reusableTest) {
+ if (test->reuseGlobal) {
+ reusedContext = reusableTest->releaseContext();
+ } else {
+ reusableTest->uninit();
+ }
+ reusableTest = nullptr;
+ }
+
+ if (!test->init(reusedContext)) {
printf("TEST-UNEXPECTED-FAIL | %s | Failed to initialize.\n", name);
failures++;
test->uninit();
continue;
}
if (test->run(test->global)) {
printf("TEST-PASS | %s | ok\n", name);
@@ -134,17 +166,26 @@ int main(int argc, char* argv[]) {
JSAPITestString messages = test->messages();
printf("%s | %s | %.*s\n",
(test->knownFail ? "TEST-KNOWN-FAIL" : "TEST-UNEXPECTED-FAIL"),
name, (int)messages.length(), messages.begin());
if (!test->knownFail) {
failures++;
}
}
- test->uninit();
+
+ test->finish();
+ if (test->reuseGlobal) {
+ reusableTest = test;
+ } else {
+ test->uninit();
+ }
+ }
+ if (reusableTest) {
+ reusableTest->uninit();
}
MOZ_RELEASE_ASSERT(!JSRuntime::hasLiveRuntimes());
JS_ShutDown();
if (failures) {
printf("\n%d unexpected failure%s.\n", failures,
(failures == 1 ? "" : "s"));
diff --git a/js/src/jsapi-tests/tests.h b/js/src/jsapi-tests/tests.h
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -72,27 +72,45 @@ class JSAPITest {
static JSAPITest* list;
JSAPITest* next;
JSContext* cx;
JS::PersistentRootedObject global;
bool knownFail;
JSAPITestString msgs;
+ // Whether this test is willing to skip its init() and reuse a global (and
+ // JSContext etc.) from a previous test that also has reuseGlobal=true. It
+ // also means this test is willing to skip its uninit() if it is followed by
+ // another reuseGlobal test.
+ bool reuseGlobal;
+
JSAPITest() : cx(nullptr), knownFail(false) {
next = list;
list = this;
+ reuseGlobal = false;
}
virtual ~JSAPITest() {
MOZ_RELEASE_ASSERT(!cx);
MOZ_RELEASE_ASSERT(!global);
}
+ // Initialize this test, possibly with the cx from a previously run test.
+ bool init(JSContext* reused_cx);
+
+ // Release this test's cx to be reused by another test.
+ JSContext* releaseContext() {
+ JSContext* ret = cx;
+ cx = nullptr;
+ return ret;
+ }
+
virtual bool init();
+ virtual void finish();
virtual void uninit();
virtual const char* name() = 0;
virtual bool run(JS::HandleObject global) = 0;
#define EXEC(s) \
do { \
if (!exec(s, __FILE__, __LINE__)) return false; \
# HG changeset patch
# User Steve Fink <[email protected]>
# Date 1601658360 25200
# Fri Oct 02 10:06:00 2020 -0700
# Node ID cbc6bc542e7028b8ca97b9b4f24cc4f169ac36b8
# Parent 4383fff479c17a6e831cf098eb8e7c3ce7a54028
Just an option -- instead of WrapForSizeOf, which is clever but a little indirect -- make an AsParameter<T>
diff --git a/js/src/jsapi-tests/testJitABIcalls.cpp b/js/src/jsapi-tests/testJitABIcalls.cpp
--- a/js/src/jsapi-tests/testJitABIcalls.cpp
+++ b/js/src/jsapi-tests/testJitABIcalls.cpp
@@ -81,31 +81,30 @@ struct IntBySize<4> {
using type = uint32_t;
};
template <>
struct IntBySize<8> {
using type = uint64_t;
};
-// sizeof(const T&) is not equal to sizeof(const T*). This structure is used to
-// wrap the type which size is being queried, instead of the size of the type
-// referenced by it.
+// sizeof(const T&) is not equal to sizeof(const T*), but references are passed
+// as pointers.
//
// "When applied to a reference or a reference type, the result is the size of
// the referenced type." [expr.sizeof] (5.3.3.2)
template <typename T>
-struct WrapForSizeOf {
- T unused_;
-};
+using AsParameter =
+ typename std::conditional<std::is_reference_v<T>,
+ std::remove_reference_t<T>*, T>::type;
// Given a type, return the integer type which has the same size.
template <typename T>
struct IntTypeOf {
- using type = typename IntBySize<sizeof(WrapForSizeOf<T>)>::type;
+ using type = typename IntBySize<sizeof(AsParameter<T>)>::type;
};
template <typename T>
using IntTypeOf_t = typename IntTypeOf<T>::type;
// Concatenate 2 std::integer_sequence, and return an std::integer_sequence with
// the content of both parameters.
template <typename Before, typename After>
@@ -156,19 +155,19 @@ using CstSeq_t = typename CstSeq<N, Valu
//
// This macro ensure that the MoveOperand would read the zero-ed padding added
// in front of the each value, if it reads too much.
#define AT_LEAST_SIZE(SIZE) \
((SIZE) < sizeof(uintptr_t) ? sizeof(uintptr_t) : (SIZE))
// Adds the padding and the reserved size for storing a value in a buffer which
// can be read by a MoveOperand.
-#define PADSIZE(SIZE, TYPE) \
- PADDING(Size, alignof(WrapForSizeOf<TYPE>)) + \
- AT_LEAST_SIZE(sizeof(WrapForSizeOf<TYPE>))
+#define PADSIZE(SIZE, TYPE) \
+ PADDING(Size, alignof(AsParameter<TYPE>)) + \
+ AT_LEAST_SIZE(sizeof(AsParameter<TYPE>))
// Generate an std::integer_sequence of 0 uint8_t elements of the size of the
// padding needed to align a type in memory.
template <size_t Align, size_t CurrSize>
using PadSeq = CstSeq<PADDING(CurrSize, Align), 0>;
template <size_t Align, size_t CurrSize>
using PadSeq_t = typename PadSeq<Align, CurrSize>::type;
@@ -257,17 +256,17 @@ using ArgsOffsets_t = typename ArgsOffse
static_assert(std::is_same_v<ArgsOffsets_t<0, uint8_t, uint64_t, bool>,
std::integer_sequence<size_t, 0, 8, 16>>);
// Generate an std::integer_sequence containing the size of each argument in
// memory.
template <typename... Args>
struct ArgsSizes {
- using type = std::integer_sequence<size_t, sizeof(WrapForSizeOf<Args>)...>;
+ using type = std::integer_sequence<size_t, sizeof(AsParameter<Args>)...>;
};
template <typename... Args>
using ArgsSizes_t = typename ArgsSizes<Args...>::type;
// Given a type, return the MoveOp type used by passABIArg to know how to
// interpret the value which are given as arguments.
template <typename Type>
@@ -306,17 +305,17 @@ template <uint8_t... Buffer, typename Ar
size_t... Values>
struct GenArgsBuffer<std::integer_sequence<uint8_t, Buffer...>,
std::integer_sequence<size_t, Val, Values...>, Arg,
Args...> {
using type = typename GenArgsBuffer<
Concat_t<
std::integer_sequence<uint8_t, Buffer...>,
Concat_t<PadSeq_t<alignof(Arg), sizeof...(Buffer)>,
- typename FillSeq<AT_LEAST_SIZE(sizeof(WrapForSizeOf<Arg>)),
+ typename FillSeq<AT_LEAST_SIZE(sizeof(AsParameter<Arg>)),
Val>::type>>,
std::integer_sequence<size_t, Values...>, Args...>::type;
};
template <typename Buffer>
struct GenArgsBuffer<Buffer, std::integer_sequence<size_t>> {
using type = Buffer;
};
@@ -388,33 +387,33 @@ using TestArgsSizes =
template <typename Type>
struct AsInt {
static IntTypeOf_t<Type> Convert(Type v) {
// Simplify working with types by casting the address of the value to the
// equivalent `const void*`.
auto address = reinterpret_cast<const void*>(&v);
// Convert the `void*` to an integer pointer of the same size as the input
// type, and return the raw value stored in the integer interpretation.
- static_assert(sizeof(WrapForSizeOf<Type>) ==
- sizeof(WrapForSizeOf<IntTypeOf_t<Type>>));
+ static_assert(sizeof(AsParameter<Type>) ==
+ sizeof(AsParameter<IntTypeOf_t<Type>>));
return *reinterpret_cast<const IntTypeOf_t<Type>*>(address);
}
};
template <typename T>
struct AsInt<T&> {
using Type = T&;
static IntTypeOf_t<Type> Convert(Type v) {
// Simplify working with types by casting the address of the value to the
// equivalent `const void*`.
auto address = reinterpret_cast<const void*>(&v);
// Convert the `void*` to an integer pointer of the same size as the input
// type, and return the raw value stored in the integer interpretation.
- static_assert(sizeof(WrapForSizeOf<Type>) ==
- sizeof(WrapForSizeOf<IntTypeOf_t<Type>>));
+ static_assert(sizeof(AsParameter<Type>) ==
+ sizeof(AsParameter<IntTypeOf_t<Type>>));
return reinterpret_cast<const IntTypeOf_t<Type>>(address);
}
};
template <typename Type>
IntTypeOf_t<Type> ConvertToInt(Type v) {
return AsInt<Type>::Convert(std::forward<Type>(v));
}
# HG changeset patch
# User Steve Fink <[email protected]>
# Date 1601658624 25200
# Fri Oct 02 10:10:24 2020 -0700
# Node ID 42d2e88d3714ba846ed83f5e0b2b235b7dc83944
# Parent cbc6bc542e7028b8ca97b9b4f24cc4f169ac36b8
Remove some code with `if constexpr`
diff --git a/js/src/jsapi-tests/testJitABIcalls.cpp b/js/src/jsapi-tests/testJitABIcalls.cpp
--- a/js/src/jsapi-tests/testJitABIcalls.cpp
+++ b/js/src/jsapi-tests/testJitABIcalls.cpp
@@ -389,32 +389,21 @@ struct AsInt {
static IntTypeOf_t<Type> Convert(Type v) {
// Simplify working with types by casting the address of the value to the
// equivalent `const void*`.
auto address = reinterpret_cast<const void*>(&v);
// Convert the `void*` to an integer pointer of the same size as the input
// type, and return the raw value stored in the integer interpretation.
static_assert(sizeof(AsParameter<Type>) ==
sizeof(AsParameter<IntTypeOf_t<Type>>));
- return *reinterpret_cast<const IntTypeOf_t<Type>*>(address);
- }
-};
-
-template <typename T>
-struct AsInt<T&> {
- using Type = T&;
- static IntTypeOf_t<Type> Convert(Type v) {
- // Simplify working with types by casting the address of the value to the
- // equivalent `const void*`.
- auto address = reinterpret_cast<const void*>(&v);
- // Convert the `void*` to an integer pointer of the same size as the input
- // type, and return the raw value stored in the integer interpretation.
- static_assert(sizeof(AsParameter<Type>) ==
- sizeof(AsParameter<IntTypeOf_t<Type>>));
- return reinterpret_cast<const IntTypeOf_t<Type>>(address);
+ if constexpr (std::is_reference_v<Type>) {
+ return reinterpret_cast<const IntTypeOf_t<Type>>(address);
+ } else {
+ return *reinterpret_cast<const IntTypeOf_t<Type>*>(address);
+ }
}
};
template <typename Type>
IntTypeOf_t<Type> ConvertToInt(Type v) {
return AsInt<Type>::Convert(std::forward<Type>(v));
}
# HG changeset patch
# User Steve Fink <[email protected]>
# Date 1601670279 25200
# Fri Oct 02 13:24:39 2020 -0700
# Node ID 05246ab2d673393e4f37bc4db5b6df91ab3bf62f
# Parent 42d2e88d3714ba846ed83f5e0b2b235b7dc83944
Not sure about this one, but it seemed odd to have a new name for std::index_sequence_for. Then again, giving it a new name makes it look more like the other similar sequences.
diff --git a/js/src/jsapi-tests/testJitABIcalls.cpp b/js/src/jsapi-tests/testJitABIcalls.cpp
--- a/js/src/jsapi-tests/testJitABIcalls.cpp
+++ b/js/src/jsapi-tests/testJitABIcalls.cpp
@@ -194,42 +194,31 @@ struct FillLESeq<0, Value, Rest...> {
};
template <size_t N, size_t Value>
using FillSeq = FillLESeq<N, Value>;
static_assert(std::is_same_v<typename FillSeq<4, 2>::type,
std::integer_sequence<uint8_t, 2, 0, 0, 0>>);
-// Given a list of template parameters, generate an std::integer_sequence of
-// size_t, where each element is 1 larger than the previous one. The generated
-// sequence starts at 0.
-template <typename... Args>
-struct ArgsIndexes {
- using type = std::index_sequence_for<Args...>;
-};
-
-static_assert(std::is_same_v<typename ArgsIndexes<uint8_t, uint64_t>::type,
- std::integer_sequence<size_t, 0, 1>>);
-
// Extract a single bit for each element of an std::integer_sequence. This is
// used to work-around some restriction around providing boolean arguments,
// which might be truncated to a single bit.
template <size_t Bit, typename IntSeq>
struct ExtractBit;
template <size_t Bit, size_t... Values>
struct ExtractBit<Bit, std::integer_sequence<size_t, Values...>> {
using type = std::integer_sequence<size_t, (Values >> Bit) & 1 ...>;
};
// Generate an std::integer_sequence of indexes which are filtered for a single
// bit, such that it can be used with boolean types.
template <size_t Bit, typename... Args>
-using ArgsBitOfIndexes = ExtractBit<Bit, typename ArgsIndexes<Args...>::type>;
+using ArgsBitOfIndexes = ExtractBit<Bit, std::index_sequence_for<Args...>>;
static_assert(
std::is_same_v<typename ArgsBitOfIndexes<0, int, int, int, int>::type,
std::integer_sequence<size_t, 0, 1, 0, 1>>);
static_assert(
std::is_same_v<typename ArgsBitOfIndexes<1, int, int, int, int>::type,
std::integer_sequence<size_t, 0, 0, 1, 1>>);
@@ -363,17 +352,17 @@ struct InstanceSeq<std::integer_sequence
static constexpr Int table[sizeof...(Values)] = {Values...};
static constexpr size_t size = sizeof...(Values);
};
// Instanciate a buffer which is used for testing the position of arguments when
// calling a function.
template <typename... Args>
using TestArgsPositions = InstanceSeq<
- typename ArgsBuffer<typename ArgsIndexes<Args...>::type, Args...>::type>;
+ typename ArgsBuffer<std::index_sequence_for<Args...>, Args...>::type>;
// Instanciate a buffer which is used for testing the position of arguments, one
// bit at a time, when calling a function.
template <size_t Bit, typename... Args>
using TestArgsBitOfPositions = InstanceSeq<typename ArgsBuffer<
typename ArgsBitOfIndexes<Bit, Args...>::type, Args...>::type>;
// Instanciate a buffer which is used to check that the size of each argument is
@@ -461,17 +450,17 @@ struct DefineCheckArgs<Res (*)(Args...)>
instance_ = instance;
}
virtual void check_result(bool) = 0;
// Check that arguments are interpreted in the same order at compile time and
// at runtime.
static Res CheckArgsPositions(Args... args) {
AutoUnsafeCallWithABI unsafe;
- using Indexes = typename ArgsIndexes<Args...>::type;
+ using Indexes = std::index_sequence_for<Args...>;
bool res = CheckArgsEqual<Args...>(Indexes(), std::forward<Args>(args)...);
instance_->check_result(res);
return Res();
}
// This is the same test as above, but some compilers might clean the boolean
// values using `& 1` operations, which corrupt the operand index, thus to
// properly check for the position of boolean operands, we have to check the
# HG changeset patch
# User Steve Fink <[email protected]>
# Date 1601670393 25200
# Fri Oct 02 13:26:33 2020 -0700
# Node ID 55ad64aeac201e237f8d7261d86d4ae74de8c6a1
# Parent 05246ab2d673393e4f37bc4db5b6df91ab3bf62f
Small tweaks
diff --git a/js/src/jsapi-tests/testJitABIcalls.cpp b/js/src/jsapi-tests/testJitABIcalls.cpp
--- a/js/src/jsapi-tests/testJitABIcalls.cpp
+++ b/js/src/jsapi-tests/testJitABIcalls.cpp
@@ -141,38 +141,37 @@ struct CstSeq<1, Value> {
using type = std::integer_sequence<uint8_t, Value>;
};
template <size_t N, uint8_t Value>
using CstSeq_t = typename CstSeq<N, Value>::type;
// Computes the number of bytes to add before a type in order to align it in
// memory.
-#define PADDING(SIZE, ALIGN) ((ALIGN) - ((SIZE) % (ALIGN))) % (ALIGN)
+#define PADBYTES(SIZE, ALIGN) ((ALIGN) - ((SIZE) % (ALIGN))) % (ALIGN)
// Request a minimum alignment for the values which are added in a buffer, in
// order to account for the read size used by the MoveOperand given as argument
// of passWithABI. The MoveOperand do not take into consideration the size of
// the data which is being transfered, and might load a larger amount of data.
//
// This macro ensure that the MoveOperand would read the zero-ed padding added
// in front of the each value, if it reads too much.
-#define AT_LEAST_SIZE(SIZE) \
- ((SIZE) < sizeof(uintptr_t) ? sizeof(uintptr_t) : (SIZE))
+#define AT_LEAST_SIZE(SIZE) std::max((SIZE), sizeof(uintptr_t))
// Adds the padding and the reserved size for storing a value in a buffer which
// can be read by a MoveOperand.
#define PADSIZE(SIZE, TYPE) \
- PADDING(Size, alignof(AsParameter<TYPE>)) + \
+ PADBYTES(Size, alignof(AsParameter<TYPE>)) + \
AT_LEAST_SIZE(sizeof(AsParameter<TYPE>))
// Generate an std::integer_sequence of 0 uint8_t elements of the size of the
// padding needed to align a type in memory.
template <size_t Align, size_t CurrSize>
-using PadSeq = CstSeq<PADDING(CurrSize, Align), 0>;
+using PadSeq = CstSeq<PADBYTES(CurrSize, Align), 0>;
template <size_t Align, size_t CurrSize>
using PadSeq_t = typename PadSeq<Align, CurrSize>::type;
static_assert(std::is_same_v<PadSeq_t<4, 0>, std::integer_sequence<uint8_t>>);
static_assert(
std::is_same_v<PadSeq_t<4, 3>, std::integer_sequence<uint8_t, 0>>);
static_assert(
@@ -231,17 +230,17 @@ struct ArgsOffsets;
template <size_t Size>
struct ArgsOffsets<Size> {
using type = std::integer_sequence<size_t>;
};
template <size_t Size, typename Arg, typename... Args>
struct ArgsOffsets<Size, Arg, Args...> {
using type = Concat_t<
- std::integer_sequence<size_t, Size + PADDING(Size, alignof(Arg))>,
+ std::integer_sequence<size_t, Size + PADBYTES(Size, alignof(Arg))>,
typename ArgsOffsets<Size + PADSIZE(Size, Arg), Args...>::type>;
};
template <size_t Size, typename... Args>
using ArgsOffsets_t = typename ArgsOffsets<Size, Args...>::type;
static_assert(std::is_same_v<ArgsOffsets_t<0, uint8_t, uint64_t, bool>,
std::integer_sequence<size_t, 0, 8, 16>>);
# HG changeset patch
# User Steve Fink <[email protected]>
# Date 1601658665 25200
# Fri Oct 02 10:11:05 2020 -0700
# Node ID 34cad7f28fc64af7e00f0e6620551a002f208877
# Parent 55ad64aeac201e237f8d7261d86d4ae74de8c6a1
Comment fixups
diff --git a/js/src/jsapi-tests/testJitABIcalls.cpp b/js/src/jsapi-tests/testJitABIcalls.cpp
--- a/js/src/jsapi-tests/testJitABIcalls.cpp
+++ b/js/src/jsapi-tests/testJitABIcalls.cpp
@@ -27,38 +27,38 @@ using namespace js::jit;
// This test case relies on VMFUNCTION_LIST, TAIL_CALL_VMFUNCTION_LIST,
// ABIFUNCTION_LIST, ABIFUNCTION_AND_TYPE_LIST and ABIFUNCTIONSIG_LIST, to
// create a test case for each function registered, in order to check if the
// arguments are properly being interpreted after a call from the JIT.
//
// This test check that the interpretation of the C++ compiler matches the
// interpretation of the JIT. It works by generating a call to a function which
// has the same signature as the tested function. The function being called
-// re-interpret the arguments content to ensure that it matches the content
-// given as argument by the JIT.
+// re-interprets the arguments' content to ensure that it matches the content
+// given as arguments by the JIT.
//
// These tests cases succeed if the content provided by the JIT matches the
-// content read by the C++ code. Otherwise, a failure imply that either the
-// MacroAssembler are not used properly, or that the code used by the JIT to
-// generate the function call does not match the ABI of the targetted system.
+// content read by the C++ code. Otherwise, a failure implies that either the
+// MacroAssembler is not used properly, or that the code used by the JIT to
+// generate the function call does not match the ABI of the targeted system.
// Convert the content of each macro list to a single and unique format which is
// (Name, Type).
#define ABIFUN_TO_ALLFUN(Fun) (#Fun, decltype(&::Fun))
#define ABIFUN_AND_SIG_TO_ALLFUN(Fun, Sig) (#Fun " as " #Sig, Sig)
#define ABISIG_TO_ALLFUN(Sig) ("(none) as " #Sig, Sig)
#define VMFUN_TO_ALLFUN(Name, Fun) (#Fun, decltype(&::Fun))
#define TC_VMFUN_TO_ALLFUN(Name, Fun, Pop) (#Fun, decltype(&::Fun))
#define APPLY(A, B) A B
// Generate macro calls for all the lists which are used to allow, directly or
// indirectly, calls performed with callWithABI.
//
-// This macro will delegate to a diffferent macro call based on the type of the
+// This macro will delegate to a different macro call based on the type of the
// list the element is extracted from.
#define ALL_FUNCTIONS(PREFIX) \
ABIFUNCTION_LIST(PREFIX##_ABIFUN_TO_ALLFUN) \
ABIFUNCTION_AND_TYPE_LIST(PREFIX##_ABIFUN_AND_SIG_TO_ALLFUN) \
ABIFUNCTIONSIG_LIST(PREFIX##_ABISIG_TO_ALLFUN) \
VMFUNCTION_LIST(PREFIX##_VMFUN_TO_ALLFUN) \
TAIL_CALL_VMFUNCTION_LIST(PREFIX##_TC_VMFUN_TO_ALLFUN)
@@ -119,17 +119,17 @@ struct Concat<std::integer_sequence<Int,
template <typename Before, typename After>
using Concat_t = typename Concat<Before, After>::type;
static_assert(std::is_same_v<Concat_t<std::integer_sequence<uint8_t, 1, 2>,
std::integer_sequence<uint8_t, 3, 4>>,
std::integer_sequence<uint8_t, 1, 2, 3, 4>>);
// Generate an std::integer_sequence of `N` elements, where each element is an
-// uint8_t integers with value `Value`.
+// uint8_t integer with value `Value`.
template <size_t N, uint8_t Value>
struct CstSeq {
using type = Concat_t<typename CstSeq<N / 2, Value>::type,
typename CstSeq<N - N / 2, Value>::type>;
};
template <uint8_t Value>
struct CstSeq<0, Value> {
@@ -143,32 +143,32 @@ struct CstSeq<1, Value> {
template <size_t N, uint8_t Value>
using CstSeq_t = typename CstSeq<N, Value>::type;
// Computes the number of bytes to add before a type in order to align it in
// memory.
#define PADBYTES(SIZE, ALIGN) ((ALIGN) - ((SIZE) % (ALIGN))) % (ALIGN)
-// Request a minimum alignment for the values which are added in a buffer, in
-// order to account for the read size used by the MoveOperand given as argument
-// of passWithABI. The MoveOperand do not take into consideration the size of
-// the data which is being transfered, and might load a larger amount of data.
+// Request a minimum alignment for the values added to a buffer in order to
+// account for the read size used by the MoveOperand given as an argument of
+// passWithABI. The MoveOperand does not take into consideration the size of
+// the data being transfered, and might load a larger amount of data.
//
-// This macro ensure that the MoveOperand would read the zero-ed padding added
+// This macro ensures that the MoveOperand would read the zero-ed padding added
// in front of the each value, if it reads too much.
#define AT_LEAST_SIZE(SIZE) std::max((SIZE), sizeof(uintptr_t))
// Adds the padding and the reserved size for storing a value in a buffer which
// can be read by a MoveOperand.
#define PADSIZE(SIZE, TYPE) \
PADBYTES(Size, alignof(AsParameter<TYPE>)) + \
AT_LEAST_SIZE(sizeof(AsParameter<TYPE>))
-// Generate an std::integer_sequence of 0 uint8_t elements of the size of the
+// Generate an std::integer_sequence of 0:uint8_t elements of the size of the
// padding needed to align a type in memory.
template <size_t Align, size_t CurrSize>
using PadSeq = CstSeq<PADBYTES(CurrSize, Align), 0>;
template <size_t Align, size_t CurrSize>
using PadSeq_t = typename PadSeq<Align, CurrSize>::type;
static_assert(std::is_same_v<PadSeq_t<4, 0>, std::integer_sequence<uint8_t>>);
@@ -194,17 +194,17 @@ struct FillLESeq<0, Value, Rest...> {
template <size_t N, size_t Value>
using FillSeq = FillLESeq<N, Value>;
static_assert(std::is_same_v<typename FillSeq<4, 2>::type,
std::integer_sequence<uint8_t, 2, 0, 0, 0>>);
// Extract a single bit for each element of an std::integer_sequence. This is
-// used to work-around some restriction around providing boolean arguments,
+// used to work around some restrictions with providing boolean arguments,
// which might be truncated to a single bit.
template <size_t Bit, typename IntSeq>
struct ExtractBit;
template <size_t Bit, size_t... Values>
struct ExtractBit<Bit, std::integer_sequence<size_t, Values...>> {
using type = std::integer_sequence<size_t, (Values >> Bit) & 1 ...>;
};
@@ -307,25 +307,25 @@ template <typename Buffer>
struct GenArgsBuffer<Buffer, std::integer_sequence<size_t>> {
using type = Buffer;
};
template <typename Values, typename... Args>
using ArgsBuffer =
GenArgsBuffer<std::integer_sequence<uint8_t>, Values, Args...>;
-// NOTE: The representation of the boolean might be surpising in this test case,
-// see AT_LEAST_SIZE macro for an explanation.
+// NOTE: The representation of the boolean might be surprising in this test
+// case, see AT_LEAST_SIZE macro for an explanation.
static_assert(
std::is_same_v<typename ArgsBuffer<std::integer_sequence<size_t, 42, 51>,
uint64_t, bool>::type,
std::integer_sequence<uint8_t, 42, 0, 0, 0, 0, 0, 0, 0, 51,
0, 0, 0, 0, 0, 0, 0>>);
-// Test used to check if any of the type given as template parameter is a
+// Test used to check if any of the types given as template parameters are
// `bool`, which is a corner case where a raw integer might be truncated by the
// C++ compiler.
template <typename... Args>
struct AnyBool;
template <>
struct AnyBool<> {
static constexpr bool value = false;
@@ -335,42 +335,41 @@ template <typename A0, typename... Args>
struct AnyBool<A0, Args...> {
static constexpr bool value =
std::is_same_v<A0, bool> || AnyBool<Args...>::value;
};
template <typename... Args>
static constexpr bool AnyBool_v = AnyBool<Args...>::value;
-// Instanciate an std::integer_sequence as a buffer which is readable and
-// addressable at runtime, which is used for reading argument values from the
-// generated code.
+// Instantiate an std::integer_sequence as a buffer which is readable and
+// addressable at runtime, for reading argument values from the generated code.
template <typename Seq>
struct InstanceSeq;
template <typename Int, Int... Values>
struct InstanceSeq<std::integer_sequence<Int, Values...>> {
static constexpr Int table[sizeof...(Values)] = {Values...};
static constexpr size_t size = sizeof...(Values);
};
-// Instanciate a buffer which is used for testing the position of arguments when
-// calling a function.
+// Instantiate a buffer for testing the position of arguments when calling a
+// function.
template <typename... Args>
using TestArgsPositions = InstanceSeq<
typename ArgsBuffer<std::index_sequence_for<Args...>, Args...>::type>;
-// Instanciate a buffer which is used for testing the position of arguments, one
-// bit at a time, when calling a function.
+// Instantiate a buffer for testing the position of arguments, one bit at a
+// time, when calling a function.
template <size_t Bit, typename... Args>
using TestArgsBitOfPositions = InstanceSeq<typename ArgsBuffer<
typename ArgsBitOfIndexes<Bit, Args...>::type, Args...>::type>;
-// Instanciate a buffer which is used to check that the size of each argument is
-// interpreted correctly when calling a function.
+// Instantiate a buffer to check that the size of each argument is interpreted
+// correctly when calling a function.
template <typename... Args>
using TestArgsSizes =
InstanceSeq<typename ArgsBuffer<ArgsSizes_t<Args...>, Args...>::type>;
// AsInt returns the raw value of any argument as an integer value which can be
// compared with the expected values.
template <typename Type>
struct AsInt {
@@ -390,17 +389,17 @@ struct AsInt {
}
};
template <typename Type>
IntTypeOf_t<Type> ConvertToInt(Type v) {
return AsInt<Type>::Convert(std::forward<Type>(v));
}
-// Check if the raw value of arguments are equals to the numbers given in the
+// Check if the raw values of arguments are equal to the numbers given in the
// std::integer_sequence given as the first argument.
template <typename Int>
bool CheckArgsEqual(std::integer_sequence<Int>) {
return true;
}
template <typename Arg0, typename Int, Int V0>
bool CheckArgsEqual(std::integer_sequence<Int, V0>, Arg0 a0) {
@@ -417,33 +416,34 @@ bool CheckArgsEqual(std::integer_sequenc
using CompareInt = IntTypeOf_t<Arg0>;
if (ConvertToInt<Arg0>(a0) != CompareInt(V0)) {
return false;
}
return CheckArgsEqual<Args...>(std::integer_sequence<Int, Val...>(),
std::forward<Args>(args)...);
}
-// Generate code which will register the value of each argument of the called
-// function. Each argument content is read from a buffer which address is stored
-// in the `base` register. The offset of arguments as third argument is expected
-// to be generated by `ArgsOffsets`. The MoveOp type of arguments as fourth
-// argument is expected to be generated by `ArgsMoveOp`.
+// Generate code to register the value of each argument of the called function.
+// Each argument's content is read from a buffer whose address is stored in the
+// `base` register. The offsets of arguments are given as a third argument
+// which is expected to be generated by `ArgsOffsets`. The MoveOp types of
+// arguments are given as the fourth argument and are expected to be generated
+// by `ArgsMoveOp`.
template <size_t... Off, MoveOp::Type... Move>
static void passABIArgs(MacroAssembler& masm, Register base,
std::integer_sequence<size_t, Off...>,
std::integer_sequence<MoveOp::Type, Move...>) {
(masm.passABIArg(MoveOperand(base, Off), Move), ...);
}
-// For each function type given as parameter, create a few function with the
+// For each function type given as a parameter, create a few functions with the
// given type, to be called by the JIT code produced by `generateCalls`. These
-// functions would report the result through the `check_result` function and
-// rely on the `set_instance` function, as we cannot add extra arguments to
-// these functions.
+// functions report the result through the `check_result` function and rely on
+// the `set_instance` function, as we cannot add extra arguments to these
+// functions.
template <typename Type>
struct DefineCheckArgs;
template <typename Res, typename... Args>
struct DefineCheckArgs<Res (*)(Args...)> {
void set_instance(DefineCheckArgs* instance) {
MOZ_ASSERT((!instance_) != (!instance));
instance_ = instance;
@@ -491,36 +491,36 @@ struct DefineCheckArgs<Res (*)(Args...)>
static Res CheckArgsPositions3(Args... args) {
AutoUnsafeCallWithABI unsafe;
using Indexes = typename ArgsBitOfIndexes<3, Args...>::type;
bool res = CheckArgsEqual<Args...>(Indexes(), std::forward<Args>(args)...);
instance_->check_result(res);
return Res();
}
- // Check that the size of each argument, known at compile time and at runtime
- // are identical.
+ // Check that the compile time and run time sizes of each argument are the
+ // same.
static Res CheckArgsSizes(Args... args) {
AutoUnsafeCallWithABI unsafe;
using Sizes = ArgsSizes_t<Args...>;
bool res = CheckArgsEqual<Args...>(Sizes(), std::forward<Args>(args)...);
instance_->check_result(res);
return Res();
}
using FunType = Res (*)(Args...);
struct Test {
const uint8_t* buffer;
const size_t size;
const FunType fun;
};
- // Generate JIT code which is in charge of calling the above test function
- // where each argument is given a raw value which would be compared by each
- // function called.
+ // Generate JIT code for calling the above test functions where each argument
+ // is given a different raw value that can be compared by each called
+ // function.
void generateCalls(MacroAssembler& masm, Register base, Register setup) {
using ArgsPositions = TestArgsPositions<Args...>;
using ArgsPositions0 = TestArgsBitOfPositions<0, Args...>;
using ArgsPositions1 = TestArgsBitOfPositions<1, Args...>;
using ArgsPositions2 = TestArgsBitOfPositions<2, Args...>;
using ArgsPositions3 = TestArgsBitOfPositions<3, Args...>;
using ArgsSizes = TestArgsSizes<Args...>;
const Test testsWithoutBoolArgs[2] = {
@@ -562,17 +562,17 @@ struct DefineCheckArgs<Res (*)(Args...)>
};
template <typename Res, typename... Args>
DefineCheckArgs<Res (*)(Args...)>*
DefineCheckArgs<Res (*)(Args...)>::instance_ = nullptr;
typedef void (*EnterTest)();
-// On entry in the JIT code, save every register.
+// On entry to the JIT code, save every register.
static void Prepare(MacroAssembler& masm) {
AllocatableRegisterSet regs(RegisterSet::All());
LiveRegisterSet save(regs.asLiveSet());
masm.PushRegsInMask(save);
}
// Generate the exit path of the JIT code, which restores every register. Then,
// make it executable and run it.
@@ -599,20 +599,20 @@ static bool Execute(JSContext* cx, Macro
}
JS::AutoSuppressGCAnalysis suppress;
EnterTest test = code->as<EnterTest>();
test();
return true;
}
-// This is an child class of the JSAPITest, which is used behind the scene to
+// This is a child class of JSAPITest, which is used behind the scenes to
// register test cases in jsapi-tests. Each instance of it creates a new test
// case. This class is specialized with the type of the function to check, and
-// initialized with the name of the function which has the given signature.
+// initialized with the name of the function with the given signature.
//
// When executed, it generates the JIT code to call functions with the same
// signature and checks that the JIT interpretation of arguments location
// matches the C++ interpretation. If it differs, the test case will fail.
template <typename Sig>
class JitABICall : public JSAPITest, public DefineCheckArgs<Sig> {
public:
JitABICall(const char* name) : name_(name) { reuseGlobal = true; }
@@ -648,21 +648,21 @@ class JitABICall : public JSAPITest, pub
CHECK_EQUAL(res, true);
return true;
}
};
template <typename Sig>
bool JitABICall<Sig>::result_ = false;
-// For each VMFunction and ABIFunction, create an instance of a JitABICall class
-// to register a jsapi-tests test case.
+// For each VMFunction and ABIFunction, create an instance of a JitABICall
+// class to register a jsapi-tests test case.
#define TEST_INSTANCE(Name, Sig) \
static JitABICall<Sig> MOZ_CONCAT(MOZ_CONCAT(cls_jitabicall, __COUNTER__), \
- _instance)("JITABI " Name);
+ _instance)("JIT ABI for " Name);
#define TEST_INSTANCE_ABIFUN_TO_ALLFUN(...) \
APPLY(TEST_INSTANCE, ABIFUN_TO_ALLFUN(__VA_ARGS__))
#define TEST_INSTANCE_ABIFUN_AND_SIG_TO_ALLFUN(...) \
APPLY(TEST_INSTANCE, ABIFUN_AND_SIG_TO_ALLFUN(__VA_ARGS__))
#define TEST_INSTANCE_ABISIG_TO_ALLFUN(...) \
APPLY(TEST_INSTANCE, ABISIG_TO_ALLFUN(__VA_ARGS__))
#define TEST_INSTANCE_VMFUN_TO_ALLFUN(...) \
APPLY(TEST_INSTANCE, VMFUN_TO_ALLFUN(__VA_ARGS__))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment