Add experimental Foreign Function & Memory API support for riscv.
Code is mainly adapted from AArch64 port, and with some riscv ABI specific changes:
1. According to the riscv spec [1], when multiple floating-point precisions are supported,
then valid values of narrower n-bit types, n < FLEN, are represented in the lower n
bits of a FLEN-bit NaN value, in a process termed NaN-boxing. The upper bits of a
valid NaN-boxed value must be all 1s. We initialize all bits of the return buffer with
1s so that we could always transfer returned floating-point value from the return buffer
into register with a single fld without knowing the current type of the value.
2. When the type class is aggregate type, the ABI of riscv is more complicated [1][2]:
- Aggregates larger than 2 * XLEN bits are passed by reference
- A struct containing just one floating-point real is passed in a floating-point
argument register if it is no more than ABI_FLEN bits wide and at least one
floating-point argument register is available. A struct containing two floating-point
reals is passed in two floating-point registers, if neither real is more than ABI_FLEN
bits wide and at least two floating-point argument registers are available.
- A struct containing one floating-point real and one integer (or bitfield), in either order,
is passed in a floating-point register and an integer register, provided the floating-point
real is no more than ABI_FLEN bits wide and the integer is no more than XLEN bits wide,
and at least one floating-point argument register and at least one integer argument
register is available.
- Aggregates whose total size is no more than XLEN bits are passed in a register,
with the fields laid out as though they were passed in memory. If no register is available,
the aggregate is passed on the stack.
3. The va_list type is defined as void* on riscv [3]. In the base integer calling convention,
variadic arguments are passed in the same manner as named arguments, with one exception.
Variadic arguments with 2×XLEN-bit alignment and size at most 2×XLEN bits are passed in
an aligned register pair (i.e., the first register in the pair is even-numbered), or on the stack
by value if none is available. After a variadic argument has been passed on the stack, all future
arguments will also be passed on the stack (i.e. the last argument register may be left unused
due to the aligned register pair rule).
4. The frame layout of riscv is a bit different from AArch64. sender_sp_offset on riscv is 0 [4],
so the FP_BIAS is set to 0 on riscv.
[1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#hardware-floating-point-calling-convention
[2]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#integer-calling-convention
[3]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#va_list-va_start-and-va_arg
[4]: https://github.com/openjdk/jdk/blob/0532045edb709a995a42c07d95cb1cbabe886bed/src/hotspot/cpu/riscv/frame_riscv.hpp#L111