Commit d28af85a authored by qinsoon's avatar qinsoon

serialization

parent d3c8e060
......@@ -6,15 +6,59 @@ use utils::vec_utils::as_str as vector_as_str;
use utils::vec_utils;
use std::fmt;
use std::cell::RefCell;
use std::sync::RwLock;
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Instruction {
pub value : Option<Vec<P<Value>>>,
pub ops : RefCell<Vec<P<TreeNode>>>,
pub ops : RwLock<Vec<P<TreeNode>>>,
pub v: Instruction_
}
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
impl Encodable for Instruction {
fn encode<S: Encoder> (&self, s: &mut S) -> Result<(), S::Error> {
s.emit_struct("Instruction", 3, |s| {
try!(s.emit_struct_field("value", 0, |s| self.value.encode(s)));
let ops = &self.ops.read().unwrap();
try!(s.emit_struct_field("ops", 1, |s| ops.encode(s)));
try!(s.emit_struct_field("v", 2, |s| self.v.encode(s)));
Ok(())
})
}
}
impl Decodable for Instruction {
fn decode<D: Decoder>(d: &mut D) -> Result<Instruction, D::Error> {
d.read_struct("Instruction", 3, |d| {
let value = try!(d.read_struct_field("value", 0, |d| Decodable::decode(d)));
let ops = try!(d.read_struct_field("ops", 1, |d| Decodable::decode(d)));
let v = try!(d.read_struct_field("v", 2, |d| Decodable::decode(d)));
Ok(Instruction{
value: value,
ops: RwLock::new(ops),
v: v
})
})
}
}
impl Clone for Instruction {
fn clone(&self) -> Self {
Instruction {
value: self.value.clone(),
ops: RwLock::new(self.ops.read().unwrap().clone()),
v: self.v.clone()
}
}
}
impl Instruction {
fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
self.v.debug_str(ops)
......@@ -23,7 +67,7 @@ impl Instruction {
impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ops = &self.ops.borrow();
let ops = &self.ops.read().unwrap();
if self.value.is_some() {
write!(f, "{} = {}", vector_as_str(self.value.as_ref().unwrap()), self.v.debug_str(ops))
} else {
......@@ -32,7 +76,7 @@ impl fmt::Display for Instruction {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
pub enum Instruction_ {
// non-terminal instruction
......@@ -189,7 +233,7 @@ pub enum Instruction_ {
branches: Vec<(OpIndex, Destination)>
},
ExnInstruction{
inner: P<Instruction>,
inner: Box<Instruction>,
resume: ResumptionData
}
}
......@@ -297,7 +341,7 @@ impl Instruction_ {
}
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum MemoryOrder {
NotAtomic,
Relaxed,
......@@ -308,18 +352,18 @@ pub enum MemoryOrder {
SeqCst
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum CallConvention {
Mu,
Foreign(ForeignFFI)
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum ForeignFFI {
C
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct CallData {
pub func: OpIndex,
pub args: Vec<OpIndex>,
......@@ -332,7 +376,7 @@ impl CallData {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ResumptionData {
pub normal_dest: Destination,
pub exn_dest: Destination
......@@ -344,7 +388,7 @@ impl ResumptionData {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Destination {
pub target: MuID,
pub args: Vec<DestArg>
......@@ -377,7 +421,7 @@ impl Destination {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum DestArg {
Normal(OpIndex),
Freshbound(usize)
......
......@@ -54,7 +54,7 @@ pub fn new_internal_id() -> MuID {
ret
}
#[derive(Debug)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MuFunction {
pub hdr: MuEntityHeader,
......@@ -89,7 +89,7 @@ impl fmt::Display for MuFunction {
}
}
#[derive(Debug)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MuFunctionVersion {
pub hdr: MuEntityHeader,
......@@ -153,8 +153,8 @@ impl MuFunctionVersion {
})
}
pub fn new_inst(&mut self, id: MuID, v: Instruction) -> P<TreeNode> {
P(TreeNode{
pub fn new_inst(&mut self, id: MuID, v: Instruction) -> Box<TreeNode> {
Box::new(TreeNode{
hdr: MuEntityHeader::unnamed(id),
op: pick_op_code_for_inst(&v),
v: TreeNode_::Instruction(v),
......@@ -162,7 +162,7 @@ impl MuFunctionVersion {
}
}
#[derive(Debug)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct FunctionContent {
pub entry: MuID,
pub blocks: HashMap<MuID, Block>
......@@ -195,7 +195,7 @@ impl FunctionContent {
}
}
#[derive(Debug)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct FunctionContext {
pub value_tags: HashMap<MuName, MuID>,
pub values: HashMap<MuID, SSAVarEntry>
......@@ -234,7 +234,7 @@ impl FunctionContext {
}
}
#[derive(Debug)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Block {
pub hdr: MuEntityHeader,
pub content: Option<BlockContent>,
......@@ -247,7 +247,7 @@ impl Block {
}
}
#[derive(Debug)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct ControlFlow {
pub preds : Vec<MuID>,
pub succs : Vec<BlockEdge>
......@@ -286,7 +286,7 @@ impl default::Default for ControlFlow {
}
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BlockEdge {
pub target: MuID,
pub kind: EdgeKind,
......@@ -300,15 +300,15 @@ impl fmt::Display for BlockEdge {
}
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum EdgeKind {
Forward, Backward
}
#[derive(Debug)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlockContent {
pub args: Vec<P<Value>>,
pub body: Vec<P<TreeNode>>,
pub body: Vec<Box<TreeNode>>,
pub keepalives: Option<Vec<P<Value>>>
}
......@@ -321,7 +321,7 @@ impl BlockContent {
match last_inst.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.borrow();
let ops = inst.ops.read().unwrap();
match inst.v {
Instruction_::Return(_)
| Instruction_::ThreadExit
......@@ -383,7 +383,7 @@ impl BlockContent {
}
}
#[derive(Debug)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
/// always use with P<TreeNode>
pub struct TreeNode {
pub hdr: MuEntityHeader,
......@@ -447,14 +447,14 @@ impl fmt::Display for TreeNode {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub enum TreeNode_ {
Value(P<Value>),
Instruction(Instruction)
}
/// always use with P<Value>
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Value {
pub hdr: MuEntityHeader,
pub ty: P<MuType>,
......@@ -528,7 +528,7 @@ impl fmt::Display for Value {
}
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Value_ {
SSAVar(MuID),
Constant(Constant),
......@@ -536,7 +536,7 @@ pub enum Value_ {
Memory(MemoryLocation)
}
#[derive(Debug, Clone)]
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SSAVarEntry {
pub id: MuID,
pub name: Option<MuName>,
......@@ -566,12 +566,12 @@ impl fmt::Display for SSAVarEntry {
}
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Constant {
Int(u64),
Float(f32),
Double(f64),
IRef(Address),
// IRef(Address),
FuncRef(MuID),
UFuncRef(MuID),
Vector(Vec<Constant>),
......@@ -583,7 +583,7 @@ impl fmt::Display for Constant {
&Constant::Int(v) => write!(f, "{}", v),
&Constant::Float(v) => write!(f, "{}", v),
&Constant::Double(v) => write!(f, "{}", v),
&Constant::IRef(v) => write!(f, "{}", v),
// &Constant::IRef(v) => write!(f, "{}", v),
&Constant::FuncRef(v) => write!(f, "{}", v),
&Constant::UFuncRef(v) => write!(f, "{}", v),
&Constant::Vector(ref v) => {
......@@ -600,7 +600,7 @@ impl fmt::Display for Constant {
}
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum MemoryLocation {
Address{
base: P<Value>,
......
......@@ -2,7 +2,7 @@ use ast::ptr::P;
use ast::types::*;
use ast::inst::*;
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum OpCode {
// SSA
RegI64,
......@@ -112,7 +112,7 @@ pub fn pick_op_code_for_value(ty: &P<MuType>) -> OpCode {
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum BinOp {
// Int(n) BinOp Int(n) -> Int(n)
Add,
......@@ -138,7 +138,7 @@ pub enum BinOp {
FRem
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum CmpOp {
// for Int comparison
EQ,
......@@ -171,7 +171,7 @@ pub enum CmpOp {
FUNO
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum AtomicRMWOp {
XCHG,
ADD,
......
......@@ -36,37 +36,28 @@
//! implementation changes (using a special thread-local heap, for example).
//! Moreover, a switch to, e.g. `P<'a, T>` would be easy and mostly automated.
//use std::fmt::{self, Display, Debug};
//use std::hash::{Hash, Hasher};
//use std::ops::Deref;
//use std::ops::DerefMut;
use std::fmt::{self, Display, Debug};
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
use std::sync::Arc;
pub type P<T> = Arc<T>;
use ast::ir::MuEntity;
///// An owned smart pointer.
//pub struct P<T> {
// ptr: Box<T>
pub type P<T> = Arc<T>;
//pub struct P<T: MuEntity> {
// ptr: Arc<T>
//}
#[allow(non_snake_case)]
/// Construct a `P<T>` from a `T` value.
pub fn P<T: 'static>(value: T) -> P<T> {
pub fn P<T: MuEntity>(value: T) -> P<T> {
// P {ptr: Arc::new(value)}
Arc::new(value)
}
//impl<T: 'static> P<T> {
// /// Move out of the pointer.
// /// Intended for chaining transformations not covered by `map`.
// pub fn and_then<U, F>(self, f: F) -> U where
// F: FnOnce(T) -> U,
// {
// f(*self.ptr)
// }
//}
//
//impl<T> Deref for P<T> {
//impl<T: MuEntity> Deref for P<T> {
// type Target = T;
//
// fn deref<'a>(&'a self) -> &'a T {
......@@ -74,45 +65,45 @@ pub fn P<T: 'static>(value: T) -> P<T> {
// }
//}
//
//impl<T> DerefMut for P<T> {
// fn deref_mut<'a>(&'a mut self) -> &'a mut T {
// &mut *self.ptr
// }
//}
//
//impl<T: 'static + Clone> Clone for P<T> {
//impl<T: MuEntity> Clone for P<T> {
// fn clone(&self) -> P<T> {
// P((**self).clone())
// P {ptr: self.ptr.clone()}
// }
//}
//
//impl<T: PartialEq> PartialEq for P<T> {
//impl<T: MuEntity + PartialEq> PartialEq for P<T> {
// fn eq(&self, other: &P<T>) -> bool {
// **self == **other
// }
//}
//
//impl<T: Eq> Eq for P<T> {}
//impl<T: MuEntity + Eq> Eq for P<T> {}
//
//impl<T: Debug> Debug for P<T> {
//impl<T: MuEntity + Debug> Debug for P<T> {
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Debug::fmt(&**self, f)
// }
//}
//impl<T: Display> Display for P<T> {
//impl<T: MuEntity + Display> Display for P<T> {
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Display::fmt(&**self, f)
// }
//}
//
//impl<T> fmt::Pointer for P<T> {
//impl<T: MuEntity> fmt::Pointer for P<T> {
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// fmt::Pointer::fmt(&self.ptr, f)
// }
//}
//
//impl<T: Hash> Hash for P<T> {
//impl<T: MuEntity + Hash> Hash for P<T> {
// fn hash<H: Hasher>(&self, state: &mut H) {
// (**self).hash(state);
// }
//}
//impl<T: MuEntity> Encodable for P<T> {
// fn encode<S: Encoder> (&self, s: &mut S) -> Result<(), S::Error> {
// s.emit_usize(self.id())
// }
//}
\ No newline at end of file
......@@ -8,7 +8,7 @@ use std::sync::RwLock;
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
pub struct MuType {
pub hdr: MuEntityHeader,
pub v: MuType_
......@@ -23,17 +23,7 @@ impl MuType {
}
}
//impl Encodable for MuType {
// fn encode<S: Encoder> (&self, s: &mut S) -> Result<(), S::Error> {
// //serialize 2 fields
// s.emit_struct("MuType", 2, |s| {
// // hdr
// try!(s.emit_struct_field("hdr", 0, |s| hdr.encode(s)));
// })
// }
//}
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
pub enum MuType_ {
/// int <length>
Int (usize),
......@@ -117,7 +107,7 @@ lazy_static! {
pub static ref STRUCT_TAG_MAP : RwLock<HashMap<MuName, StructType_>> = RwLock::new(HashMap::new());
}
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
pub struct StructType_ {
tys: Vec<P<MuType>>
}
......@@ -335,7 +325,7 @@ macro_rules! is_type (
)
);
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
pub struct MuFuncSig {
pub hdr: MuEntityHeader,
pub ret_tys : Vec<P<MuType>>,
......
......@@ -38,7 +38,7 @@ impl <'a> InstructionSelection {
// 3. we need to backup/restore all the callee-saved registers
// if any of these assumption breaks, we will need to re-emit the code
#[allow(unused_variables)]
fn instruction_select(&mut self, node: &'a P<TreeNode>, cur_func: &MuFunctionVersion, vm: &VM) {
fn instruction_select(&mut self, node: &'a TreeNode, cur_func: &MuFunctionVersion, vm: &VM) {
trace!("instsel on node {}", node);
match node.v {
......@@ -55,7 +55,7 @@ impl <'a> InstructionSelection {
}
};
let ops = inst.ops.borrow();
let ops = inst.ops.read().unwrap();
self.process_dest(&ops, fallthrough_dest, cur_func, vm);
self.process_dest(&ops, branch_dest, cur_func, vm);
......@@ -94,7 +94,7 @@ impl <'a> InstructionSelection {
},
Instruction_::Branch1(ref dest) => {
let ops = inst.ops.borrow();
let ops = inst.ops.read().unwrap();
self.process_dest(&ops, dest, cur_func, vm);
......@@ -108,7 +108,7 @@ impl <'a> InstructionSelection {
Instruction_::ExprCall{ref data, is_abort} => {
trace!("deal with pre-call convention");
let ops = inst.ops.borrow();
let ops = inst.ops.read().unwrap();
let rets = inst.value.as_ref().unwrap();
let ref func = ops[data.func];
let ref func_sig = match func.v {
......@@ -206,7 +206,7 @@ impl <'a> InstructionSelection {
},
Instruction_::BinOp(op, op1, op2) => {
let ops = inst.ops.borrow();
let ops = inst.ops.read().unwrap();
match op {
op::BinOp::Add => {
......@@ -352,7 +352,7 @@ impl <'a> InstructionSelection {
// load on x64 generates mov inst (no matter what order is specified)
// https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
Instruction_::Load{is_ptr, order, mem_loc} => {
let ops = inst.ops.borrow();
let ops = inst.ops.read().unwrap();
let ref loc_op = ops[mem_loc];
// check order
......@@ -377,7 +377,7 @@ impl <'a> InstructionSelection {
}
Instruction_::Store{is_ptr, order, mem_loc, value} => {
let ops = inst.ops.borrow();
let ops = inst.ops.read().unwrap();
let ref loc_op = ops[mem_loc];
let ref val_op = ops[value];
......@@ -504,7 +504,7 @@ impl <'a> InstructionSelection {
// FIXME: this may change in the future
// prepare return regs
let ref ops = ret_inst.ops.borrow();
let ref ops = ret_inst.ops.read().unwrap();
let ret_val_indices = match ret_inst.v {
Instruction_::Return(ref vals) => vals,
_ => panic!("expected ret inst")
......@@ -556,7 +556,7 @@ impl <'a> InstructionSelection {
fn emit_cmp_res(&mut self, cond: &P<TreeNode>, cur_func: &MuFunctionVersion, vm: &VM) -> op::CmpOp {
match cond.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.borrow();
let ops = inst.ops.read().unwrap();
match inst.v {
Instruction_::CmpOp(op, op1, op2) => {
......@@ -591,7 +591,7 @@ impl <'a> InstructionSelection {
}
}
fn match_ireg(&mut self, op: &P<TreeNode>) -> bool {
fn match_ireg(&mut self, op: &TreeNode) -> bool {
match op.v {
TreeNode_::Instruction(ref inst) => {
if inst.value.is_some() {
......@@ -737,7 +737,7 @@ impl <'a> InstructionSelection {
unimplemented!()
}
fn emit_get_result(&mut self, node: &P<TreeNode>) -> P<Value> {
fn emit_get_result(&mut self, node: &TreeNode) -> P<Value> {
match node.v {
TreeNode_::Instruction(ref inst) => {
if inst.value.is_some() {
......@@ -817,7 +817,7 @@ impl CompilerPass for InstructionSelection {
self.backend.set_block_liveout(block_label.clone(), &live_out);
for inst in block_content.body.iter() {
self.instruction_select(inst, func, vm);
self.instruction_select(&inst, func, vm);
}
self.backend.end_block(block_label);
......
......@@ -147,12 +147,12 @@ fn layout_struct(tys: &Vec<P<MuType>>, vm: &VM) -> BackendTypeInfo {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BackendTypeInfo {
size: ByteSize,
alignment: ByteSize,
struct_layout: Option<Vec<ByteSize>>
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum RegGroup {GPR, FPR}
......@@ -54,7 +54,7 @@ impl CompilerPass for DefUse {
// if an SSA appears in operands of instrs, its use count increases
match node.v {
TreeNode_::Instruction(ref inst) => {
for op in inst.ops.borrow().iter() {
for op in inst.ops.read().unwrap().iter() {
use_op(op, func_context);
}
},
......
......@@ -49,7 +49,7 @@ impl CompilerPass for TreeGen {
{
trace!("check if we can replace any operand with inst");
let mut ops = inst.ops.borrow_mut();
let mut ops = inst.ops.write().unwrap();
for index in 0..ops.len() {
let possible_ssa_id = ops[index].extract_ssa_id();
if possible_ssa_id.is_some() {
......
......@@ -213,6 +213,7 @@ impl MuThread {
}
}
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MuPrimordialThread {
pub func_id: MuID,
pub args: Vec<Constant>
......
This diff is collapsed.
extern crate rustc_serialize;
use test_ir::test_ir::factorial;
use mu::ast::ir::*;
use mu::vm::*;
use std::sync::Arc;
......@@ -16,4 +15,41 @@ fn test_vm_serialize_factorial() {
let serialized = json::encode(&vm).unwrap();
println!("{}", serialized);
let reconstruct_vm : VM = json::decode(&serialized).unwrap();
let serialized_again = json::encode(&reconstruct_vm).unwrap();
println!("{}", serialized_again);
// check_string_eq_char_by_char(serialized, serialized_again);
}
#[allow(dead_code)]
fn check_string_eq_char_by_char(str1: String, str2: String) {
use std::cmp;
let min_len = cmp::min(str1.len(), str2.len());
println!("str1_len = {}, str2_len = {}", str1.len(), str2.len());
let b1 = str1.into_bytes();
let b2 = str2.into_bytes();
for i in 0..min_len {
if b1[i] != b2[i] {
println!("different here ({}):", i);
print!("str1: ..");
for j in 0..20 {
print!("{}", b1[i + j] as char);
}
println!("..");
print!("str2: ..");
for j in 0..20 {
print!("{}", b2[i + j] as char);
}
println!("..");
panic!("found difference in two strings");
}
}
}
\ No newline at end of file
......@@ -29,7 +29,7 @@ fn test_global_access() {
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.id(), func.cur_ver.unwrap())).unwrap().write().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
backend::emit_context(&vm);
......
......@@ -26,7 +26,7 @@ fn test_instsel_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.id(), func.cur_ver.unwrap())).unwrap().write().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
......@@ -23,7 +23,7 @@ fn test_use_count() {
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.id(), func.cur_ver.unwrap())).unwrap().write().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);