Commit 1a740b5f authored by qinsoon's avatar qinsoon

deleted empty files (by mistake left a few empty files from previous merge)

parent 692d55df
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use compiler::backend::*;
use utils::Address;
use utils::POINTER_SIZE;
use std::collections::HashMap;
use std::ops::Deref;
use compiler::machine_code::CompiledCallsite;
use runtime::*;
/// runtime function to deal with exception (unwind stack, find catch block, and restore)
/// This function is called by muentry_throw_exception() which gets emitted for THROW instruction
/// With the first argument being the address of the exception object,
/// And the second argument should be point to the base of the call frame of muentry_throw_exception,
/// which saves every callee saved register (note this frame will be modified by this function).
/// e.g. on aarch64 (where the values are the value of the registers immediately before the first
/// instruction in muentry_throw_exception is executed):
/// Return Address (value of X30)
/// frame_cursor --> Frame Pointer (value of X29)
/// First Callee Saved Register (value of X19)
/// .........
/// Last Callee Saved Register (value of D15)
/// The actual offsets of the callee saved registers is determined by get_callee_saved_offset
/// (relative to frame_cursor)
/// The location of Frame Pointer and Return address is architecture dependent
/// (and are accessed by get/set_return_address and get/set_previous_frame and may be passed
/// real frame pointers or the frame cursor)
#[no_mangle]
pub extern fn throw_exception_internal(exception_obj: Address, frame_cursor: Address) -> ! {
trace!("throwing exception: {}", exception_obj);
if cfg!(debug_assertions) {
trace!("Initial Frame: ");
print_frame(frame_cursor);
}
let ref mut cur_thread = thread::MuThread::current_mut();
// set exception object (the catch block will have a landing pad to fetch this object)
cur_thread.exception_obj = exception_obj;
let ref vm = cur_thread.vm;
// this will be 16 bytes bellow the bottom of the previous frame
let mut current_frame_pointer = frame_cursor;
let mut callsite = get_return_address(current_frame_pointer);
// thrower's fp, the starting point of the previous frame
let mut previous_frame_pointer = get_previous_frame_pointer(current_frame_pointer); // thrower::fp, the starting point of the previous frame
// the address of the catch block
let catch_address;
// the stack pointer to restore to
let sp;
{
// acquire lock for exception table
let compiled_callsite_table = vm.compiled_callsite_table.read().unwrap();
loop {
// Lookup the table for the callsite
trace!("Callsite: 0x{:x}", callsite);
trace!("\tprevious_frame_pointer: 0x{:x}", previous_frame_pointer);
trace!("\tcurrent_frame_pointer: 0x{:x}", current_frame_pointer);
let callsite_info = {
let table_entry = compiled_callsite_table.get(&callsite);
if table_entry.is_none() {
// we are not dealing with native frames for unwinding stack
// See Issue #42
error!("Cannot find Mu callsite (i.e. we have reached a native frame), \
either there isn't a catch block to catch the exception or \
your catch block is above a native function call");
// This function may segfault
print_backtrace(frame_cursor, compiled_callsite_table.deref());
panic!("Uncaught Mu Exception");
}
table_entry.unwrap()
};
// Check for a catch block at this callsite (there won't be one on the first iteration of this loop)
if callsite_info.exceptional_destination.is_some() {
catch_address = callsite_info.exceptional_destination.unwrap();
trace!("Found catch block: 0x{:x}", catch_address);
sp = get_previous_stack_pointer(current_frame_pointer, callsite_info.stack_args_size);
trace!("\tRestoring SP to: 0x{:x}", sp);
if cfg!(debug_assertions) {
trace!("Restoring frame: ");
print_frame(frame_cursor);
}
break; // Found a catch block
}
// Restore callee saved registers
unsafe {
for (target_offset, source_offset) in callsite_info.callee_saved_registers.iter() {
// *(frame_cursor + target_offset) = *(frame_pointer + source_offset)
let val = (previous_frame_pointer + *source_offset).load::<Address>();
(frame_cursor + *target_offset).store::<Address>(val);
}
}
// Move up to the previous frame
current_frame_pointer = previous_frame_pointer;
previous_frame_pointer = get_previous_frame_pointer(current_frame_pointer);
// Restore the callsite
callsite = get_return_address(current_frame_pointer);
set_return_address(frame_cursor, callsite);
set_previous_frame_pointer(frame_cursor, previous_frame_pointer);
}
}
// The above loop will only exit when a catch block is found, so restore to it
unsafe { thread::exception_restore(catch_address, frame_cursor.to_ptr(), sp); }
}
/// prints current frame cursor
fn print_frame(cursor: Address) {
let top = 2;
let bottom = -(CALLEE_SAVED_COUNT as isize);
for i in (bottom .. top).rev() {
unsafe {
let addr = cursor + (i * POINTER_SIZE as isize);
let val = addr.load::<Word>();
trace!("\taddr: 0x{:x} | val: 0x{:x} {}", addr, val, {if addr == cursor {"<- cursor"} else {""}});
}
}
}
/// This function may segfault or panic when it reaches the bottom of the stack
// TODO: Determine where the bottom is without segfaulting
fn print_backtrace(base: Address, compiled_callsite_table: &HashMap<Address, CompiledCallsite>) {
error!("BACKTRACE: ");
let cur_thread = thread::MuThread::current();
let ref vm = cur_thread.vm;
// compiled_funcs: RwLock<HashMap<MuID, RwLock<CompiledFunction>>>;
let compiled_funcs = vm.compiled_funcs().read().unwrap();
let mut frame_pointer = base;
let mut frame_count = 0;
loop {
let callsite = get_return_address(frame_pointer);
if compiled_callsite_table.contains_key(&callsite) {
let function_version = compiled_callsite_table.get(&callsite).unwrap().function_version;
let compiled_func = compiled_funcs.get(&function_version).unwrap().read().unwrap();
error!("\tframe {:2}: 0x{:x} - {} (fid: #{}, fvid: #{}) at 0x{:x}", frame_count,
compiled_func.start.to_address(), vm.name_of(compiled_func.func_id),
compiled_func.func_id, compiled_func.func_ver_id, callsite);
} else {
let (func_name, func_start) = get_function_info(callsite);
error!("\tframe {:2}: 0x{:x} - {} at 0x{:x}", frame_count, func_start, func_name, callsite);
}
frame_pointer = get_previous_frame_pointer(frame_pointer);
if frame_pointer.is_zero() {
return;
}
frame_count += 1;
}
}
\ No newline at end of file
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use testutil::*;
use ast::ir::MuName;
use runtime;
use vm::VM;
use compiler::backend;
use std::path::PathBuf;
use std::process::Command;
use std::process::Output;
fn link_executable_internal (files: Vec<PathBuf>, lib: &Vec<String>, libpath: &Vec<String>, out: PathBuf) -> PathBuf {
let mut cc = Command::new(get_test_clang_path());
for file in files {
info!("link with {:?}", file.as_path());
cc.arg(file.as_path());
}
// external libs
for path in libpath.iter() {
cc.arg(format!("-L{}", path));
}
for l in lib.iter() {
cc.arg(format!("-l{}", l));
}
info!("output as {:?}", out.as_path());
if cfg!(target_os = "linux") {
cc.arg("-ldl");
cc.arg("-lrt");
cc.arg("-lm");
cc.arg("-lpthread");
}
// so we can find symbols in itself
cc.arg("-rdynamic");
cc.arg("-o");
cc.arg(out.as_os_str());
assert!(exec(cc).status.success());
out
}
fn link_dylib_internal (files: Vec<PathBuf>, lib: &Vec<String>, libpath: &Vec<String>, out: PathBuf) -> PathBuf {
let mut object_files : Vec<PathBuf> = vec![];
for file in files {
let mut cc = Command::new(get_test_clang_path());
cc.arg("-c");
cc.arg("-fPIC");
let mut out = file.clone();
out.set_extension("o");
cc.arg(file.as_os_str());
cc.arg("-o");
cc.arg(out.as_os_str());
object_files.push(out);
exec(cc);
}
let mut cc = Command::new(get_test_clang_path());
// external libs
for path in libpath.iter() {
cc.arg(format!("-L{}", path));
}
for l in lib.iter() {
cc.arg(format!("-l{}", l));
}
// options
cc.arg("-shared");
cc.arg("-fPIC");
cc.arg("-Wl");
cc.arg("-undefined");
cc.arg("dynamic_lookup");
// all object files
for obj in object_files {
cc.arg(obj.as_os_str());
}
// output
cc.arg("-o");
cc.arg(out.as_os_str());
exec(cc);
out
}
fn get_path_for_mu_func (f: MuName, vm: &VM) -> PathBuf {
let mut ret = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
ret.push(f);
ret.set_extension("s");
ret
}
fn get_path_for_mu_context (vm: &VM) -> PathBuf {
let mut ret = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
ret.push(backend::AOT_EMIT_CONTEXT_FILE);
ret
}
pub fn link_primordial (funcs: Vec<MuName>, out: &str, vm: &VM) -> PathBuf {
let emit_dir = PathBuf::from(&vm.vm_options.flag_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, vm));
}
// mu context
ret.push(get_path_for_mu_context(vm));
// copy primoridal entry
let source = get_path_under_mu(runtime::PRIMORDIAL_ENTRY);
let dest = {
let mut ret = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
ret.push("main.c");
ret
};
trace!("copying from {:?} to {:?}", source, dest);
match fs::copy(source.as_path(), dest.as_path()) {
Ok(_) => {},
Err(e) => panic!("failed to copy: {}", e)
}
// include the primordial C main
ret.push(dest);
// include mu static lib
let libmu_path = if cfg!(debug_assertions) {
"target/debug/libmu.a"
} else {
"target/release/libmu.a"
};
let libmu = get_path_under_mu(libmu_path);
ret.push(libmu);
ret
};
let mut out_path = emit_dir.clone();
out_path.push(out);
link_executable_internal(files,
&vm.vm_options.flag_bootimage_external_lib,
&vm.vm_options.flag_bootimage_external_libpath,
out_path)
}
pub fn execute(executable: PathBuf) -> Output {
let run = Command::new(executable.as_os_str());
exec(run)
}
pub fn execute_nocheck(executable: PathBuf) -> Output {
let run = Command::new(executable.as_os_str());
exec_nocheck(run)
}
pub fn link_dylib (funcs: Vec<MuName>, out: &str, vm: &VM) -> PathBuf {
let files = {
let mut ret = vec![];
for func in funcs {
ret.push(get_path_for_mu_func(func, vm));
}
ret.push(get_path_for_mu_context(vm));
ret
};
let mut out_path = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
out_path.push(out);
link_dylib_internal(files,
&vm.vm_options.flag_bootimage_external_lib,
&vm.vm_options.flag_bootimage_external_libpath,
out_path)
}
pub fn link_dylib_with_extra_srcs(funcs: Vec<MuName>, srcs: Vec<String>, out: &str, vm: &VM) -> PathBuf{
let files = {
let mut ret = vec![];
for func in funcs {
ret.push(get_path_for_mu_func(func, vm));
}
for src in srcs {
ret.push(PathBuf::from(src));
}
ret.push(get_path_for_mu_context(vm));
ret
};
let mut out_path = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
out_path.push(out);
link_dylib_internal(files,
&vm.vm_options.flag_bootimage_external_lib,
&vm.vm_options.flag_bootimage_external_libpath,
out_path)
}
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