diff options
Diffstat (limited to 'src/sim/guest_abi.hh')
-rw-r--r-- | src/sim/guest_abi.hh | 46 |
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(); |