WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

Commit 325749b4 authored by Kunshan Wang's avatar Kunshan Wang
Browse files

WIP: basic tests

parent 43d60570
#ifndef __MUAPI_H__
#define __MUAPI_H__
#ifdef __cplusplus
extern "C" {
#include <stdint.h>
// MuValue and MuXxxValue type are opaque handles to values in the Mu type
// system.
// The actual values are held by MuCtx. MuValue opaquely refers to one such
// value. Copies of MuValue values refer to the same value. A MuValue instance
// can only be used in the MuCtx holding it.
// Values of subtypes can be cast to MuValue and back using the type cast
// expression in C, similar to casting one pointer to another.
typedef void *MuValue; // Any Mu value
typedef void *MuIntValue; // int<n>
typedef void *MuFloatValue; // float
typedef void *MuDoubleValue; // double
typedef void *MuRefValue; // ref<T>
typedef void *MuIRefValue; // iref<T>
typedef void *MuStructValue; // struct<...>
typedef void *MuArrayValue; // array<T l>
typedef void *MuVectorValue; // vector<T l>
typedef void *MuFuncRefValue; // funcref<sig>
typedef void *MuThreadRefValue; // threadref
typedef void *MuStackRefValue; // stackref
typedef void *MuFCRefValue; // framecursorref
typedef void *MuTagRef64Value; // tagref64
typedef void *MuUPtrValue; // uptr
typedef void *MuUFPValue; // ufuncptr
// Identifiers and names of Mu
typedef uint32_t MuID;
typedef char *MuName;
// Convenient types for the void* type and the void(*)() type in C
typedef void *MuCPtr;
typedef void (*MuCFP)();
// Result of a trap handler
typedef int MuTrapHandlerResult;
// Used by new_thread
typedef int MuHowToResume;
#define MU_THREAD_EXIT 0x00
#define MU_REBIND_THROW_EXC 0x02
// Declare the types here because they are used in the following signatures.
typedef struct MuVM MuVM;
typedef struct MuCtx MuCtx;
// Signature of the trap handler
typedef void (*MuTrapHandler)(MuCtx *ctx, MuThreadRefValue thread,
MuStackRefValue stack, int wpid, MuTrapHandlerResult *result,
MuStackRefValue *new_stack, MuValue *values, int *nvalues,
MuRefValue *exception,
MuCPtr userdata);
// Memory orders
typedef int MuMemOrd;
#define MU_NOT_ATOMIC 0x00
#define MU_RELAXED 0x01
#define MU_CONSUME 0x02
#define MU_ACQUIRE 0x03
#define MU_RELEASE 0x04
#define MU_ACQ_REL 0x05
#define MU_SEQ_CST 0x06
// Operations for the atomicrmw API function
typedef int MuAtomicRMWOp;
#define MU_XCHG 0x00
#define MU_ADD 0x01
#define MU_SUB 0x02
#define MU_AND 0x03
#define MU_NAND 0x04
#define MU_OR 0x05
#define MU_XOR 0x06
#define MU_MAX 0x07
#define MU_MIN 0x08
#define MU_UMAX 0x09
#define MU_UMIN 0x0A
// Calling conventions.
typedef int MuCallConv;
#define MU_DEFUALT 0x00
// Concrete Mu implementations may define more calling conventions.
// NOTE: MuVM and MuCtx are structures with many function pointers. This
// approach loosens the coupling between the client module and the Mu
// implementation. At compile time, the client does not need to link against
// any dynamic libraries. At run time, more than one Mu implementations can be
// used by the same client.
// A handle and method lists of a micro VM
struct MuVM {
void *header; // Refer to internal stuff
// Create context
MuCtx* (*new_context)(MuVM *mvm);
// Convert between IDs and names
MuID (*id_of )(MuVM *mvm, MuName name);
MuName (*name_of)(MuVM *mvm, MuID id);
// Set handlers
void (*set_trap_handler )(MuVM *mvm, MuTrapHandler trap_handler, MuCPtr userdata);
// A local context. It can only be used by one thread at a time. It holds many
// states which are typically held by a Mu thread, such as object references,
// local heap allocation pool, and an object-pinning set. It also holds many Mu
// values and expose them to the client as opaque handles (MuValue and its
// subtypes).
struct MuCtx {
void *header; // Refer to internal stuff
// Convert between IDs and names
MuID (*id_of )(MuCtx *ctx, MuName name);
MuName (*name_of)(MuCtx *ctx, MuID id);
// Close the current context, releasing all resources
void (*close_context)(MuCtx *ctx);
// Load bundles and HAIL scripts
void (*load_bundle)(MuCtx *ctx, char *buf, int sz);
void (*load_hail )(MuCtx *ctx, char *buf, int sz);
// Convert from C values to Mu values
MuIntValue (*handle_from_int8 )(MuCtx *ctx, int8_t num, int len);
MuIntValue (*handle_from_uint8 )(MuCtx *ctx, uint8_t num, int len);
MuIntValue (*handle_from_int16 )(MuCtx *ctx, int16_t num, int len);
MuIntValue (*handle_from_uint16)(MuCtx *ctx, uint16_t num, int len);
MuIntValue (*handle_from_int32 )(MuCtx *ctx, int32_t num, int len);
MuIntValue (*handle_from_uint32)(MuCtx *ctx, uint32_t num, int len);
MuIntValue (*handle_from_int64 )(MuCtx *ctx, int64_t num, int len);
MuIntValue (*handle_from_uint64)(MuCtx *ctx, uint64_t num, int len);
MuFloatValue (*handle_from_float )(MuCtx *ctx, float num);
MuDoubleValue (*handle_from_double)(MuCtx *ctx, double num);
MuUPtrValue (*handle_from_ptr )(MuCtx *ctx, MuID mu_type, MuCPtr ptr);
MuUFPValue (*handle_from_fp )(MuCtx *ctx, MuID mu_type, MuCFP fp);
// Convert from Mu values to C values
int8_t (*handle_to_sint8 )(MuCtx *ctx, MuIntValue opnd);
uint8_t (*handle_to_uint8 )(MuCtx *ctx, MuIntValue opnd);
int16_t (*handle_to_sint16)(MuCtx *ctx, MuIntValue opnd);
uint16_t (*handle_to_uint16)(MuCtx *ctx, MuIntValue opnd);
int32_t (*handle_to_sint32)(MuCtx *ctx, MuIntValue opnd);
uint32_t (*handle_to_uint32)(MuCtx *ctx, MuIntValue opnd);
int64_t (*handle_to_sint64)(MuCtx *ctx, MuIntValue opnd);
uint64_t (*handle_to_uint64)(MuCtx *ctx, MuIntValue opnd);
float (*handle_to_float )(MuCtx *ctx, MuFloatValue opnd);
double (*handle_to_double)(MuCtx *ctx, MuDoubleValue opnd);
MuCPtr (*handle_to_ptr )(MuCtx *ctx, MuUPtrValue opnd);
MuCFP (*handle_to_fp )(MuCtx *ctx, MuUFPValue opnd);
// Make MuValue instances from Mu global SSA variables
MuValue (*handle_from_const )(MuCtx *ctx, MuID id);
MuIRefValue (*handle_from_global)(MuCtx *ctx, MuID id);
MuFuncRefValue (*handle_from_func )(MuCtx *ctx, MuID id);
MuValue (*handle_from_expose)(MuCtx *ctx, MuID id);
// Delete the value held by the MuCtx, making it unusable, but freeing up
// the resource.
void (*delete_value)(MuCtx *ctx, MuValue opnd);
// Compare reference or general reference types.
// EQ. Available for ref, iref, funcref, threadref and stackref.
int (*ref_eq )(MuCtx *ctx, MuValue lhs, MuValue rhs);
// ULT. Available for iref only.
int (*ref_ult)(MuCtx *ctx, MuIRefValue lhs, MuIRefValue rhs);
// Manipulate Mu values of the struct<...> type
MuValue (*extract_value)(MuCtx *ctx, MuStructValue str, int index);
MuValue (*insert_value )(MuCtx *ctx, MuStructValue str, int index, MuValue newval);
// Manipulate Mu values of the array or vector type
// str can be MuArrayValue or MuVectorValue
MuValue (*extract_element)(MuCtx *ctx, MuValue str, MuIntValue index);
MuValue (*insert_element )(MuCtx *ctx, MuValue str, MuIntValue index, MuValue newval);
// Heap allocation
MuRefValue (*new_fixed )(MuCtx *ctx, MuID mu_type);
MuRefValue (*new_hybrid)(MuCtx *ctx, MuID mu_type, MuIntValue length);
// Change the T or sig in ref<T>, iref<T> or func<sig>
MuValue (*refcast)(MuCtx *ctx, MuValue opnd, MuID new_type);
// Memory addressing
MuIRefValue (*get_iref )(MuCtx *ctx, MuRefValue opnd);
MuIRefValue (*get_field_iref )(MuCtx *ctx, MuIRefValue opnd, int field);
MuIRefValue (*get_elem_iref )(MuCtx *ctx, MuIRefValue opnd, MuIntValue index);
MuIRefValue (*shift_iref )(MuCtx *ctx, MuIRefValue opnd, MuIntValue offset);
MuIRefValue (*get_var_part_iref )(MuCtx *ctx, MuIRefValue opnd);
// Memory accessing
MuValue (*load )(MuCtx *ctx, MuMemOrd ord, MuIRefValue loc);
void (*store )(MuCtx *ctx, MuMemOrd ord, MuIRefValue loc, MuValue newval);
MuValue (*cmpxchg )(MuCtx *ctx, MuMemOrd ord_succ, MuMemOrd ord_fail,
int weak, MuIRefValue loc, MuValue expected, MuValue desired,
int *is_succ);
MuValue (*atomicrmw)(MuCtx *ctx, MuMemOrd ord, MuAtomicRMWOp op,
MuIRefValue loc, MuValue opnd);
void (*fence )(MuCtx *ctx, MuMemOrd ord);
// Thread and stack creation and stack destruction
MuStackRefValue (*new_stack )(MuCtx *ctx, MuFuncRefValue func);
MuThreadRefValue (*new_thread)(MuCtx *ctx, MuStackRefValue stack,
MuHowToResume *htr, MuValue *vals, int nvals, MuRefValue *exc);
void (*kill_stack)(MuCtx *ctx, MuStackRefValue stack);
// Frame cursor operations
MuFCRefValue (*new_cursor )(MuCtx *ctx, MuStackRefValue stack);
void (*next_frame )(MuCtx *ctx, MuFCRefValue cursor);
MuFCRefValue (*copy_cursor )(MuCtx *ctx, MuFCRefValue cursor);
void (*close_cursor)(MuCtx *ctx, MuFCRefValue cursor);
// Stack introspection
MuID (*cur_func )(MuCtx *ctx, MuFCRefValue cursor);
MuID (*cur_func_ver )(MuCtx *ctx, MuFCRefValue cursor);
MuID (*cur_inst )(MuCtx *ctx, MuFCRefValue cursor);
void (*dump_keepalives)(MuCtx *ctx, MuFCRefValue cursor, MuValue *results);
// On-stack replacement
void (*pop_frames_to)(MuCtx *ctx, MuFCRefValue cursor);
void (*push_frame )(MuCtx *ctx, MuStackRefValue stack, MuFuncRefValue func);
// 64-bit tagged reference operations
int (*tr64_is_fp )(MuCtx *ctx, MuTagRef64Value value);
int (*tr64_is_int )(MuCtx *ctx, MuTagRef64Value value);
int (*tr64_is_ref )(MuCtx *ctx, MuTagRef64Value value);
MuDoubleValue (*tr64_to_fp )(MuCtx *ctx, MuTagRef64Value value);
MuIntValue (*tr64_to_int )(MuCtx *ctx, MuTagRef64Value value);
MuRefValue (*tr64_to_ref )(MuCtx *ctx, MuTagRef64Value value);
MuIntValue (*tr64_to_tag )(MuCtx *ctx, MuTagRef64Value value);
MuTagRef64Value (*tr64_from_fp )(MuCtx *ctx, MuDoubleValue value);
MuTagRef64Value (*tr64_from_int)(MuCtx *ctx, MuIntValue value);
MuTagRef64Value (*tr64_from_ref)(MuCtx *ctx, MuRefValue ref, MuIntValue tag);
// Watchpoint operations
void (*enable_watchpoint )(MuCtx *ctx, int wpid);
void (*disable_watchpoint)(MuCtx *ctx, int wpid);
// Mu memory pinning, usually object pinning
MuUPtrValue (*pin )(MuCtx *ctx, MuValue loc); // loc is either MuRefValue or MuIRefValue
void (*unpin)(MuCtx *ctx, MuValue loc); // loc is either MuRefValue or MuIRefValue
// Expose Mu functions as native callable things, usually function pointers
MuValue (*expose )(MuCtx *ctx, MuFuncRefValue func, MuCallConv call_conv, MuIntValue cookie);
void (*unexpose)(MuCtx *ctx, MuCallConv call_conv, MuValue value);
#ifdef __cplusplus
#endif // __MUAPI_H__
......@@ -249,4 +249,12 @@ object NativeClientSupport {
* alive so that the native program can access them.
val stringPool = HashMap[String, Pointer]()
// Expose and unexpose objects
def exposeMicroVM(microVM: MicroVM): Word = microVMs.add(microVM).address()
def exposeMuCtx(muCtx: MuCtx): Word = muCtxs.add(muCtx).address()
def exposeMuValue(muValue: MuValue): Word = muValues.add(muValue).address()
def unexposeMicroVM(addr: Long): Unit = microVMs.remove(jnrMemoryManager.newPointer(addr))
def unexposeMuCtx(addr: Long): Unit = muCtxs.remove(jnrMemoryManager.newPointer(addr))
def unexposeMuValue(addr: Long): Unit = muValues.remove(jnrMemoryManager.newPointer(addr))
\ No newline at end of file
package uvm.refimpl.nat
import scala.reflect.runtime.universe
import ch.qos.logback.classic.Level._
import uvm.refimpl.UvmBundleTesterBase
import jnr.ffi.LibraryLoader
import PlatformConstants._
import NativeSupport._
import org.scalatest.FlatSpec
import org.scalatest.Matchers
class NativeClientSupportTest extends UvmBundleTesterBase {
"uvm.refimpl.nat" -> DEBUG)
val fileName = "./tests/c-snippets/ncs_tests.so"
if (!new java.io.File(fileName).isFile()) {
throw new RuntimeException("Need to compile the ncs_tests.so library. cd into tests/c-snippets and invoke 'make'.")
trait NcsTestsLib {
def test_basic(mvm: Word): Unit
val ncs_tests = LibraryLoader.create(classOf[NcsTestsLib]).load(fileName)
class NativeClientSupportTest extends FlatSpec with Matchers {
"The ClientAccessibleClassExposer" should "enumerate declared methods" in {
val cace = new ClientAccessibleClassExposer(NativeMuVM)
val microVMAddr = NativeClientSupport.exposeMicroVM(microVM)
val funcTable = cace.makeFuncTable(microVMAddr)
val funcTablePtr = NativeClientSupport.funcTableToPointer(funcTable)
val header = funcTablePtr.getAddress(0)
val mvm =NativeClientSupport.microVMs.get(jnrMemoryManager.newPointer(header))
mvm shouldBe microVM
\ No newline at end of file
all: structtest.so callbacktest.so
MU_INCLUDE = ../../cinclude
.PHONY: all
all: structtest.so callbacktest.so ncs_tests.so
structtest.so: structtest.c
cc -fPIC -shared -o structtest.so structtest.c
callbacktest.so: callbacktest.c
cc -fPIC -shared -o callbacktest.so callbacktest.c
ncs_tests.so: ncs_tests.c
cc -fPIC -shared -I $(MU_INCLUDE) -o ncs_tests.so ncs_tests.c
#include <stdio.h>
#include <muapi.h>
void test_basic(MuVM *mvm) {
printf("[C] header: %p\n", mvm->header);
printf("[C] new_context: %p\n", mvm->new_context);
printf("[C] id_of: %p\n", mvm->id_of);
printf("[C] name_of: %p\n", mvm->name_of);
printf("[C] set_trap_handler: %p\n", mvm->set_trap_handler);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment