Skip to content
This repository has been archived by the owner on Aug 2, 2019. It is now read-only.

Metacircular Client Interface #36

Open
wks opened this issue Jun 23, 2015 · 1 comment
Open

Metacircular Client Interface #36

wks opened this issue Jun 23, 2015 · 1 comment

Comments

@wks
Copy link
Member

wks commented Jun 23, 2015

It has been proposed long ago that "everything the API can do should also be possible in the Mu IR".

This issue maintains a checklist of features not in the Mu IR. These functions should be gradually added to the IR.

Features in the API but not the IR:

  • bundle loading
  • stack introspection: current_func_ver, current_instruction, dump_keepalives
  • OSR: pop_frame, push_frame
  • Handle traps and undefined functions in Mu IR. It depends on how the Mu VM itself is implemented.
  • Handle watchpoint in Mu IR: an instruction which is a no-op when disabled, but a (maybe limited kind of) Mu function call when enabled.

Things that can be done dynamically via handles in the API, but can only be done statically in the IR. I am not sure how dynamic Mu should be, or need to be, because some of the items below can be worked around with some Mu IR code, such as maintaining a hash table implemented in Mu IR, or writing wrapper functions.

  • Opaque handle type: a handle that holds any Mu value. ref<T> can be a candidate for this purpose.
  • Getting a Mu constant value (including constants, globals and functions) by its ID. This is a kind of introspection.
    • This can be done with a type argument: %c = GET_CONST <@T> %id, %c is a @T
    • Or return a handle: %ch = GET_CONST_H %id, %ch is a ref<void>
  • Creating Mu heap objects by a type ID.
  • Calling a Mu function (or constructing a Mu frame) with both the callee and the arguments as handles. This allows calling a Mu function with a run-time-determined arity and arg types.
  • Dump keepalive variables.
    • This can be done with a type argument: %sixth_ka = GET_KEEPALIVE <@T> %frame 6
    • or return handle: %sixth_ka_handle = GET_KEEPALIVE_H %frame 6
@wks
Copy link
Member Author

wks commented Jun 23, 2015

Working around some dynamism

Getting a Mu constant/global/function/expFunc by ID: maintain a HashMap<int, Callable<Object>>. For every constant ID, the Callable returns a boxed value that contains that constant. Or maintain a HashMap<int,Object> where each constant is pre-boxed and prepared for dynamic getting.

Extract value/insert value using a boxed value (handle) and a dynamically-supplied index; Creating a Mu heap object by type ID; Memory addressing/accessing via dynamic types, boxed values and dynamic indices; Pinning a ref/iref held in boxed values: Use dynamic dispatching. Either map the argument types (inside the boxed value) to accessor functions, or use SWITCH, or use virtual tables.

Calling a Mu function with a dynamic callee and a dynamic list of arguments (of run-time-known lengths and types): This is a bit tricky.

For a Mu function whose signature is @retty (@paramty1 @paramty2 ... @paramtyn), make a wrapper Mu function whose signature is ref<void> (hybrid<int<64> ref<void>>), i.e. the only parameter is a hybrid, with an int<64> as the fixed part which encodes the length of the variable part. Each element in the variable part is a ref<void>, which can refer to an object of arbitrary type. The return type is a boxed type, too. The actual implementation of this wrapper function may be:

// for simplicity, this function is written in Java
RetTy actualFunc(ParamTy1 param1, ParamTy2 param2, ..., ParamTyn paramn) { ... }

Object wrapper(Object[] args) {
    if (args.length != n) undefinedBehaviour();

    ParamTy1 arg1 = ((Ref<ParamTy1>)args[0]).load();
    ParamTy2 arg2 = ((Ref<ParamTy2>)args[1]).load();
    ...
    ParamTyn argn = ((Ref<ParamTyn>)args[n]).load();

    RetTy rv = actualFunc(arg1, arg2, ..., argn);

    return new Ref<RetTy>(rv);
}

When making a dynamic call, a list of actual arguments is supplied to the wrapper. The arity and the types are checked (if necessary) in the wrapper function.

A HashMap<int, WrapperFunction> is maintained to map each function ID to its wrapper, so that the callee itself can be dynamic.

dump keepalive variables without a type argument: For each trap ID, create a function which dumps all keep-alive variables and boxes all of them into a list.

In conclusion, the IR does not need to be dynamic. The client can always implement its own dynamism.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant