Commit f3f82554 authored by qinsoon's avatar qinsoon

[wip] interfacing vm with the GC. still debugging

parent 9cd0463b
......@@ -73,7 +73,7 @@ mu_gc = { path = "src/gc"}
built = "0.1"
[target.x86_64-rumprun-netbsd.dependencies]
mu_gc = { path = "src/gc", features = ["use-sidemap", "sel4-rumprun-target-side"], target = "x86_64-rumprun-netbsd"}
mu_gc = { path = "src/gc", features = ["sel4-rumprun-target-side"], target = "x86_64-rumprun-netbsd"}
[target.aarch64-unknown-linux-gnu.build-dependencies]
built = "0.1"
......
......@@ -26,6 +26,7 @@ use compiler::backend::x86_64::check_op_len;
use compiler::machine_code::MachineCode;
use vm::VM;
use runtime::ValueLocation;
use runtime::mm::*;
use utils::vec_utils;
use utils::string_utils;
......@@ -42,6 +43,8 @@ use std::ops;
use std::collections::HashSet;
use std::sync::{RwLock, Arc};
use std::any::Any;
use std::path;
use std::io::prelude::*;
/// ASMCode represents a segment of assembly machine code. Usually it is machine code for
/// a Mu function, but it could simply be a sequence of machine code.
......@@ -3787,9 +3790,6 @@ use std::fs::File;
/// emit assembly file for a function version
pub fn emit_code(fv: &mut MuFunctionVersion, vm: &VM) {
use std::io::prelude::*;
use std::path;
// acquire lock and function
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&fv.func_id).unwrap().read().unwrap();
......@@ -4034,10 +4034,6 @@ fn mangle_all(name_vec: &mut Vec<String>) {
#[cfg(feature = "sel4-rumprun")]
pub fn emit_sym_table(vm: &VM) {
use std::path;
use std::io::Write;
// Here goes the code to generate an asm file to resolve symbol addresses at link time
// in this stage, a single sym_file is generated for the test
// these sym_files will be compiled in build.rs in the parent directory of sel4 side
......@@ -4167,9 +4163,6 @@ pub fn emit_context_with_reloc(
symbols: HashMap<Address, MuName>,
fields: HashMap<Address, MuName>
) {
use std::path;
use std::io::prelude::*;
// creates emit directy, and file
debug!("---Emit VM Context---");
create_emit_directory(vm);
......@@ -4228,15 +4221,16 @@ pub fn emit_context_with_reloc(
// for all the reachable object, we write them to the boot image
for obj_dump in objects.values() {
// write object metadata
write_align(&mut file, 8);
write_obj_header(&mut file, &obj_dump.encode);
// write object metadata
// .bytes xx,xx,xx,xx (between mem_start to reference_addr)
write_data_bytes(&mut file, obj_dump.mem_start, obj_dump.reference_addr);
// write alignment for the object
write_align(&mut file, obj_dump.align);
// if this object is a global cell, we add labels so it can be accessed
if global_addr_id_map.contains_key(&obj_dump.reference_addr) {
let global_id = global_addr_id_map.get(&obj_dump.reference_addr).unwrap();
if global_addr_id_map.contains_key(&obj_dump.addr) {
let global_id = global_addr_id_map.get(&obj_dump.addr).unwrap();
let global_value = global_lock.get(global_id).unwrap();
// .globl global_cell_name
......@@ -4259,20 +4253,17 @@ pub fn emit_context_with_reloc(
}
// put dump_label for this object (so it can be referred to from other dumped objects)
let dump_label = symbol(&&relocatable_refs
.get(&obj_dump.reference_addr)
.unwrap()
.clone());
let dump_label = symbol(&&relocatable_refs.get(&obj_dump.addr).unwrap().clone());
file.write_fmt(format_args!("{}:\n", dump_label)).unwrap();
// get ready to go through from the object start (not mem_start) to the end
let base = obj_dump.reference_addr;
let end = obj_dump.mem_start + obj_dump.mem_size;
let base = obj_dump.addr;
let end = obj_dump.addr + obj_dump.size;
assert!(base.is_aligned_to(POINTER_SIZE));
// offset as cursor
let mut offset = 0;
while offset < obj_dump.mem_size {
while offset < obj_dump.size {
let cur_addr = base + offset;
if obj_dump.reference_offsets.contains(&offset) {
......@@ -4358,6 +4349,16 @@ pub fn emit_context(vm: &VM) {
emit_context_with_reloc(vm, hashmap!{}, hashmap!{});
}
/// writes header for a dumped object
fn write_obj_header(f: &mut File, obj: &ObjectEncode) {
// header is 8 bytes aligned, and takes 24 bytes
write_align(f, 8);
let hdr = obj.as_raw();
f.write_fmt(format_args!("\t.quad {}\n", hdr[0])).unwrap();
f.write_fmt(format_args!("\t.quad {}\n", hdr[1])).unwrap();
f.write_fmt(format_args!("\t.quad {}\n", hdr[2])).unwrap();
}
/// writes raw bytes from memory between from_address (inclusive) to to_address (exclusive)
fn write_data_bytes(f: &mut File, from: Address, to: Address) {
use std::io::Write;
......
This diff is collapsed.
......@@ -22,8 +22,7 @@ build = "build.rs"
crate-type = ["rlib"]
[features]
default = ["use-sidemap"]
use-sidemap = []
default = []
sel4-rumprun = []
sel4-rumprun-target-side = []
......
// 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.
#![allow(dead_code)]
use std;
use std::u32;
use std::sync::Arc;
use utils::POINTER_SIZE;
use utils::ByteSize;
use utils::math::align_up;
use objectmodel;
pub const GCTYPE_INIT_ID: u32 = u32::MAX;
// Id has size less than the alignment of the others so it needs to go at the end
rodal_struct!(GCType {
alignment,
fix_size,
fix_refs,
var_refs,
var_size,
id
});
#[derive(Debug, Clone)] // size 136, align 8
pub struct GCType {
pub id: u32, // +128
pub alignment: ByteSize, // +0
pub fix_size: ByteSize, // +8
pub fix_refs: Option<RefPattern>, //+16
pub var_refs: Option<RefPattern>, //+64
pub var_size: Option<ByteSize> //+112
}
impl GCType {
pub fn new_fix(
id: u32,
size: ByteSize,
alignment: ByteSize,
fix_refs: Option<RefPattern>
) -> GCType {
GCType {
id: id,
alignment: objectmodel::check_alignment(alignment),
fix_refs: fix_refs,
fix_size: size,
var_refs: None,
var_size: None
}
}
pub fn new_hybrid(
id: u32,
size: ByteSize,
alignment: ByteSize,
fix_refs: Option<RefPattern>,
var_refs: Option<RefPattern>,
var_size: ByteSize
) -> GCType {
GCType {
id: id,
alignment: objectmodel::check_alignment(alignment),
fix_refs: fix_refs,
fix_size: size,
var_refs: var_refs,
var_size: Some(var_size)
}
}
pub fn new_noreftype(size: ByteSize, align: ByteSize) -> GCType {
GCType {
id: GCTYPE_INIT_ID,
alignment: align,
fix_refs: None,
fix_size: size,
var_refs: None,
var_size: None
}
}
pub fn new_reftype() -> GCType {
GCType {
id: GCTYPE_INIT_ID,
alignment: POINTER_SIZE,
fix_refs: Some(RefPattern::Map {
offsets: vec![0],
size: POINTER_SIZE
}),
fix_size: POINTER_SIZE,
var_refs: None,
var_size: None
}
}
#[inline(always)]
pub fn is_hybrid(&self) -> bool {
self.var_size.is_some()
}
pub fn size(&self) -> ByteSize {
self.fix_size
}
pub fn size_hybrid(&self, length: u32) -> ByteSize {
assert!(self.var_size.is_some());
self.fix_size + self.var_size.unwrap() * (length as usize)
}
#[allow(unused_assignments)]
pub fn gen_ref_offsets(&self) -> Vec<ByteSize> {
let mut ret = vec![];
let mut cur_offset = 0;
match self.fix_refs {
Some(ref pattern) => {
cur_offset = pattern.append_offsets(cur_offset, &mut ret);
}
None => {}
}
ret
}
pub fn gen_hybrid_ref_offsets(&self, length: u32) -> Vec<ByteSize> {
debug_assert!(self.is_hybrid());
let mut ret = vec![];
let mut cur_offset = 0;
// fix part
match self.fix_refs {
Some(ref pattern) => {
cur_offset = pattern.append_offsets(cur_offset, &mut ret);
}
None => {}
}
// var part
if self.var_refs.is_some() {
let ref var_part = self.var_refs.as_ref().unwrap();
for _ in 0..length {
cur_offset = var_part.append_offsets(cur_offset, &mut ret);
}
}
ret
}
}
rodal_enum!(RefPattern{{Map: offsets, size}, (NestedType: vec), {Repeat: pattern, count}});
#[derive(Clone, Debug)]
pub enum RefPattern {
// size 40, alignment 8
// discriminat 8 bytes
Map {
offsets: Vec<ByteSize>, // +8
size: usize // +32
},
NestedType(Vec<Arc<GCType>>), // +8
Repeat {
pattern: Box<RefPattern>, // +8
count: usize // +16
}
}
impl RefPattern {
pub fn size(&self) -> ByteSize {
match self {
&RefPattern::Map { size, .. } => size,
&RefPattern::NestedType(ref vec) => {
let mut size = 0;
for ty in vec.iter() {
size += ty.size();
}
size
}
&RefPattern::Repeat { ref pattern, count } => pattern.size() * count
}
}
pub fn append_offsets(&self, base: ByteSize, vec: &mut Vec<ByteSize>) -> ByteSize {
match self {
&RefPattern::Map { ref offsets, size } => {
for off in offsets {
vec.push(base + off);
}
base + size
}
&RefPattern::NestedType(ref types) => {
let mut cur_base = base;
for ty in types {
cur_base = align_up(cur_base, ty.alignment);
let nested_offset = ty.gen_ref_offsets();
let mut nested_offset = nested_offset.iter().map(|x| x + cur_base).collect();
vec.append(&mut nested_offset);
cur_base += ty.size();
}
cur_base
}
&RefPattern::Repeat { ref pattern, count } => {
let mut cur_base = base;
for _ in 0..count {
cur_base = pattern.append_offsets(cur_base, vec);
}
cur_base
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use utils::ByteSize;
fn create_types() -> Vec<GCType> {
// linked list: struct {ref, int64}
let a = GCType {
id: 0,
alignment: 8,
fix_size: 16,
fix_refs: Some(RefPattern::Map {
offsets: vec![0],
size: 16
}),
var_size: None,
var_refs: None
};
// array of struct {ref, int64} with length 10
let b = GCType {
id: 1,
alignment: 8,
fix_size: 160,
fix_refs: Some(RefPattern::Repeat {
pattern: Box::new(RefPattern::Map {
offsets: vec![0],
size: 16
}),
count: 10
}),
var_size: None,
var_refs: None
};
// array(10) of array(10) of struct {ref, int64}
let c = GCType {
id: 2,
alignment: 8,
fix_size: 1600,
fix_refs: Some(RefPattern::Repeat {
pattern: Box::new(RefPattern::NestedType(vec![Arc::new(b.clone()).clone()])),
count: 10
}),
var_size: None,
var_refs: None
};
vec![a, b, c]
}
#[test]
fn test_types() {
create_types();
}
#[test]
fn test_hybrid_type() {
// hybrid { fix: ref, int } { var: int }
let a = GCType {
id: 10,
alignment: 8,
fix_size: 16,
fix_refs: Some(RefPattern::Map {
offsets: vec![0],
size: 16
}),
var_size: Some(8),
var_refs: None
};
assert_eq!(a.gen_hybrid_ref_offsets(5), vec![0]);
assert_eq!(a.size_hybrid(5), 56);
}
#[test]
fn test_hybrid_type2() {
// hybrid { fix: ref, int } { var: ref }
let a = GCType {
id: 10,
alignment: 8,
fix_size: 16,
fix_refs: Some(RefPattern::Map {
offsets: vec![0],
size: 16
}),
var_size: Some(8),
var_refs: Some(RefPattern::Map {
offsets: vec![0],
size: 8
})
};
assert_eq!(a.gen_hybrid_ref_offsets(5), vec![0, 16, 24, 32, 40, 48]);
assert_eq!(a.size_hybrid(5), 56);
}
#[test]
fn test_ref_offsets() {
let vec = create_types();
assert_eq!(vec[0].gen_ref_offsets(), vec![0]);
assert_eq!(vec[1].gen_ref_offsets(), vec![0, 16, 32, 48, 64, 80, 96, 112, 128, 144]);
assert_eq!(vec[2].gen_ref_offsets(), (0..100).map(|x| x * 16).collect::<Vec<ByteSize>>());
let int = GCType {
id: 3,
alignment: 8,
fix_size: 8,
fix_refs: None,
var_size: None,
var_refs: None
};
assert_eq!(int.gen_ref_offsets(), vec![]);
}
}
......@@ -18,7 +18,6 @@ mod bitmap;
mod address_bitmap;
mod address_map;
pub mod ptr;
pub mod gctype;
pub mod objectdump;
pub use self::address_bitmap::AddressBitmap;
......
......@@ -12,10 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use utils::Address;
use utils::ByteSize;
use utils::*;
use objectmodel::*;
use heap::*;
use heap::immix::*;
use heap::freelist::*;
use std::collections::HashMap;
use std::mem::transmute;
pub struct HeapDump {
pub objects: HashMap<Address, ObjectDump>,
......@@ -23,10 +27,10 @@ pub struct HeapDump {
}
pub struct ObjectDump {
pub mem_start: Address,
pub mem_size: ByteSize,
pub reference_addr: Address,
pub addr: Address,
pub size: ByteSize,
pub align: ByteSize,
pub encode: ObjectEncode,
pub reference_offsets: Vec<ByteSize> // based on reference_addr
}
......@@ -56,84 +60,116 @@ impl HeapDump {
heap
}
#[cfg(feature = "use-sidemap")]
#[allow(unused_variables)]
fn persist_object(&self, obj: Address) -> ObjectDump {
unimplemented!()
}
#[cfg(not(feature = "use-sidemap"))]
fn persist_object(&self, obj: Address) -> ObjectDump {
trace!("dump object: {}", obj);
let hdr_addr = obj + objectmodel::OBJECT_HEADER_OFFSET;
let hdr = unsafe { hdr_addr.load::<u64>() };
if objectmodel::header_is_fix_size(hdr) {
// fix sized type
if objectmodel::header_has_ref_map(hdr) {
// has ref map
let ref_map = objectmodel::header_get_ref_map(hdr);
trace!("fix sized, ref map as {:b}", ref_map);
let mut offsets = vec![];
let mut i = 0;
while i < objectmodel::REF_MAP_LENGTH {
let has_ref: bool = ((ref_map >> i) & 1) == 1;
if has_ref {
offsets.push(i * POINTER_SIZE);
match SpaceDescriptor::get(unsafe { obj.to_object_reference() }) {
SpaceDescriptor::ImmixTiny => {
let space = ImmixSpace::get::<ImmixSpace>(obj);
let encode: TinyObjectEncode = unsafe {
space
.get_type_byte_slot(space.get_word_index(obj))
.load::<TinyObjectEncode>()
};
// get a vector of all reference offsets
let mut ref_offsets = vec![];
for i in 0..encode.n_fields() {
if encode.field(i) != WordType::NonRef {
ref_offsets.push(i * POINTER_SIZE);
}
i += 1;
}
ObjectDump {
reference_addr: obj,
mem_start: hdr_addr,
mem_size: objectmodel::header_get_object_size(hdr) as usize +
objectmodel::OBJECT_HEADER_SIZE,
reference_offsets: offsets
addr: obj,
size: encode.size(),
align: MINIMAL_ALIGNMENT,
encode: ObjectEncode::Tiny(encode),
reference_offsets: ref_offsets
}
}
SpaceDescriptor::ImmixNormal => {
let space = ImmixSpace::get::<ImmixSpace>(obj);
let encode: MediumObjectEncode = unsafe {
space
.get_type_byte_slot(space.get_word_index(obj))
.load::<MediumObjectEncode>()
};
let small_encode: &SmallObjectEncode = unsafe { transmute(&encode) };
// get type id
let (type_id, type_size) = if small_encode.is_small() {
(small_encode.type_id(), small_encode.size())
} else {
(encode.type_id(), encode.size())
};
// get type encode, and find all references
let type_encode: &ShortTypeEncode = &GlobalTypeTable::table()[type_id];
let mut ref_offsets = vec![];
let mut offset = 0;
for i in 0..type_encode.fix_len() {
if type_encode.fix_ty(i) != WordType::NonRef {
ref_offsets.push(offset);
}
offset += POINTER_SIZE;
}
if type_encode.var_len() != 0 {
while offset < type_size {
for i in 0..type_encode.var_len() {
if type_encode.var_ty(i) != WordType::NonRef {
ref_offsets.push(offset);
}
offset += POINTER_SIZE;
}
}
}
} else {
// by type ID
let gctype_id = objectmodel::header_get_gctype_id(hdr);
trace!("fix size, type id as {}", gctype_id);
let gc_lock = MY_GC.read().unwrap();
let gctype: Arc<GCType> =
gc_lock.as_ref().unwrap().gc_types[gctype_id as usize].clone();
ObjectDump {
reference_addr: obj,
mem_start: hdr_addr,
mem_size: gctype.size() + objectmodel::OBJECT_HEADER_SIZE,
reference_offsets: gctype.gen_ref_offsets()
addr: obj,
size: type_size,
align: type_encode.align(),
encode: if small_encode.is_small() {
ObjectEncode::Small(small_encode.clone())
} else {
ObjectEncode::Medium(encode)
},
reference_offsets: ref_offsets
}
}
} else {
// hybrids - same as above
let gctype_id = objectmodel::header_get_gctype_id(hdr);
let var_length = objectmodel::header_get_hybrid_length(hdr);
trace!("var sized, type id as {}", gctype_id);
let gc_lock = MY_GC.read().unwrap();
let gctype: Arc<GCType> =
gc_lock.as_ref().unwrap().gc_types[gctype_id as usize].clone();
ObjectDump {
reference_addr: obj,
mem_start: hdr_addr,
mem_size: gctype.size_hybrid(var_length) + objectmodel::OBJECT_HEADER_SIZE,
reference_offsets: gctype.gen_hybrid_ref_offsets(var_length)
SpaceDescriptor::Freelist => {
let space = FreelistSpace::get::<FreelistSpace>(obj);
let encode = unsafe { space.get_type_encode_slot(obj).load::<LargeObjectEncode>() };
let ty_encode = GlobalTypeTable::get_full_type(encode.type_id());
let mut ref_offsets = vec![];
let mut offset: ByteSize = 0;
for &word in ty_encode.fix.iter() {
if word != WordType::NonRef {
ref_offsets.push(offset);
}
offset += POINTER_SIZE;
}
while offset < encode.size() {
for &word in ty_encode.var.iter() {
if word != WordType::NonRef {
ref_offsets.push(offset);
}
offset += POINTER_SIZE;
}
}
ObjectDump {
addr: obj,
size: encode.size(),
align: ty_encode.align,
encode: ObjectEncode::Large(encode),
reference_offsets: ref_offsets
}