summaryrefslogtreecommitdiff
path: root/src/sim/guest_abi.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/guest_abi.hh')
-rw-r--r--src/sim/guest_abi.hh46
1 files changed, 46 insertions, 0 deletions
diff --git a/src/sim/guest_abi.hh b/src/sim/guest_abi.hh
index ff1464e8f..2dd27c424 100644
--- a/src/sim/guest_abi.hh
+++ b/src/sim/guest_abi.hh
@@ -74,8 +74,23 @@ struct Result
* of this method which actually does something and is public.
*/
static void store(ThreadContext *tc, const Ret &ret);
+
+ /*
+ * Adjust the position of arguments based on the return type, if necessary.
+ *
+ * This method can be excluded if no adjustment is necessary.
+ */
+ static void allocate(ThreadContext *tc, typename ABI::Position &position);
};
+/*
+ * This partial specialization prevents having to special case 'void' when
+ * working with return types.
+ */
+template <typename ABI>
+struct Result<ABI, void>
+{};
+
template <typename ABI, typename Arg, typename Enabled=void>
struct Argument
{
@@ -92,6 +107,35 @@ struct Argument
/*
+ * This struct template provides a default allocate() method in case the
+ * Result template doesn't provide one. This is the default in cases where the
+ * return type doesn't affect how arguments are laid out.
+ */
+template <typename ABI, typename Ret, typename Enabled=void>
+struct ResultAllocator
+{
+ static void
+ allocate(ThreadContext *tc, typename ABI::Position &position)
+ {}
+};
+
+/*
+ * If the return type *does* affect how the arguments are laid out, the ABI
+ * can implement an allocate() method for the various return types, and this
+ * specialization will call into it.
+ */
+template <typename ABI, typename Ret>
+struct ResultAllocator<ABI, Ret, decltype((void)&Result<ABI, Ret>::allocate)>
+{
+ static void
+ allocate(ThreadContext *tc, typename ABI::Position &position)
+ {
+ Result<ABI, Ret>::allocate(tc, position);
+ }
+};
+
+
+/*
* These templates implement a variadic argument mechanism for guest ABI
* functions. A function might be written like this:
*
@@ -364,6 +408,7 @@ invokeSimcall(ThreadContext *tc,
// Default construct a Position to track consumed resources. Built in
// types will be zero initialized.
auto position = typename ABI::Position();
+ GuestABI::ResultAllocator<ABI, Ret>::allocate(tc, position);
return GuestABI::callFrom<ABI, Ret, Args...>(tc, position, target);
}
@@ -408,6 +453,7 @@ dumpSimcall(std::string name, ThreadContext *tc,
auto position = typename ABI::Position();
std::ostringstream ss;
+ GuestABI::ResultAllocator<ABI, Ret>::allocate(tc, position);
ss << name;
GuestABI::dumpArgsFrom<ABI, Ret, Args...>(0, ss, tc, position);
return ss.str();