...
 
Commits (200)
......@@ -10,3 +10,6 @@ target
.d8_history
hs_err_pid*.log
/bin/
*.py[co]
classpath.txt
build.properties
language: scala
scala:
- 2.11.8
jdk:
- oraclejdk8
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-6
script:
- pushd tests/c-snippets && make CC=gcc-6 && popd
- sbt compile
- sbt test
# vim: ts=2 sw=2 sts=2
This diff is collapsed.
enablePlugins(Antlr4Plugin)
lazy val genSrc = taskKey[List[File]]("generate sources")
genSrc <<= (sourceGenerators in Compile) { _.join.map(_.flatten.toList) }
genSrc := (sourceGenerators in Compile) { _.join.map(_.flatten.toList) }.value
organization := "org.microvm"
lazy val makeClasspathFile = taskKey[Unit]("write the run-time classpath to target/jars.txt as colon-separated list")
name := "microvm-refimpl2"
lazy val root = (project in file(".")).
settings(
organization := "org.microvm",
version := "2.1.0"
name := "mu-impl-ref2",
description := "The second reference implementation of Mu, the micro virtual machine"
version := "2.2.0",
licenses := Seq("CC BY-SA 4.0" -> url("https://creativecommons.org/licenses/by-sa/4.0/legalcode"))
description := "The second reference implementation of Mu, the micro virtual machine",
scalaVersion := "2.11.7"
licenses := Seq("CC BY-SA 4.0" -> url("https://creativecommons.org/licenses/by-sa/4.0/legalcode")),
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % "2.11.7",
"org.antlr" % "antlr4" % "4.5.1-1",
"com.typesafe.scala-logging" %% "scala-logging" % "3.1.0",
"ch.qos.logback" % "logback-classic" % "1.1.3",
"com.github.jnr" % "jnr-ffi" % "2.0.7",
"com.github.jnr" % "jffi" % "1.2.10",
"com.github.jnr" % "jnr-posix" % "3.0.23",
"org.scalatest" %% "scalatest" % "2.2.4" % "test",
"junit" % "junit" % "4.12" % "test"
)
scalaVersion := "2.12.6",
testOptions in Test += Tests.Argument("-oF") // print full stack trace when testing
libraryDependencies ++= Seq(
"org.antlr" % "antlr4" % "4.7.1",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.0",
"ch.qos.logback" % "logback-classic" % "1.2.3",
"com.github.jnr" % "jnr-ffi" % "2.1.7",
"com.github.jnr" % "jffi" % "1.2.16" classifier "native",
"com.github.jnr" % "jnr-posix" % "3.0.44",
"org.scalatest" %% "scalatest" % "3.0.5" % "test",
"junit" % "junit" % "4.12" % "test"
),
antlr4Settings
scalacOptions += "-language:implicitConversions",
antlr4PackageName in Antlr4 := Some("uvm.ir.textinput.gen")
testOptions in Test += Tests.Argument("-oF"), // print full stack trace when testing
antlr4GenListener in Antlr4 := false
parallelExecution in Test := false, // disable parallel tests because the refimpl2 is not thread-safe
antlr4GenVisitor in Antlr4 := false
antlr4PackageName in Antlr4 := Some("uvm.ir.textinput.gen"),
lazy val makeClasspathFile = taskKey[Unit]("write the run-time classpath to target/jars.txt as colon-separated list")
antlr4GenListener in Antlr4 := false,
antlr4GenVisitor in Antlr4 := false,
antlr4Version in Antlr4 := "4.7.1",
makeClasspathFile := {
val cp = (fullClasspath in Runtime).value.files
makeClasspathFile := {
val cp = (fullClasspath in Runtime).value.files
println("fullClasspath: \n" + cp.mkString("\n"))
println("fullClasspath: \n" + cp.mkString("\n"))
val cpStr = cp.mkString(":")
val cpStr = cp.mkString(":")
IO.write(new java.io.File("cbinding/classpath.txt"), cpStr)
}
IO.write(new java.io.File("classpath.txt"), cpStr)
}
)
*.so
*.dylib
test_client
test_client2
classpath.txt
classpath.h
test_client2_bootimg.mu
*.dSYM
CFLAGS += -std=gnu11
ifndef JAVA_HOME
$(error JAVA_HOME is required. Invoke with 'make JAVA_HOME=/path/to/java/home')
endif
CFLAGS += -I $(JAVA_HOME)/include
unamem := $(shell uname -m)
ifeq ($(unamem),x86_64)
JDKARCH := amd64
else ifeq ($(unamem),aarch64)
JDKARCH := aarch64
else
$(error Unsupported architecture: $(unamem))
endif
CFLAGS += -std=gnu11 -g -I $(JAVA_HOME)/include
ifndef OS
uname := $(shell uname)
ifeq ($(uname),Darwin)
OS = OSX
ifeq ($(uname),Darwin)
OS = OSX
else ifeq ($(uname),Linux)
OS = LINUX
else
ifeq ($(uname),Linux)
OS = LINUX
else
$(error Unrecognized operating system $(uname). I currently only worked on OSX and Linux.)
endif
$(error Unrecognized operating system $(uname). I currently only worked on OSX and Linux.)
endif
endif
ifeq ($(OS),OSX)
CFLAGS += -I $(JAVA_HOME)/include/darwin
LDFLAGS += -L $(JAVA_HOME)/jre/lib/server -l jvm -rpath $(JAVA_HOME)/jre/lib/server -install_name '@rpath/libmurefimpl2start.so'
endif
ifeq ($(OS),LINUX)
CFLAGS += -I $(JAVA_HOME)/include/linux
LDFLAGS += -Wl,--no-as-needed -L $(JAVA_HOME)/jre/lib/amd64/server -l jvm -Wl,-rpath,$(JAVA_HOME)/jre/lib/amd64/server
CFLAGS += -I $(JAVA_HOME)/include/darwin
LDFLAGS += -L $(JAVA_HOME)/lib/jli -l jli -rpath $(JAVA_HOME)/lib/jli -install_name '@rpath/libmurefimpl2start.so'
else ifeq ($(OS),LINUX)
CFLAGS += -I $(JAVA_HOME)/include/linux
LDFLAGS += -Wl,--no-as-needed -L $(JAVA_HOME)/jre/lib/$(JDKARCH)/server -l jvm -Wl,-rpath,$(JAVA_HOME)/jre/lib/$(JDKARCH)/server
endif
.PHONY: all
all: libs tests
ifeq ($(OS),OSX)
.PHONY: libs
libs: libmurefimpl2start.so libmurefimpl2start.dylib
else
.PHONY: libs
libs: libmurefimpl2start.so
endif
libmurefimpl2start.so: refimpl2-start.c classpath.h
$(CC) -fPIC -shared $(CFLAGS) -o $@ $< $(LDFLAGS)
classpath.txt: ../build.sbt
libmurefimpl2start.dylib:
ln -s libmurefimpl2start.so libmurefimpl2start.dylib
../classpath.txt: ../build.sbt
cd .. ; sbt makeClasspathFile
classpath.h: classpath.txt
xxd -i classpath.txt > classpath.h
classpath.h: ../classpath.txt
cp ../classpath.txt ./
xxd -i classpath.txt ./classpath.h
.PHONY: tests
tests: test_client
tests: test_client test_client2
test_client: test_client.c libmurefimpl2start.so
$(CC) `./refimpl2-config --istart --cflags --libs` -o $@ $<
.PHONY: clean veryclean
test_client2: test_client2.c libmurefimpl2start.so
$(CC) `./refimpl2-config --istart --cflags --libs` -o $@ $<
.PHONY: clean veryclean
clean:
rm *.so test_client
rm -f *.so test_client test_client2 *.dylib
veryclean:
rm *.so test_client classpath.txt classpath.h
veryclean: clean
rm -f classpath.txt classpath.h ../classpath.txt
......@@ -36,7 +36,8 @@ The `libmurefimpl2start.so` library contains functions (defined in
`refimpl2-start.h`) that starts the JVM and create the Mu instance for you.
Your client invokes the `mu_refimpl2_new()` function which returns a `MuVM*`.
After using, call `mu_refimpl2_close` to close it. The `mu_refimpl2_new_ex`
function provides more options.
function provides more options (see [../README.md](../README.md) for a complete
list of options).
Use the `refimpl2-config` script with the `--istart` flag to indicate your
program will create the Mu reference implementation instance. Such clients need
......@@ -83,6 +84,22 @@ cc `/path/to/refimpl2-config --cflags` -fPIC -shared -o libmyclient.so my_client
The `MuVM` struct has an extra non-standard function `execute()`. See
[../README.md](../README.md) for more details.
## Notes for Mac OS X
You need to download the JDK from Oracle, preferably JDK 8. Set `JAVA_HOME` to
the output of `/usr/libexec/java_home`, or wherever your preferred JRE is. The
following command should work:
```bash
export JAVA_HOME=$(/usr/libexec/java_home)
```
When you upgraded the OS X operating system, and you run `test_client`, it may
complain "No Java runtime present, requesting install" and "To use the java
command-line tool you need to install a JDK". Do what it says. Click the "More
Info..." button and install the legacy Java 6 from Apple. Your `test_client`
will still use your chosen JRE.
<!--
vim: tw=80
-->
This diff is collapsed.
......@@ -36,8 +36,4 @@ if '--istart' in args:
whereami, whereami), end="")
else:
if '--cflags' in args:
print("-I {} ".format(whereami), end="")
if '--libs' in args:
pass
print("-I {} ".format(whereami), end="")
\ No newline at end of file
......@@ -4,6 +4,10 @@
#include <jni.h>
#ifndef MUREF_JNI_VERSION
#define MUREF_JNI_VERSION JNI_VERSION_1_6
#endif // MUREF_JNI_VERSION
#include "refimpl2-start.h"
#include "classpath.h"
......@@ -30,19 +34,21 @@ static void init_jvm() {
JavaVMInitArgs vm_args;
JavaVMOption options[1];
JavaVMOption options[2];
char *cpoptionstr = (char*)calloc(classpath_txt_len + 100, 1);
strcat(cpoptionstr, "-Djava.class.path=");
strncat(cpoptionstr, (const char*)classpath_txt, classpath_txt_len);
options[0].optionString = cpoptionstr;
options[1].optionString = "-Xmx4096M";
if (refimpl2_start_debug) {
printf("Classpath option: '%s'\n", cpoptionstr);
}
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
vm_args.version = MUREF_JNI_VERSION;
vm_args.nOptions = 2;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_FALSE;
......@@ -68,7 +74,7 @@ static void init_jvm() {
exit(1);
}
new_ex_mid = (*env)->GetStaticMethodID(env, cinitiater_cls, new_ex_method, "(JJJ)J");
new_ex_mid = (*env)->GetStaticMethodID(env, cinitiater_cls, new_ex_method, "(Ljava/lang/String;)J");
if (new_ex_mid == NULL) {
printf("ERROR: method %s cannot be found.\n", new_ex_method);
......@@ -94,13 +100,22 @@ MuVM *mu_refimpl2_new() {
return (MuVM*)rv;
}
MuVM *mu_refimpl2_new_ex(int64_t heap_size, int64_t global_size, int64_t stack_size) {
MuVM *mu_refimpl2_new_ex(const char *gc_conf) {
if (jvm == NULL) {
init_jvm();
}
jstring conf_str = (*env)->NewStringUTF(env, gc_conf);
if (conf_str == NULL) {
printf("ERROR: Cannot convert gc_conf to Java String\n");
exit(1);
}
uintptr_t rv = (*env)->CallStaticLongMethod(env, cinitiater_cls, new_ex_mid,
heap_size, global_size, stack_size);
conf_str);
(*env)->DeleteLocalRef(env, conf_str);
return (MuVM*)rv;
}
......
......@@ -10,7 +10,7 @@ extern "C" {
#endif
MuVM *mu_refimpl2_new();
MuVM *mu_refimpl2_new_ex(int64_t heap_size, int64_t global_size, int64_t stack_size);
MuVM *mu_refimpl2_new_ex(const char *gc_conf);
void mu_refimpl2_close(MuVM *mvm);
......
......@@ -7,11 +7,22 @@
#include <refimpl2-start.h>
#include <muapi.h>
char *hw_string = "Hello world!\n";
const char *hw_string = "Hello world!\n";
const char *hw2_string = "Goodbye world!\n";
const char *gc_conf =
"vmLog=DEBUG\n"
"sosSize=524288\n"
"losSize=524288\n"
"globalSize=1048576\n"
"stackSize=32768\n"
;
int main() {
MuVM *mvm = mu_refimpl2_new_ex(1048576, 1048576, 32768);
printf("Creating micro VM...\n");
MuVM *mvm = mu_refimpl2_new_ex(gc_conf);
printf("Creating client context...\n");
MuCtx *ctx = mvm->new_context(mvm);
char *bundle1 =
......@@ -22,6 +33,8 @@ int main() {
".funcsig @write.sig = (@cint @cvoidptr @csize_t) -> (@csize_t)\n"
".typedef @write.fp = ufuncptr<@write.sig>\n"
".const @the_fd <@cint> = 1\n"
".typedef @i64 = int<64>\n"
".const @print_stat_point <@i64> = 92\n"
;
char bundle2[256];
......@@ -29,13 +42,16 @@ int main() {
".const @the_write <@write.fp> = 0x%lx\n"
".const @the_string <@cvoidptr> = 0x%lx\n"
".const @the_length <@csize_t> = 0x%lx\n"
, (uintptr_t)write, (uintptr_t)hw_string, (unsigned long)strlen(hw_string));
".const @the_length2 <@csize_t> = 0x%lx\n"
, (uintptr_t)write, (uintptr_t)hw_string,
(unsigned long)strlen(hw_string), (unsigned long)strlen(hw2_string));
char *bundle3 =
".funcsig @v_v = ()->()\n"
".funcdef @hw VERSION %1 <@v_v> {\n"
" %entry():\n"
" %rv = CCALL #DEFAULT <@write.fp @write.sig> @the_write (@the_fd @the_string @the_length)\n"
" COMMINST @uvm.ext.print_stats (@print_stat_point)\n"
" COMMINST @uvm.thread_exit\n"
"}\n"
;
......@@ -53,11 +69,44 @@ int main() {
MuFuncRefValue func = ctx->handle_from_func(ctx, ctx->id_of(ctx, "@hw"));
MuStackRefValue stack = ctx->new_stack(ctx, func);
MuThreadRefValue thread = ctx->new_thread(ctx, stack, MU_REBIND_PASS_VALUES,
NULL, 0, NULL);
MuThreadRefValue thread = ctx->new_thread_nor(ctx, stack, NULL, NULL, 0);
mvm->execute(mvm);
char *bundle4 =
".typedef @cchar = int<8>\n"
".typedef @charhybrid = hybrid<@cchar>\n"
".typedef @refvoid = ref<@void>\n"
".funcdef @hw2 VERSION %1 <@v_v> {\n"
" %entry():\n"
" COMMINST @uvm.ext.clear_stats\n"
" %tl = COMMINST @uvm.get_threadlocal\n"
" %p = COMMINST @uvm.native.pin <@refvoid> (%tl)\n"
" %rv = CCALL #DEFAULT <@write.fp @write.sig> @the_write (@the_fd %p @the_length2)\n"
" COMMINST @uvm.native.unpin <@refvoid> (%tl)\n"
" COMMINST @uvm.thread_exit\n"
"}\n"
;
printf("Loading additional bundle...\n");
ctx->load_bundle(ctx, bundle4, strlen(bundle4));
printf("Bundle loaded. Create a thread-local string object...\n");
MuIntValue hlen = ctx->handle_from_sint32(ctx, 256, 32);
MuRefValue hobj = ctx->new_hybrid(ctx, ctx->id_of(ctx, "@charhybrid"), hlen);
MuUPtrValue hpobj = ctx->pin(ctx, hobj);
char *mustrbuf = (char*)ctx->handle_to_ptr(ctx, hpobj);
strcpy(mustrbuf, hw2_string);
ctx->unpin(ctx, hobj);
printf("Object populated. Create thread with threadlocal and execute...\n");
MuFuncRefValue func2 = ctx->handle_from_func(ctx, ctx->id_of(ctx, "@hw2"));
MuStackRefValue stack2 = ctx->new_stack(ctx, func2);
MuThreadRefValue thread2 = ctx->new_thread_nor(ctx, stack2, hobj, NULL, 0);
mvm->execute(mvm);
mu_refimpl2_close(mvm);
return 0;
......
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h> // write
#include <refimpl2-start.h>
#include <muapi.h>
const char *hw_string =
"**************\n"
"*Hello world!*\n"
"**************\n";
const char *gc_conf =
"sosSize=524288\n"
"losSize=524288\n"
"globalSize=1048576\n"
"stackSize=32768\n"
"vmLog=DEBUG\n"
;
char *boot_image_name = "test_client2_bootimg.mu";
int *muerrno;
#define MUCHECKERR() do { if(*muerrno) { \
fprintf(stderr, "Line %d: Error thrown in Mu. Stop. **muerrno: %d\n", \
__LINE__, *muerrno); \
exit(1); \
}} while(0)
#define SYM(i) MuID i = b->gen_sym(b, "@" #i)
// Some wrappers for making comminsts.
void make_pin(MuIRBuilder *b, MuID id, MuID result_id,
MuTypeNode ty, MuVarNode ref) {
MuID results[] = { result_id };
MuID type_args[] = { ty };
MuID value_args[] = { ref };
b->new_comminst(b, id, results, 1,
MU_CI_UVM_NATIVE_PIN,
NULL, 0, type_args, 1,
NULL, 0, value_args, 1,
MU_NO_ID, MU_NO_ID);
}
void make_unpin(MuIRBuilder *b, MuID id,
MuTypeNode ty, MuVarNode ref) {
MuID type_args[] = { ty };
MuID value_args[] = { ref };
b->new_comminst(b, id, NULL, 0,
MU_CI_UVM_NATIVE_UNPIN,
NULL, 0, type_args, 1,
NULL, 0, value_args, 1,
MU_NO_ID, MU_NO_ID);
}
int main(int argc, char** argv) {
MuVM *mvm = mu_refimpl2_new_ex(gc_conf);
muerrno = mvm->get_mu_error_ptr(mvm);
MuCtx *ctx = mvm->new_context(mvm);
MUCHECKERR();
MuIRBuilder *b = ctx->new_ir_builder(ctx);
// primitive types
MuID i1 = b->gen_sym(b, "@i1"); // The raw form
SYM(i8); // My convenient macro :)
SYM(i32);
SYM(i64);
SYM(pi8);
SYM(ppi8);
// typedef uint8_t i8;
// ...
b->new_type_int(b, i1, 1);
b->new_type_int(b, i8, 8);
b->new_type_int(b, i32, 32);
b->new_type_int(b, i64, 64);
b->new_type_uptr(b, pi8, i8);
b->new_type_uptr(b, ppi8, pi8);
// typedef struct { i8 var_part[]; } string_t;
// typedef ref<string_t> string_r;
SYM(string_t);
SYM(string_r);
b->new_type_hybrid(b, string_t, NULL, 0, i8);
b->new_type_ref(b, string_r, string_t);
// static string_r hw_string;
SYM(g_hello_world);
b->new_global_cell(b, g_hello_world, string_r);
// signature for the main function
// typedef void (main_sig)(i32, ppi8);
SYM(main_sig);
MuTypeNode main_paramtys[] = { i32, ppi8 };
b->new_funcsig(b, main_sig, main_paramtys, 2, NULL, 0);
// signature and ufuncptr for the write function
// typedef void *pvoid;
SYM(muvoid);
SYM(pvoid);
b->new_type_void(b, muvoid);
b->new_type_uptr(b, pvoid, muvoid);
// typedef i64 (*write_fp)(i32, pvoid, i64);
SYM(write_sig);
SYM(write_fp);
MuTypeNode write_paramtys[] = { i32, pvoid, i64 };
MuTypeNode write_rettys[] = { i64 };
b->new_funcsig(b, write_sig, write_paramtys, 3, write_rettys, 1);
b->new_type_ufuncptr(b, write_fp, write_sig);
// static write_fp const_fp_write = (uintptr_t)write;
SYM(const_fp_write);
b->new_const_extern(b, const_fp_write, write_fp, "write"); // external linkage
// the exit state of the Mu function. It cannot directly return to C.
SYM(exit_status);
b->new_global_cell(b, exit_status, i32);
// the main function
SYM(main_func);
b->new_func(b, main_func, main_sig);
// the main function body
// void entry(i32 p_argc, ppi8 p_argv) {
SYM(p_argc);
SYM(p_argv);
// args to write. fd=1, sz=size of hw_string
// const i32 const_i32_1 = 1;
// const i64 const_i64_hwsz = strlen(hw_string)+1;
SYM(const_i32_1);
SYM(const_i64_hwsz);
b->new_const_int(b, const_i32_1, i32, 1L);
b->new_const_int(b, const_i64_hwsz, i64, strlen(hw_string)+1);
// hw_ref = g_hello_world;
SYM(inst_load);
SYM(hw_ref);
b->new_load(b, inst_load, hw_ref, 0, MU_ORD_NOT_ATOMIC, string_r, g_hello_world, MU_NO_ID);
// hw_ptr = pin(hw_ref);
SYM(inst_pin);
SYM(hw_ptr);
make_pin(b, inst_pin, hw_ptr, string_r, hw_ref);
// var_x = (ppi8)hw_ptr; // inst_ptrcast
SYM(inst_ptrcast);
SYM(var_x);
b->new_conv(b, inst_ptrcast, var_x, MU_CONV_PTRCAST,
ppi8, pvoid, hw_ptr);
// var_y = write(const_i32_1, var_x, const_i64_hwsz); // inst_write
SYM(var_y);
SYM(inst_write);
MuVarNode write_args[] = { const_i32_1, var_x, const_i64_hwsz };
MuVarNode write_rvs[] = { var_y };
b->new_ccall(b, inst_write, write_rvs, 1, MU_CC_DEFAULT,
write_fp, write_sig, const_fp_write, write_args, 3, MU_NO_ID, MU_NO_ID);
// unpin(hw_ref);
SYM(inst_unpin);
make_unpin(b, inst_unpin, string_r, hw_ref);
// const i32 const_i32_0 = 0;
// *exit_status = const_i32_0; // inst_store
SYM(const_i32_0);
SYM(inst_store);
b->new_const_int(b, const_i32_0, i32, 0L);
b->new_store(b, inst_store, 0, MU_ORD_NOT_ATOMIC, i32,
exit_status, const_i32_0, MU_NO_ID);
// thread_exit
// uvm.thread_exit(); // inst_threadexit
SYM(inst_threadexit);
b->new_comminst(b, inst_threadexit, NULL, 0, MU_CI_UVM_THREAD_EXIT,
NULL, 0, NULL, 0, NULL, 0, NULL, 0, MU_NO_ID, MU_NO_ID);
// Now construct the entry block
SYM(entry);
MuVarNode entry_args[] = { p_argc, p_argv };
MuTypeNode entry_argtys[] = { i32, ppi8 };
MuInstNode entry_insts[] = { inst_load, inst_pin, inst_ptrcast,
inst_write, inst_unpin, inst_store, inst_threadexit };
b->new_bb(b, entry, entry_args, entry_argtys, 2, MU_NO_ID, entry_insts,
sizeof(entry_insts)/sizeof(entry_insts[0]));
// and the function version (function body)
SYM(main_fv);
MuBBNode main_fv_bbs[] = { entry };
b->new_func_ver(b, main_fv, main_func, main_fv_bbs, 1);
b->load(b);
MUCHECKERR();
// Allocate an object to hold the "hello world" string.
MuIntValue v_hw_sz = ctx->handle_from_sint64(ctx, strlen(hw_string), 64);
MuRefValue v_hw_obj = ctx->new_hybrid(ctx, string_t, v_hw_sz);
// Populate the content.
MuUPtrValue v_hw_uptr = ctx->pin(ctx, v_hw_obj);
char *hw_uptr = (char*)ctx->handle_to_ptr(ctx, v_hw_uptr);
strcpy(hw_uptr, hw_string);
ctx->unpin(ctx, v_hw_obj);
// Set the global cell
MuIRefValue v_g_hello_world = ctx->handle_from_global(ctx, g_hello_world);
ctx->store(ctx, MU_ORD_NOT_ATOMIC, v_g_hello_world, v_hw_obj);
MuFuncRefValue v_main_func = ctx->handle_from_func(ctx, main_func);
// Not used anywhere. Just use this to test thread-local objref.
MuIntValue v_main_thread_local = ctx->new_fixed(ctx, i64);
printf("Making boot image...\n");
// I just want i64 to be in the boot image, too, in addition to the main funciton.
MuID whitelist[] = { i64, main_func };
ctx->make_boot_image(ctx,
whitelist, 2,
v_main_func, NULL, v_main_thread_local,
NULL, NULL, 0,
NULL, NULL, 0,
boot_image_name);
printf("Boot image created. Use the following command to run:\n");
printf(" ../tools/runmu.sh ./%s\n", boot_image_name);
MuIntValue v_argc = ctx->handle_from_sint32(ctx, i32, argc);
MuUPtrValue v_argv = ctx->handle_from_ptr(ctx, ppi8, (MuCPtr)argv);
MuValue v_main_args[] = {v_argc, v_argv};
MuStackRefValue v_main_stack = ctx->new_stack(ctx, v_main_func);
MuThreadRefValue v_main_thread = ctx->new_thread_nor(ctx, v_main_stack,
NULL, v_main_args, 2);
MUCHECKERR();
mvm->execute(mvm);
mu_refimpl2_close(mvm);
return 0;
}
<!-- This is an example. Make a copy of this file, and modify it for your need. -->
<configuration>
<!-- Set debug="true" to enable debugging for the logback logging framework itself -->
<!-- configuration debug="true" -->
<!-- This appender writes into stdout -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="uvm.refimpl.itpr" level="DEBUG" />
<!-- This appender writes into stderr -->
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Loggers are organised by packages. uvm includes everything in Holstein. -->
<logger name="uvm" level="INFO" />
<logger name="uvm.refimpl.itpr" level="INFO" /> <!-- Set this to DEBUG to print execution traces. -->
<logger name="uvm.refimpl.mem" level="INFO" /> <!-- Set this to DEBUG to print GC logs. -->
<root level="INFO">
<appender-ref ref="STDERR" />
</root>
</configuration>
<!--
vim: ts=2 sw=2 sts=2 et
-->
""" This is for one-time use only. It generates contents of
uvm.ir.irbuilder/irBuilderNode.scala, but that file should be maintained
manually in the long run. """
import muapiparser
from refimpl2injectablefiles import muapi_h_path
from muapitocstubs import toCamelCase
_to_scala_type = {
"int": "Int",
"MuBool": "Boolean",
}
def to_scala_type(rt):
return _to_scala_type.get(rt, rt)
def generate_node(method):
func_name = toCamelCase(method["name"])
node_name = "Node" + func_name[3:]
params = method["params"][1:] # skip MuIRBuilder*
node_params = []
for param in params:
pn = param['name']
pt = param['type']
nn = toCamelCase(pn)
if param.get("is_sz_param", False):
continue
elif 'array_sz_param' in param:
assert pt.endswith("*")
rt = pt[:-1]
st = to_scala_type(rt)
nt = "Seq[{}]".format(pt[:-1])
elif param.get('is_optional', False):
assert pt in ["MuCString", "MuID"] or pt.endswith("*") or any(
pt.endswith(x) for x in ["Clause", "Node"]), pt
if pt.endswith("*"):
rt = pt[:-1]
else:
rt = pt
st = to_scala_type(rt)
nt = "Option[{}]".format(rt)
else:
rt = pt
st = to_scala_type(rt)
nt = st
node_params.append((nn, nt))
return '''case class {}({}) extends IRBuilderNode(id)'''.format(
node_name, ", ".join("{}: {}".format(nn, nt) for (nn, nt) in node_params))
def generate_things(ast):
irb = [s for s in ast["structs"] if s["name"] == "MuIRBuilder"][0]
nodes = []
for meth in irb["methods"]:
if meth["name"].startswith("new_"):
nodes.append(generate_node(meth))
return "\n".join(nodes)
def main():
with open(muapi_h_path) as f:
src_text = f.read()
ast = muapiparser.parse_muapi(src_text)
generated = generate_things(ast)
print(generated)
if __name__=='__main__':
main()
import re
from typing import List, Union, Tuple, Any, Callable, TypeVar, Mapping
from typing.re import Pattern
import tempfile, os.path
Predicate = Union[str,
Tuple[Pattern, ...],
Callable[[Any], bool]]
def _string_contains(line, string):
return string in line
def _pattern_value_match(line, tup):
pat = tup[0]
vals = tup[1:]
m = pat.search(line)
return m is not None and all(
v is None or g == v
for g,v in zip(m.groups(), vals))
def _apply_func(line, func):
return func(line)
def find_line(lines: List[str], substr: Predicate, start: int = 0) -> int:
"""Find the line that contains or matches substr since line ``start``. """
if isinstance(substr, str):
pred = _string_contains
elif isinstance(substr, tuple):
pred = _pattern_value_match
else:
pred = _apply_func
for i in range(start, len(lines)):
if pred(lines[i], substr):
return i
raise Exception("Not found: " + str(substr) + "\n text:" + str(lines) )
def extract_lines(parent: str, begin: Predicate, end: Predicate) -> str:
"""
Extract the lines between the line containing ``begin`` and the line
containing ``end`` (excluding both lines) in ``parent``.
"""
lines = parent.splitlines()
begin_line = find_line(lines, begin)
end_line = find_line(lines, end, begin_line+1)
new_lines = lines[begin_line+1:end_line]
return "\n".join(new_lines)
def inject_lines(parent: str, begin: Predicate, end: Predicate, generated: str) -> str:
"""
Replace the lines between the line containing ``begin`` and the line
containing ``end`` (excluding both lines) in ``parent`` with ``generated``.
"""
lines = parent.splitlines()
begin_line = find_line(lines, begin)
end_line = find_line(lines, end, begin_line+1)
new_lines = lines[:begin_line+1] + generated.splitlines() + lines[end_line:]
return "\n".join(new_lines)
STANDARD_PREFIX_BEGIN = "GEN:BEGIN:"
STANDARD_PREFIX_END = "GEN:END:"
class StandardInjectableFile(object):
def __init__(self, path: str, injection_points: List[str] = None):
self.path = path
if injection_points is None:
injection_points = []
self.injection_points = injection_points
def inject_many(self, m: Mapping[str, str], force=False):
with open(self.path) as f:
orig_txt = f.read()
txt = orig_txt
for inj_point, inj_content in m.items():
if inj_point not in self.injection_points and not force:
raise Exception("Unknown injection point '{}'".format(inj_point))
inj_begin = STANDARD_PREFIX_BEGIN + inj_point
inj_end = STANDARD_PREFIX_END + inj_point
new_txt = inject_lines(txt, inj_begin, inj_end, inj_content)
txt = new_txt
if not txt.endswith("\n"):
txt += "\n"
with tempfile.NamedTemporaryFile("w", delete=False) as f:
print("Backup to temporary file: {} -> {}".format(self.path, f.name))
f.write(orig_txt)
with open(self.path, "w") as f:
print("Writing to file: {}".format(self.path))
f.write(txt)
def make_injectable_file_set(
root_path: str,
items : List[Tuple[str, str, List[str]]],
) -> Mapping[str, StandardInjectableFile]:
m = InjectableFileSet()
for name, path, inj_points in items:
full_path = os.path.join(root_path, path)
sif = StandardInjectableFile(full_path, inj_points)
m[name] = sif
return m
class InjectableFileSet(dict):
def inject_many(self, m: Mapping[str, Mapping[str, str]]):
for name, mm in m.items():
self[name].inject_many(mm)
"""
Generate match cases to match against instructions.
"""
from refimpl2injectablefiles import _refimpl2_root
import injecttools
import os.path, sys
import re
case_class_r = re.compile(r'case class (\w+)\(([^)]*)\)', re.MULTILINE)
param_r = re.compile(r'va[lr]\s+(\w+)\s*:\s*([a-zA-Z0-9\[\]_]+)', re.MULTILINE)
ssavariables_path = os.path.join(_refimpl2_root, "src/main/scala/uvm/ssavariables/ssavariables.scala")
def main():
with open(ssavariables_path) as f:
txt = f.read()
txt = injecttools.extract_lines(txt, "EXTRACT:BEGIN:INSTS", "EXTRACT:END:INSTS")
for name, params in case_class_r.findall(txt):
pns = []
for pn, pt in param_r.findall(params):
pns.append(pn)
print("case {}({}) => ".format(name, ", ".join(pns)))
if __name__=="__main__":
main()
"""
Usage: python3 irbuildernodestoirbuildermethods.py
"""
import re
import sys, os.path, io
import injecttools
from refimpl2injectablefiles import injectable_files, irbuilder_nodes_path
replaces = [(re.compile(x), y) for (x,y) in [
(r'TrantientBundle', 'MuBundleNode'),
(r'TB', 'MuBundleNode'),
(r'Bundle', 'MuBundleNode'),
(r'TopLevel', 'MuChildNode'),
(r'ChildNode', 'MuChildNode'),
(r'Type\w*', 'MuTypeNode'),
(r'Abstract\w+Type', 'MuTypeNode'),
(r'FuncSig', 'MuFuncSigNode'),
(r'Const\w+', 'MuConstNode'),
(r'GlobalCell', 'MuGlobalNode'),
(r'Function', 'MuFuncNode'),
(r'ExposedFunc', 'MuExpFuncNode'),
(r'FuncVer', 'MuFuncVerNode'),
(r'BasicBlock', 'MuBBNode'),
(r'BB', 'MuBBNode'),
(r'SSAVariable', 'MuVarNode'),
(r'Var', 'MuVarNode'),
(r'LocalVariable', 'MuLocalVarNode'),
(r'NorParam', 'MuNorParamNode'),
(r'ExcParam', 'MuExcParamNode'),
(r'InstResult', 'MuInstResNode'),
(r'Inst\w+', 'MuInstNode'),
(r'HasKeepaliveClause', 'MuInstNode'),
]]
case_class_r = re.compile(r'^(case\s+class\s+(\w+)\s*\(([^)]*)\))', re.MULTILINE)
arg = re.compile(r'(\w+):\s*([a-zA-Z0-9\[\].]+)')
begin="EXT:BEGIN:IRBUILDER_NODES"
end="EXT:END:IRBUILDER_NODES"
def main():
with open(irbuilder_nodes_path) as f:
lines = f.read()
text = injecttools.extract_lines(lines, begin, end)
output = io.StringIO()
for whole, name, arglist in case_class_r.findall(text):
node_name = name
func_name = "new" + name[4:]
argnames = []
argtypes = []
for an,at in arg.findall(arglist):
argnames.append(an)
argtypes.append(at)
print(" def {}({}): Unit = {{".format(func_name, ", ".join(
"{}: {}".format(an, at) for an, at in zip(argnames, argtypes))),
file=output)
print(" val _node = new {}({})".format(node_name,
", ".join(argnames)), file=output)
print(" onNewNodeCreated(_node)", file=output)
print(" }", file=output)
#print(output.getvalue())
#return
injectable_files["IRBuilder.scala"].inject_many({
"IRBUILDERNODE_CONSTRUCTORS": output.getvalue(),
})
if __name__=='__main__':
main()
"""
IRBuilder is no longer part of MuCtx. Don't use this.
"""
import re
import sys, os.path, io
import injecttools
from refimpl2injectablefiles import injectable_files
begin = "SCRIPT: BEGIN HERE"
end = "SCRIPT: END HERE"
replaces = [(re.compile(x), y) for (x,y) in [
(r'TrantientBundle', 'MuBundleNode'),
(r'TB', 'MuBundleNode'),
(r'Bundle', 'MuBundleNode'),
(r'TopLevel', 'MuChildNode'),
(r'ChildNode', 'MuChildNode'),
(r'Type\w*', 'MuTypeNode'),
(r'Abstract\w+Type', 'MuTypeNode'),
(r'FuncSig', 'MuFuncSigNode'),
(r'Const\w+', 'MuConstNode'),
(r'GlobalCell', 'MuGlobalNode'),
(r'Function', 'MuFuncNode'),
(r'ExposedFunc', 'MuExpFuncNode'),
(r'FuncVer', 'MuFuncVerNode'),
(r'BasicBlock', 'MuBBNode'),
(r'BB', 'MuBBNode'),
(r'SSAVariable', 'MuVarNode'),
(r'Var', 'MuVarNode'),
(r'LocalVariable', 'MuLocalVarNode'),
(r'NorParam', 'MuNorParamNode'),
(r'ExcParam', 'MuExcParamNode'),
(r'InstResult', 'MuInstResNode'),
(r'Inst\w+', 'MuInstNode'),
(r'HasKeepaliveClause', 'MuInstNode'),
]]
sig = re.compile(r'^( def\s+(\w+)\s*\(([^)]*)\):\s+(\w+)\s+=)', re.MULTILINE)
arg = re.compile(r'(\w*):\s*([a-zA-Z0-9\[\].]+)')
node_like = re.compile(r'Mu\w+Node')
node_seq_like = re.compile(r'Seq\[(Mu\w+Node)\]')
_my_dir = os.path.dirname(__file__)
_refimpl2_root = os.path.join(_my_dir, "..")
irbuilder_path = os.path.join(_refimpl2_root, "src/main/scala/uvm/ir/irbuilder/IRBuilder.scala")
## No longer replace names, but just use MuIRNode[...]
#def rewrite_type(ty):
# for p, t in replaces:
# oldty = ty
# ty = p.sub(t, ty)
# if oldty != ty:
# break
# return ty
container_ty_r = re.compile(r'(Seq|Option)\[(.+)\]')
def rewrite_type(ty):
m = container_ty_r.match(ty)
if m is not None:
t1, t2 = m.groups()
return "{}[{}]".format(t1, rewrite_type(t2))
for p, t in replaces:
if p.match(ty) is not None:
return "MuIRNode[{}]".format(ty)
return ty
def main():
with open(irbuilder_path) as f:
lines = f.read()
text = injecttools.extract_lines(lines, begin, end)
#for p, t in replaces:
#text = p.sub(t, text)
output = io.StringIO()
for whole, name, arglist, retty in sig.findall(text):
argnames = []
argtypes_muctx = []
sanitisers = []
retty = rewrite_type(retty)
for an,at in arg.findall(arglist):
rwt = rewrite_type(at)
print(an, at, rwt)
argnames.append(an)
argtypes_muctx.append(rwt)
m = node_seq_like.match(rwt)
if m is not None:
sanitisers.append(' for((n,i) <- {}.zipWithIndex) require(!n.isNull, "{}[%d] must not be NULL".format(i))'.format(an, an))
elif node_like.match(rwt) is not None:
sanitisers.append(' require(!{}.isNull, "{} must not be NULL")'.format(an, an))
new_arglist = ", ".join("{}: {}".format(n,t) for n,t in zip(argnames, argtypes_muctx))
print(" def {}({}): {} = {{".format(name, new_arglist, retty), file=output)
for s in sanitisers:
print(s, file=output)
if name.startswith("new") or name in["getNode", "getInstRes"]:
print(' nodeToHandle(irBuilder.{}({}))'.format(name, ", ".join(argnames)), file=output)
else:
print(' irBuilder.{}({})'.format(name, ", ".join(argnames)), file=output)
print(" }", file=output)
print(file=output)
#print(whole, name, args)
#for n,a in sig.findall(line):
#args = arg_name.findall(a)
#print(" addHandle(irBuilder.{}({}))".format(n, ", ".join(args)))
#print(output.getvalue())
#return
injectable_files["MuCtxIRBuilderPart.scala"].inject_many({
"METHODS": output.getvalue(),
})
if __name__=='__main__':
main()
"""
Parse the muapi.h so that you can generate different bindings.
The result will be a simple JSON object (dict of dicts).
"""
import re
import injecttools
rfrag_commpragma = r'(?:///\s*MUAPIPARSER\s+(?P<pragma>.*))?'
r_comment = re.compile(r'//.*$', re.MULTILINE)
r_decl = re.compile(r'(?P<ret>\w+\s*\*?)\s*\(\s*\*\s*(?P<name>\w+)\s*\)\s*\((?P<params>[^)]*)\)\s*;\s*' + rfrag_commpragma, re.MULTILINE)
r_param = re.compile(r'\s*(?P<type>\w+\s*\*?)\s*(?P<name>\w+)')
r_define = re.compile(r'^\s*#define\s+(?P<name>\w+)\s*\(\((?P<type>\w+)\)(?P<value>\w+)\)\s*' + rfrag_commpragma + r'\s*$', re.MULTILINE)
r_typedef = re.compile(r'^\s*typedef\s+(?P<const>const\s+)?(?P<expand_to>\w+\s*\*?)\s*(?P<name>\w+)\s*;', re.MULTILINE)
r_struct_start = re.compile(r'^struct\s+(\w+)\s*\{')
r_struct_end = re.compile(r'^\};')
def filter_ret_ty(text):
return text.replace(" ","")
def extract_params(text):
params = []
for text1 in text.split(','):
ty, name = r_param.search(text1).groups()
ty = ty.replace(" ",'')
params.append({"type": ty, "name": name})
return params
def extract_pragmas(text):
text = text.strip()
if len(text) == 0:
return []
else:
return text.split(";")
def extract_method(name, params, ret_ty, pragmas):
params = extract_params(params)
ret_ty = filter_ret_ty(ret_ty)
pragmas = extract_pragmas(pragmas)
params_index = {p["name"]:p for p in params}
for pragma in pragmas:
parts = pragma.split(":")
param_name = parts[0]
if param_name not in params_index:
raise Exception("Method {}: Pragma {} is for unknown param {}".format(
name, pragma, param_name))
param = params_index[param_name]
kind = parts[1]
if kind == 'array':
sz_param_name = parts[2]
param["array_sz_param"] = sz_param_name