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.2% of users enabled 2FA.

Commit c8c90822 authored by Yi Lin's avatar Yi Lin
Browse files

Merge branch 'jit-test' into 'master'

Merge jit-test branch to master



See merge request !2
parents bec493dc b8286940
......@@ -13,4 +13,5 @@ pub extern crate ast;
pub extern crate utils;
pub mod vm;
pub mod compiler;
pub mod runtime;
\ No newline at end of file
pub mod runtime;
pub mod testutil;
extern crate log;
extern crate simple_logger;
extern crate libloading as ll;
use compiler::*;
use ast::ir::*;
use vm::*;
use std::sync::Arc;
pub mod aot {
use ast::ir::MuName;
use runtime;
use compiler::backend;
use std::path::PathBuf;
use std::process::Command;
use std::process::Output;
fn get_test_clang_path() -> String {
use std::env;
match env::var("CLANG_FOR_AOT") {
Ok(val) => val,
Err(_) => "clang".to_string()
}
}
fn exec (mut cmd: Command) -> Output {
println!("executing: {:?}", cmd);
let output = cmd.output().expect("failed to execute");
println!("---out---");
println!("{}", String::from_utf8_lossy(&output.stdout));
println!("---err---");
println!("{}", String::from_utf8_lossy(&output.stderr));
output
}
fn link_executable_internal (files: Vec<PathBuf>, out: PathBuf) -> PathBuf {
let mut gcc = Command::new(get_test_clang_path());
for file in files {
println!("link with {:?}", file.as_path());
gcc.arg(file.as_path());
}
println!("output as {:?}", out.as_path());
if cfg!(target_os = "linux") {
gcc.arg("-lrt");
gcc.arg("-ldl");
gcc.arg("-lpthread");
}
// so we can find symbols in itself
gcc.arg("-rdynamic");
gcc.arg("-o");
gcc.arg(out.as_os_str());
assert!(exec(gcc).status.success());
out
}
fn link_dylib_internal (files: Vec<PathBuf>, out: PathBuf) -> PathBuf {
let mut object_files : Vec<PathBuf> = vec![];
for file in files {
let mut gcc = Command::new(get_test_clang_path());
gcc.arg("-c");
gcc.arg("-fpic");
let mut out = file.clone();
out.set_extension("o");
gcc.arg(file.as_os_str());
gcc.arg("-o");
gcc.arg(out.as_os_str());
object_files.push(out);
exec(gcc);
}
let mut gcc = Command::new(get_test_clang_path());
gcc.arg("-shared");
gcc.arg("-Wl");
gcc.arg("-undefined");
gcc.arg("dynamic_lookup");
for obj in object_files {
gcc.arg(obj.as_os_str());
}
gcc.arg("-o");
gcc.arg(out.as_os_str());
exec(gcc);
out
}
fn get_path_for_mu_func (f: MuName) -> PathBuf {
let mut ret = PathBuf::from(backend::AOT_EMIT_DIR);
ret.push(f);
ret.set_extension("s");
ret
}
fn get_path_for_mu_context () -> PathBuf {
let mut ret = PathBuf::from(backend::AOT_EMIT_DIR);
ret.push(backend::AOT_EMIT_CONTEXT_FILE);
ret
}
pub fn link_primordial (funcs: Vec<MuName>, out: &str) -> PathBuf {
let emit_dir = PathBuf::from(backend::AOT_EMIT_DIR);
let files : Vec<PathBuf> = {
use std::fs;
let mut ret = vec![];
// all interested mu funcs
for func in funcs {
ret.push(get_path_for_mu_func(func));
}
// mu context
ret.push(get_path_for_mu_context());
// copy primoridal entry
let source = PathBuf::from(runtime::PRIMORDIAL_ENTRY);
let mut dest = PathBuf::from(backend::AOT_EMIT_DIR);
dest.push("main.c");
fs::copy(source.as_path(), dest.as_path()).unwrap();
// include the primordial C main
ret.push(dest);
// include mu static lib
let libmu = PathBuf::from("target/debug/libmu.a");
ret.push(libmu);
ret
};
let mut out_path = emit_dir.clone();
out_path.push(out);
link_executable_internal(files, out_path)
}
pub fn execute(executable: PathBuf) {
let run = Command::new(executable.as_os_str());
assert!(exec(run).status.success());
}
pub fn link_dylib (funcs: Vec<MuName>, out: &str) -> PathBuf {
let files = {
let mut ret = vec![];
for func in funcs {
ret.push(get_path_for_mu_func(func));
}
ret.push(get_path_for_mu_context());
ret
};
let mut out_path = PathBuf::from(backend::AOT_EMIT_DIR);
out_path.push(out);
link_dylib_internal(files, out_path)
}
}
pub fn compile_fnc<'a>(fnc_name: &'static str, build_fnc: &'a Fn() -> VM) -> ll::Library {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm = Arc::new(build_fnc());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of(fnc_name);
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
let libname = &format!("lib{}.dylib", fnc_name);
let dylib = aot::link_dylib(vec![Mu(fnc_name)], libname);
ll::Library::new(dylib.as_os_str()).unwrap()
}
......@@ -243,6 +243,14 @@ extern fn _forwarder__MuVM__set_trap_handler(mvm: *mut CMuVM, trap_handler: CMuT
};
}
extern fn _forwarder__MuVM__compile_to_sharedlib(mvm: *mut CMuVM, lib_name: CMuCString) {
let mut _arg_mvm = from_MuVM_ptr(mvm);
let mut _arg_lib_name = from_MuCString(lib_name);
unsafe {
(*_arg_mvm).compile_to_sharedlib(&_arg_lib_name)
};
}
extern fn _forwarder__MuCtx__id_of(ctx: *mut CMuCtx, name: CMuName) -> CMuID {
let mut _arg_ctx = from_MuCtx_ptr(ctx);
let mut _arg_name = from_MuName(name);
......@@ -2037,6 +2045,7 @@ pub fn make_new_MuVM(header: *mut c_void) -> *mut CMuVM {
id_of: _forwarder__MuVM__id_of,
name_of: _forwarder__MuVM__name_of,
set_trap_handler: _forwarder__MuVM__set_trap_handler,
compile_to_sharedlib: _forwarder__MuVM__compile_to_sharedlib,
});
Box::into_raw(bx)
......
......@@ -109,6 +109,8 @@ pub struct CMuVM {
pub id_of: extern fn(*mut CMuVM, CMuName) -> CMuID,
pub name_of: extern fn(*mut CMuVM, CMuID) -> CMuName,
pub set_trap_handler: extern fn(*mut CMuVM, CMuTrapHandler, CMuCPtr),
// this function is only used in testing jit
pub compile_to_sharedlib: extern fn(*mut CMuVM, CMuCString),
}
#[repr(C)]
......
use super::common::*;
use std::sync::Arc;
pub struct MuVM {
// The actual VM
pub vm: VM,
pub vm: Arc<VM>,
// Cache C strings. The C client expects `char*` from `name_of`. We assume the client won't
// call `name_of` very often, so that we don't need to initialise this hashmap on startup.
......@@ -19,7 +20,7 @@ impl MuVM {
*/
pub fn new() -> MuVM {
MuVM {
vm: VM::new(),
vm: Arc::new(VM::new()),
// Cache C strings. The C client expects `char*` from `name_of`. We assume the client
// won't call `name_of` very often, so that we don't need to initialise this hashmap on
// startup.
......@@ -69,6 +70,28 @@ impl MuVM {
panic!("Not implemented")
}
pub fn compile_to_sharedlib(&self, lib_name: &str) {
extern crate libloading as ll;
use compiler::*;
use testutil::aot;
let compiler = Compiler::new(CompilerPolicy::default(), self.vm.clone());
let funcs = self.vm.funcs().read().unwrap();
let mut func_names = vec![];
// NOTE: this fails because load() API call is not properly implemented yet.
for (func_id, ref f) in funcs.iter() {
let func = f.read().unwrap();
let func_vers = self.vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
func_names.push(func.name().unwrap());
}
backend::emit_context(&self.vm);
let libname = &format!("lib{}.dylib", lib_name);
aot::link_dylib(func_names, libname);
}
}
/**
......
......@@ -270,6 +270,8 @@ struct MuVM {
// Set handlers
void (*set_trap_handler)(MuVM *mvm, MuTrapHandler trap_handler, MuCPtr userdata);
void (*compile_to_sharedlib)(MuVM *mvm, MuCString lib_name);
};
// A local context. It can only be used by one thread at a time. It holds many
......
......@@ -30,168 +30,3 @@ mod common {
assert_eq!(format!("{:?}", left), format!("{:?}", right))
}
}
mod aot {
use mu::ast::ir::MuName;
use mu::runtime;
use mu::compiler::backend;
use std::path::PathBuf;
use std::process::Command;
use std::process::Output;
fn get_test_clang_path() -> String {
use std::env;
match env::var("CLANG_FOR_AOT") {
Ok(val) => val,
Err(_) => "clang".to_string()
}
}
fn exec (mut cmd: Command) -> Output {
println!("executing: {:?}", cmd);
let output = cmd.output().expect("failed to execute");
println!("---out---");
println!("{}", String::from_utf8_lossy(&output.stdout));
println!("---err---");
println!("{}", String::from_utf8_lossy(&output.stderr));
output
}
fn link_executable_internal (files: Vec<PathBuf>, out: PathBuf) -> PathBuf {
let mut gcc = Command::new(get_test_clang_path());
for file in files {
println!("link with {:?}", file.as_path());
gcc.arg(file.as_path());
}
println!("output as {:?}", out.as_path());
if cfg!(target_os = "linux") {
gcc.arg("-lrt");
gcc.arg("-ldl");
gcc.arg("-lpthread");
}
// so we can find symbols in itself
gcc.arg("-rdynamic");
gcc.arg("-o");
gcc.arg(out.as_os_str());
assert!(exec(gcc).status.success());
out
}
fn link_dylib_internal (files: Vec<PathBuf>, out: PathBuf) -> PathBuf {
let mut object_files : Vec<PathBuf> = vec![];
for file in files {
let mut gcc = Command::new(get_test_clang_path());
gcc.arg("-c");
gcc.arg("-fpic");
let mut out = file.clone();
out.set_extension("o");
gcc.arg(file.as_os_str());
gcc.arg("-o");
gcc.arg(out.as_os_str());
object_files.push(out);
exec(gcc);
}
let mut gcc = Command::new(get_test_clang_path());
gcc.arg("-shared");
gcc.arg("-Wl");
gcc.arg("-undefined");
gcc.arg("dynamic_lookup");
for obj in object_files {
gcc.arg(obj.as_os_str());
}
gcc.arg("-o");
gcc.arg(out.as_os_str());
exec(gcc);
out
}
fn get_path_for_mu_func (f: MuName) -> PathBuf {
let mut ret = PathBuf::from(backend::AOT_EMIT_DIR);
ret.push(f);
ret.set_extension("s");
ret
}
fn get_path_for_mu_context () -> PathBuf {
let mut ret = PathBuf::from(backend::AOT_EMIT_DIR);
ret.push(backend::AOT_EMIT_CONTEXT_FILE);
ret
}
pub fn link_primordial (funcs: Vec<MuName>, out: &str) -> PathBuf {
let emit_dir = PathBuf::from(backend::AOT_EMIT_DIR);
let files : Vec<PathBuf> = {
use std::fs;
let mut ret = vec![];
// all interested mu funcs
for func in funcs {
ret.push(get_path_for_mu_func(func));
}
// mu context
ret.push(get_path_for_mu_context());
// copy primoridal entry
let source = PathBuf::from(runtime::PRIMORDIAL_ENTRY);
let mut dest = PathBuf::from(backend::AOT_EMIT_DIR);
dest.push("main.c");
fs::copy(source.as_path(), dest.as_path()).unwrap();
// include the primordial C main
ret.push(dest);
// include mu static lib
let libmu = PathBuf::from("target/debug/libmu.a");
ret.push(libmu);
ret
};
let mut out_path = emit_dir.clone();
out_path.push(out);
link_executable_internal(files, out_path)
}
pub fn execute(executable: PathBuf) {
let run = Command::new(executable.as_os_str());
assert!(exec(run).status.success());
}
pub fn link_dylib (funcs: Vec<MuName>, out: &str) -> PathBuf {
let files = {
let mut ret = vec![];
for func in funcs {
ret.push(get_path_for_mu_func(func));
}
ret.push(get_path_for_mu_context());
ret
};
let mut out_path = PathBuf::from(backend::AOT_EMIT_DIR);
out_path.push(out);
link_dylib_internal(files, out_path)
}
}
\ No newline at end of file
......@@ -12,7 +12,7 @@ use self::mu::compiler::*;
use std::sync::Arc;
use std::sync::RwLock;
use std::collections::HashMap;
use aot;
use self::mu::testutil::aot;
#[test]
fn test_instruction_new() {
......
extern crate libloading as ll;
extern crate mu;
extern crate log;
extern crate simple_logger;
extern crate libloading;
use test_ir::test_ir::sum;
use test_ir::test_ir::factorial;
use self::mu::compiler::*;
use self::mu::ast::ir::*;
use std::sync::Arc;
use aot;
use mu::testutil;
#[test]
fn test_regalloc_fac() {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm = Arc::new(factorial());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of("fac");
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
let dylib = aot::link_dylib(vec![Mu("fac")], "libfac.dylib");
let lib = libloading::Library::new(dylib.as_os_str()).unwrap();
fn test_factorial() {
let lib = testutil::compile_fnc("fac", &factorial);
unsafe {
let fac : libloading::Symbol<unsafe extern fn(u64) -> u64> = lib.get(b"fac").unwrap();
let fac5 = fac(5);
println!("fac(5) = {}", fac5);
assert!(fac5 == 120);
let fac: ll::Symbol<unsafe extern fn (u64) -> u64> = lib.get(b"fac").unwrap();
println!("fac(10) = {}", fac(10));
assert!(fac(10) == 3628800);
}
}
#[test]
fn test_regalloc_sum() {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm = Arc::new(sum());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of("sum");
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
let dylib = aot::link_dylib(vec![Mu("sum")], "libsum.dylib");
let lib = libloading::Library::new(dylib.as_os_str()).unwrap();
fn test_sum() {
let lib = testutil::compile_fnc("sum", &sum);
unsafe {
let sum : libloading::Symbol<unsafe extern fn(u64) -> u64> = lib.get(b"sum").unwrap();
let sum5 = sum(5);
println!("sum(1..4) = {}", sum5);
assert!(sum5 == 10);
let sum10 = sum(10);
println!("sum(0..9) = {}", sum10);
assert!(sum10 == 45);
}
}
\ No newline at end of file
let sumptr: ll::Symbol<unsafe extern fn (u64) -> u64> = lib.get(b"sum").unwrap();
assert!(sumptr(5) == 10);
assert!(sumptr(10) == 45);
}
}
......@@ -9,7 +9,7 @@ use self::mu::ast::inst::*;
use self::mu::vm::*;
use self::mu::compiler::*;
use aot;
use self::mu::testutil::aot;
use std::sync::Arc;
use std::sync::RwLock;
......
......@@ -12,7 +12,7 @@ use self::mu::compiler::*;
use std::sync::RwLock;
use std::sync::Arc;
use aot;
use mu::testutil::aot;
#[test]
fn test_fp_add() {
......
......@@ -3,7 +3,7 @@ extern crate log;
extern crate simple_logger;
extern crate libloading;
use aot;
use mu::testutil::aot;
use test_ir::test_ir::factorial;
use self::mu::compiler::*;
use self::mu::utils::vec_utils;
......
......@@ -11,7 +11,7 @@ use self::mu::ast::op::*;
use self::mu::vm::*;
use self::mu::compiler::*;
use aot;
use self::mu::testutil::aot;
use std::sync::Arc;