Commit 8fd15ab3 authored by qinsoon's avatar qinsoon

[wip] can jump to named primordial function

gonna implement THREADEXIT
parent d9f4e1b1
build_targets=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?>\n<build_targets xmlns\="com.github.rustdt.ide.core">\n<target auto_enabled\="true" config\="build" n_enabled\="true" version2\="true"/>\n<target auto_enabled\="false" config\="check" n_enabled\="false" version2\="true">\n<command_invocation append_env\="true" command_arguments\="${CARGO_TOOL_PATH} build">\n<env_vars/>\n</command_invocation>\n</target>\n</build_targets>\n
build_targets=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?>\n<build_targets xmlns\="com.github.rustdt.ide.core">\n<target auto_enabled\="false" config\="build" n_enabled\="true" version2\="true"/>\n<target auto_enabled\="true" config\="check" n_enabled\="false" version2\="true">\n<command_invocation append_env\="true" command_arguments\="${CARGO_TOOL_PATH} build">\n<env_vars/>\n</command_invocation>\n</target>\n</build_targets>\n
eclipse.preferences.version=1
......@@ -4,5 +4,9 @@ extern crate gcc;
#[cfg(target_arch = "x86_64")]
fn main() {
gcc::compile_library("libruntime.a", &["src/runtime/runtime_x64_macos.c"]);
gcc::compile_library("libgc_clib_x64.a", &["src/runtime/mm/heap/gc/clib_x64.c"]);
gcc::compile_library("libgc_clib_x64.a", &["src/runtime/mm/heap/gc/clib_x64.c"]);
gcc::Config::new().flag("-O3")
.file("src/runtime/swap_stack_x64_macos.s")
.compile("libswap_stack.a");
}
\ No newline at end of file
......@@ -652,6 +652,7 @@ impl fmt::Display for MemoryLocation {
}
}
#[repr(C)]
#[derive(Debug)] // Display, PartialEq
pub struct MuEntityHeader {
pub id: MuID,
......
......@@ -1192,11 +1192,11 @@ fn directive_comm(name: String, size: ByteSize, align: ByteSize) -> String {
}
#[cfg(target_os = "linux")]
fn symbol(name: String) -> String {
pub fn symbol(name: String) -> String {
name
}
#[cfg(target_os = "macos")]
fn symbol(name: String) -> String {
pub fn symbol(name: String) -> String {
format!("_{}", name)
}
}
\ No newline at end of file
......@@ -410,6 +410,10 @@ impl <'a> InstructionSelection {
unimplemented!()
}
}
Instruction_::ThreadExit => {
// do nothing for now
}
_ => unimplemented!()
} // main switch
......
......@@ -116,6 +116,12 @@ impl fmt::UpperHex for Address {
}
}
impl fmt::LowerHex for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:x}", self.0)
}
}
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "0x{:X}", self.0)
......@@ -169,6 +175,12 @@ impl fmt::UpperHex for ObjectReference {
}
}
impl fmt::LowerHex for ObjectReference {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:x}", self.0)
}
}
impl fmt::Display for ObjectReference {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "0x{:X}", self.0)
......
......@@ -9,6 +9,29 @@ use ast::ir::*;
use compiler::backend::Word;
use compiler::backend::RegGroup;
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::ffi::CString;
#[link(name="dl")]
extern "C" {
fn dlopen(filename: *const c_char, flags: isize) -> *const c_void;
fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void;
}
pub fn resolve_symbol(symbol: String) -> Address {
use std::ptr;
let rtld_default = unsafe {dlopen(ptr::null(), 0)};
let ret = unsafe {dlsym(rtld_default, CString::new(symbol.clone()).unwrap().as_ptr())};
if ret == 0 as *const c_void {
panic!("cannot find symbol {}", symbol);
}
Address::from_ptr(ret)
}
#[derive(Clone, Debug)]
pub enum ValueLocation {
Register(RegGroup, MuID),
......
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
__thread void* mu_tls;
void* init_thread_local(void** local) {
mu_tls = *local;
void* init_thread_local(void* thread) {
mu_tls = thread;
return &mu_tls;
}
void* resolve_symbol(const char* sym) {
printf("%s\n", sym);
return dlsym(RTLD_DEFAULT, sym);
}
# swap_stack_to(new_sp: Address, entry: Address, old_sp_loc: Address)
# %rdi %rsi %rdx
.globl _swap_to_mu_stack
_swap_to_mu_stack:
# -- on old stack --
# C calling convention
pushq %rbp
movq %rsp, %rbp
# other callee-saved registers
pushq %rbx
pushq %r12
pushq %r13
pushq %r14
pushq %r15
# save sp to %rbx
movq %rsp, 0(%rdx)
# switch to new stack
movq %rdi, %rsp
# save entry function in %rax
movq %rsi, %rax
# -- on new stack --
# arguments (reverse order of thread.rs - runtime_load_args)
popq %r9
popq %r8
popq %rcx
popq %rdx
popq %rsi
popq %rdi
movsd 0(%rsp), %xmm7
movsd 8(%rsp), %xmm6
movsd 16(%rsp), %xmm5
movsd 24(%rsp), %xmm4
movsd 32(%rsp), %xmm3
movsd 40(%rsp), %xmm2
add $48, %rsp
# at this point new stack is clean (no intermediate values)
movq %rsp, %rbp
# push an empty pointer to stack, if entry fucntion tries to return, it causes a segfault
pushq $0
# push entry function and start it
pushq %rax
ret
# _swap_back_to_native_stack(sp_loc: Address)
# %rdi
.globl _swap_back_to_native_stack
_swap_back_to_native_stack:
movq 0(%rdi), %rsp
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbx
popq %rbp
ret
......@@ -4,6 +4,7 @@ use ast::ir::*;
use ast::ptr::*;
use ast::types::*;
use vm::VM;
use runtime;
use runtime::ValueLocation;
use runtime::mm;
......@@ -12,6 +13,7 @@ use utils::Address;
use utils::mem::memmap;
use utils::mem::memsec;
use std::mem;
use std::thread;
use std::thread::JoinHandle;
......@@ -23,6 +25,7 @@ pub const PAGE_SIZE : ByteSize = (4 << 10); // 4kb
impl_mu_entity!(MuThread);
impl_mu_entity!(MuStack);
#[repr(C)]
pub struct MuStack {
pub hdr: MuEntityHeader,
......@@ -156,6 +159,38 @@ impl MuStack {
debug_assert!(self.sp.diff(stack_ptr) == 12 * WORD_SIZE);
// save it back
self.sp = stack_ptr;
self.print_stack(Some(20));
}
pub fn print_stack(&self, n_entries: Option<usize>) {
use compiler::backend::Word;
use compiler::backend::WORD_SIZE;
let mut cursor = self.upper_bound.sub(WORD_SIZE);
let mut count = 0;
println!("0x{:x} | UPPER_BOUND", self.upper_bound);
while cursor >= self.lower_bound {
let val = unsafe{cursor.load::<Word>()};
print!("0x{:x} | 0x{:x} ({})", cursor, val, val);
if cursor == self.sp {
print!(" <- SP");
}
println!("");
cursor = cursor.sub(WORD_SIZE);
count += 1;
if n_entries.is_some() && count > n_entries.unwrap() {
println!("...");
break;
}
}
println!("0x{:x} | LOWER_BOUND", self.lower_bound);
}
}
......@@ -165,11 +200,13 @@ pub enum MuStackState {
Dead
}
#[repr(C)]
pub struct MuThread {
pub hdr: MuEntityHeader,
allocator: Box<mm::Mutator>,
stack: Option<Box<MuStack>>,
native_sp_loc: Address,
user_tls: Option<Address>
}
......@@ -177,7 +214,16 @@ pub struct MuThread {
#[cfg(target_os = "macos")]
#[link(name = "runtime")]
extern "C" {
fn init_thread_local(thread: &Box<MuThread>) -> Address;
#[allow(improper_ctypes)]
fn init_thread_local(thread: *mut MuThread) -> Address;
}
#[cfg(target_arch = "x86_64")]
#[cfg(target_os = "macos")]
#[link(name = "swap_stack")]
extern "C" {
fn swap_to_mu_stack(new_sp: Address, entry: Address, old_sp_loc: Address);
fn swap_back_to_native_stack(sp_loc: Address);
}
impl MuThread {
......@@ -186,6 +232,7 @@ impl MuThread {
hdr: MuEntityHeader::unnamed(id),
allocator: allocator,
stack: Some(stack),
native_sp_loc: unsafe {Address::zero()},
user_tls: user_tls
}
}
......@@ -193,24 +240,30 @@ impl MuThread {
#[no_mangle]
#[allow(unused_variables)]
pub extern fn mu_thread_launch(id: MuID, stack: Box<MuStack>, user_tls: Option<Address>, vm: &VM) -> JoinHandle<()> {
let new_sp = stack.sp;
let entry = runtime::resolve_symbol(vm.name_of(stack.func_id));
debug!("entry : 0x{:x}", entry);
match thread::Builder::new().name(format!("Mu Thread #{}", id)).spawn(move || {
let muthread = Box::new(MuThread::new(id, mm::new_mutator(), stack, user_tls));
let muthread : *mut MuThread = Box::into_raw(Box::new(MuThread::new(id, mm::new_mutator(), stack, user_tls)));
// set thread local
let addr = unsafe {init_thread_local(&muthread)};
let addr = unsafe {init_thread_local(muthread)};
let sp_threadlocal_loc = addr.plus(mem::size_of::<MuEntityHeader>())
.plus(mem::size_of::<Box<mm::Mutator>>())
.plus(mem::size_of::<Option<Box<MuStack>>>());
debug!("new sp: 0x{:x}", new_sp);
debug!("sp_store: 0x{:x}", sp_threadlocal_loc);
MuThread::thread_entry(muthread);
unsafe {
swap_to_mu_stack(new_sp, entry, sp_threadlocal_loc);
}
}) {
Ok(handle) => handle,
Err(_) => panic!("failed to create a thread")
}
}
/// entry function for launching a mu thread
#[allow(unused_variables)]
pub fn thread_entry(mu_thread: Box<MuThread>) -> ! {
unimplemented!()
}
}
#[derive(Debug, RustcEncodable, RustcDecodable)]
......
......@@ -520,8 +520,6 @@ impl <'a> VM {
pub extern fn mu_main(serialized_vm : *const c_char) {
debug!("mu_main() started...");
// clone it, otherwise rust allocator will try deallocate
// since the char* points to data section, the deallocation will fail
let str_vm = unsafe{CStr::from_ptr(serialized_vm)}.to_str().unwrap();
let vm : Arc<VM> = Arc::new(VM::resume_vm(str_vm));
......
......@@ -14,14 +14,16 @@ use self::mu::compiler::*;
use test_ir::test_ir::factorial;
use std::sync::Arc;
use std::sync::RwLock;
use std::collections::HashMap;
#[test]
fn test_thread_create() {
let vm = Arc::new(factorial());
let vm = Arc::new(primordial_main());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of("fac");
let func_id = vm.id_of("primordial_main");
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
......@@ -31,6 +33,46 @@ fn test_thread_create() {
compiler.compile(&mut func_ver);
}
vm.make_primordial_thread(func_id, vec![Constant::Int(5)]);
vm.make_primordial_thread(func_id, vec![]);
backend::emit_context(&vm);
}
fn primordial_main() -> VM {
let vm = VM::new();
let sig = vm.declare_func_sig(vm.next_id(), vec![], vec![]);
let func = MuFunction::new(vm.next_id(), sig.clone());
vm.set_name(func.as_entity(), "primordial_main".to_string());
let func_id = func.id();
vm.declare_func(func);
let mut func_ver = MuFunctionVersion::new(vm.next_id(), func_id, sig.clone());
let mut blk_entry = Block::new(vm.next_id());
vm.set_name(blk_entry.as_entity(), "entry".to_string());
let thread_exit = func_ver.new_inst(vm.next_id(), Instruction {
value: None,
ops: RwLock::new(vec![]),
v: Instruction_::ThreadExit
});
let blk_entry_content = BlockContent {
args: vec![],
body: vec![thread_exit],
keepalives: None
};
blk_entry.content = Some(blk_entry_content);
func_ver.define(FunctionContent {
entry: blk_entry.id(),
blocks: {
let mut blocks = HashMap::new();
blocks.insert(blk_entry.id(), blk_entry);
blocks
}
});
vm.define_func_version(func_ver);
vm
}
\ No newline at end of file
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