// and write a result (if any) back to. For convenience, the wrapper also
// returns the result of the wrapped function.
-template <typename ABI, typename Ret, typename ...Args>
+template <typename ABI, bool store_ret, typename Ret, typename ...Args>
Ret
invokeSimcall(ThreadContext *tc,
std::function<Ret(ThreadContext *, Args...)> target)
// types will be zero initialized.
auto state = GuestABI::initializeState<ABI>(tc);
GuestABI::prepareForFunction<ABI, Ret, Args...>(tc, state);
- return GuestABI::callFrom<ABI, Ret, Args...>(tc, state, target);
+ return GuestABI::callFrom<ABI, store_ret, Ret, Args...>(tc, state, target);
}
template <typename ABI, typename Ret, typename ...Args>
Ret
+invokeSimcall(ThreadContext *tc,
+ std::function<Ret(ThreadContext *, Args...)> target)
+{
+ return invokeSimcall<ABI, true>(tc, target);
+}
+
+template <typename ABI, bool store_ret, typename Ret, typename ...Args>
+Ret
invokeSimcall(ThreadContext *tc, Ret (*target)(ThreadContext *, Args...))
{
- return invokeSimcall<ABI>(
+ return invokeSimcall<ABI, store_ret>(
tc, std::function<Ret(ThreadContext *, Args...)>(target));
}
+template <typename ABI, typename Ret, typename ...Args>
+Ret
+invokeSimcall(ThreadContext *tc, Ret (*target)(ThreadContext *, Args...))
+{
+ return invokeSimcall<ABI, true>(tc, target);
+}
+
template <typename ABI, typename ...Args>
void
invokeSimcall(ThreadContext *tc,
EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
EXPECT_EQ(tc.floatResult, DoubleRetValue + 1.0);
}
+ {
+ // Disable storing the return value in the ThreadContext.
+ ThreadContext tc;
+ int ret = invokeSimcall<TestABI_1D, false>(&tc, testIntRet);
+ EXPECT_EQ(ret, IntRetValue);
+ EXPECT_EQ(tc.intResult, tc.DefaultIntResult);
+ EXPECT_EQ(tc.floatResult, tc.DefaultFloatResult);
+ }
+
// 2D returns.
{
// With no arguments to gather, call the target function and store the
// result.
-template <typename ABI, typename Ret>
-static typename std::enable_if<!std::is_void<Ret>::value, Ret>::type
+template <typename ABI, bool store_ret, typename Ret>
+static typename std::enable_if<!std::is_void<Ret>::value && store_ret,
+ Ret>::type
callFrom(ThreadContext *tc, typename ABI::State &state,
std::function<Ret(ThreadContext *)> target)
{
return ret;
}
+template <typename ABI, bool store_ret, typename Ret>
+static typename std::enable_if<!std::is_void<Ret>::value && !store_ret,
+ Ret>::type
+callFrom(ThreadContext *tc, typename ABI::State &state,
+ std::function<Ret(ThreadContext *)> target)
+{
+ return target(tc);
+}
+
// With no arguments to gather and nothing to return, call the target function.
template <typename ABI>
static void
// Recursively gather arguments for target from tc until we get to the base
// case above.
-template <typename ABI, typename Ret, typename NextArg, typename ...Args>
+template <typename ABI, bool store_ret, typename Ret,
+ typename NextArg, typename ...Args>
static typename std::enable_if<!std::is_void<Ret>::value, Ret>::type
callFrom(ThreadContext *tc, typename ABI::State &state,
std::function<Ret(ThreadContext *, NextArg, Args...)> target)
};
// Recursively handle any remaining arguments.
- return callFrom<ABI, Ret, Args...>(tc, state, partial);
+ return callFrom<ABI, store_ret, Ret, Args...>(tc, state, partial);
}
// Recursively gather arguments for target from tc until we get to the base