Commit 5fd41775 authored by Kunshan Wang's avatar Kunshan Wang

Support for symbols, relocs and primordial threads.

- The make_boot_image method is moved to MuCtx because it needs to refer
  to memory locations using handles of IRef types.

- Let global cells be always pinned, and added the get_addr API/CommInst
  to get their addresses.
parent c1d90055
This diff is collapsed.
===================
Boot-image Building
Boot Image Building
===================
Mu provides an interface to build "boot images". A boot image is a file that
......@@ -42,7 +42,35 @@ initialised when they start:
files into different regions of the address space of the process, and fixes
relocation entries.
A good language runtime must start-up fast. Thus it is not practical to use the
- **inter-references by untraced pointers**: In addition to calling foreign
functions, language runtimes may also need to create global variables of
struct types which contain pointers to global variables or functions defined
in native modules. Symbol resolution is not a problem for JIT (``dlsym`` will
work), but when creating boot images, the actual addresses of these fields can
only be resolved at load time.
Take the following C program as example::
struct Foo {
int bar;
int (*some_func_ptr)(char*);
};
struct Foo my_foo = { 42, puts };
At load time, the ``my_foo.some_func_ptr`` field is initialised to the
address of the ``puts`` function in libc. But the address is different each
time the program runs. So relocation entries need to be placed at the
``my_foo.some_func_ptr`` field so that the dynamic linker can fill in its
value at load time.
There is a pure client-side solution: (1) record such fields at compile time
as a list of IRefs in the boot image, then (2) resolve the symbols manually
(using ``dlsym``, the ``EXTERN`` Mu constants, or calculating the address of
Mu object fields from IRefs) at load time, and (3) assign them to the fields.
But this approach cannot make use of the system dynamic linker.
A good language runtime must start up fast. Thus it is not practical to use the
JIT compiler to compile all of the standard library functions at start-up time,
but the boot image builder should AoT compile the initial Mu IR bundle into
machine code, and simply memory-map the machine code into the memory. The same
......@@ -51,22 +79,29 @@ into the heap. It should also make use of system utilities (such as the dynamic
linker/loader) to load external libraries and resolve external symbols, thus
metadata should be provided.
Mu IR and API
Mu IR Changes
=============
Several extensions has been added to the Mu IR and the API to support boot image
building.
The IR can define `external constants <ir.rst#external-constructor>`__. They are
resolved in an implementation-specific manner when the bundle is loaded.
resolved in an implementation-specific manner when the bundle is loaded. The API
function `new_const_extern <irbuilder.rst#new-const-extern>`__ creates external
constants programmatically.
Global cells are permanently pinned. The new ``get_addr`` `API
<api.rst#get-addr>`__/`CommInst <common-insts.rst#get-addr>`__ gets the address
of already pinned memory locations, including global cells.
Two API functions are added:
Mu API Changes
==============
- `new_const_extern <irbuilder.rst#new-const-extern>`__ creates the external
constants programmatically.
The `MuCtx.make_boot_image <api.rst#make-boot-image>`__ will create the boot
image. Basically, it specifies what's in the boot image by a white-list of
top-level definitions, and saves all things reachable from them. It also lets
the client specify a list of memory locations in global cells where symbols will
be placed, and a list of memory locations in global cells and heap objects which
will be filled with the address of other symbols at load time.
- `make_boot_image <api.rst#make-boot-image>`__ creates the boot image. It takes
a white-list of top-level definitions and writes its transitive closure (over
both IR nodes, heap objects and global cells) into a file.
It also lets the client specify the initial state of a primordial thread which
can be the entry point of pure Mu IR programs.
.. vim: tw=80
......@@ -288,6 +288,8 @@ Native Interface
.. _pinning:
.. _get-addr:
Object pinning
--------------
......@@ -295,6 +297,7 @@ Object pinning
[0x240]@uvm.native.pin <T> (%opnd: T) -> uptr<U>
[0x241]@uvm.native.unpin <T> (%opnd: T)
[0x242]@uvm.native.get_addr <T> (%opnd: T) -> uptr<U>
*T* must be ``ref<U>`` or ``iref<U>`` for some U.
......@@ -308,12 +311,16 @@ Object pinning
multiset of the current thread. It has undefined behaviour if no such an
instance exists.
- ``get_addr`` gets the address of a memory location ``%opnd`` which must
already be pinned with respect to the current thread. This include all global
cells and other memory locations in the pinning set of the current thread.
Mu function exposing
--------------------
::
[0x242]@uvm.native.expose [callconv] <[sig]> (%func: funcref<sig>, %cookie: int<64>) -> U
[0x243]@uvm.native.expose [callconv] <[sig]> (%func: funcref<sig>, %cookie: int<64>) -> U
*callconv* is a platform-specific calling convention flag. *U* is determined by
the calling convention and *sig*.
......@@ -329,7 +336,7 @@ convention *callConv* with cookie *cookie*.
::
[0x243]@uvm.native.unexpose [callconv] (%value: U)
[0x244]@uvm.native.unexpose [callconv] (%value: U)
*callconv* is a platform-specific calling convention flag. *U* is determined by
the calling convention.
......@@ -338,7 +345,7 @@ the calling convention.
::
[0x244]@uvm.native.get_cookie () -> int<64>
[0x245]@uvm.native.get_cookie () -> int<64>
If a Mu function is called via its exposed value, this instruction returns the
attached cookie. Otherwise it returns an arbitrary value.
......
......@@ -727,7 +727,8 @@ memory allocation unit in the *global memory*. See `<memory.rst>`__ for more
information about the global memory.
NOTE: The global memory is the counterpart of static or global variables in
C/C++.
C/C++. In Mu, global cells are also permanently pinned so that it can be
used to interact with native programs.
A global cell definition has the form::
......
......@@ -142,8 +142,10 @@ overlapping regions in the address space.
* Mu forces the 2's complement representation, though the byte order and
alignment requirement are implementation-defined.
See `Native Interface <native-interface.rst>`__ for details about the pinning and
unpinning operations.
Global cells are always pinned. Other Mu memory locations can be pinned by
adding to the pinning set of any Mu thread (see `Native Interface
<native-interface.rst>`__ for details about the pinning and unpinning operations
which modifies the pinning set).
Memory Allocation and Deallocation
==================================
......
......@@ -264,11 +264,6 @@ struct MuVM {
// Set handlers
void (*set_trap_handler)(MuVM *mvm, MuTrapHandler trap_handler, MuCPtr userdata);
// Build boot image
void (*make_boot_image)(MuVM *mvm,
MuID* whitelist, MuArraySize whitelist_sz,
MuCString output_file); /// MUAPIPARSER whitelist:array:whitelist_sz
};
// A local context. It can only be used by one thread at a time. It holds many
......@@ -417,7 +412,8 @@ struct MuCtx {
// 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
void (*unpin )(MuCtx *ctx, MuValue loc); // loc is either MuRefValue or MuIRefValue
MuUPtrValue (*get_addr)(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);
......@@ -425,6 +421,15 @@ struct MuCtx {
// Create an IR builder and start building.
MuIRBuilder* (*new_ir_builder)(MuCtx *ctx);
// Build boot image
void (*make_boot_image)(MuVM *mvm,
MuID* whitelist, MuArraySize whitelist_sz,
MuIRefValue *sym_fields, MuCString *sym_strings, MuArraySize nsyms,
MuIRefValue *reloc_fields, MuCString *reloc_strings, MuArraySize nrelocs,
MuFuncRefValue primordial_func, MuStackRefValue primordial_stack,
MuRefValue primordial_threadlocal,
MuCString output_file); /// MUAPIPARSER whitelist:array:whitelist_sz;sym_fields:array:nsyms;sym_strings:array:nsyms;reloc_fields:array:nrelocs;reloc_strings:array:nrelocs;primordial_func:optional;primordial_stack:optional;primordial_threadlocal:optional
};
// These types are all aliases of MuID. They are provided to guide C
......
......@@ -184,6 +184,8 @@ conventions, the native function may be represented in different ways, and the
arguments are passed in different ways. The return value of the call will be the
return value of the ``CCALL`` instruction, which is a Mu SSA variable.
.. _exposed-function:
Native Functions Calling Mu Functions
-------------------------------------
......
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