* std::enable_if style conditional specializations.
*/
+/*
+ * Position may need to be initialized based on the ThreadContext, for instance
+ * to find out where the stack pointer is initially.
+ */
+template <typename ABI, typename Enabled=void>
+struct PositionInitializer
+{
+ static typename ABI::Position
+ init(const ThreadContext *tc)
+ {
+ return typename ABI::Position();
+ }
+};
+
+template <typename ABI>
+struct PositionInitializer<ABI, typename std::enable_if<
+ std::is_constructible<typename ABI::Position, const ThreadContext *>::value
+ >::type>
+{
+ static typename ABI::Position
+ init(const ThreadContext *tc)
+ {
+ return typename ABI::Position(tc);
+ }
+};
+
template <typename ABI, typename Ret, typename Enabled=void>
struct Result
{
{
// Default construct a Position to track consumed resources. Built in
// types will be zero initialized.
- auto position = typename ABI::Position();
+ auto position = GuestABI::PositionInitializer<ABI>::init(tc);
GuestABI::ResultAllocator<ABI, Ret>::allocate(tc, position);
return GuestABI::callFrom<ABI, Ret, Args...>(tc, position, target);
}
{
// Default construct a Position to track consumed resources. Built in
// types will be zero initialized.
- auto position = typename ABI::Position();
+ auto position = GuestABI::PositionInitializer<ABI>::init(tc);
GuestABI::callFrom<ABI, Args...>(tc, position, target);
}
std::function<Ret(ThreadContext *, Args...)> target=
std::function<Ret(ThreadContext *, Args...)>())
{
- auto position = typename ABI::Position();
+ auto position = GuestABI::PositionInitializer<ABI>::init(tc);
std::ostringstream ss;
GuestABI::ResultAllocator<ABI, Ret>::allocate(tc, position);
int intResult = DefaultIntResult;
double floatResult = DefaultFloatResult;
+
+ int intOffset = 0;
};
const int ThreadContext::ints[] = {
using Position = std::pair<int, int>;
};
+struct TestABI_TcInit
+{
+ struct Position
+ {
+ int pos;
+ Position(const ThreadContext *tc) : pos(tc->intOffset) {}
+ };
+};
+
namespace GuestABI
{
}
};
+// Hooks for the TcInit ABI arguments.
+template <>
+struct Argument<TestABI_TcInit, int>
+{
+ static int
+ get(ThreadContext *tc, TestABI_TcInit::Position &position)
+ {
+ return tc->ints[position.pos++];
+ }
+};
+
} // namespace GuestABI
// Test function which verifies that its arguments reflect the 1D ABI and
EXPECT_EQ(varargs.get<double>(), tc->floats[3]);
}
+void
+testTcInit(ThreadContext *tc, int a)
+{
+ EXPECT_EQ(tc->intOffset, 2);
+ EXPECT_EQ(a, tc->ints[2]);
+}
+
// Test functions which returns various types of values.
const int IntRetValue = 50;
const float FloatRetValue = 3.14;
EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
}
+TEST(GuestABI, ABI_TC_init)
+{
+ ThreadContext tc;
+ tc.intOffset = 2;
+ invokeSimcall<TestABI_TcInit>(&tc, testTcInit);
+}
+
TEST(GuestABI, ABI_returns)
{
// 1D returns.