To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

Commit 49e961dd authored by Isaac Oscar Gariano's avatar Isaac Oscar Gariano
Browse files

Converted line endings to UNIX style

parent 83f6e292
......@@ -7,7 +7,7 @@ Cargo.lock
*.log
*.DS_Store
*.swp
.idea
.idea
*.pyc
*.o
*.dylib
......
use ptr::P;
use types::*;
use inst::*;
use op::*;
use utils::vec_utils;
use utils::LinkedHashMap;
use utils::LinkedHashSet;
use std::fmt;
use std::default;
use std::sync::RwLock;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
pub type WPID = usize;
pub type MuID = usize;
pub type MuName = String;
pub type CName = MuName;
#[allow(non_snake_case)]
pub fn Mu(str: &'static str) -> MuName {str.to_string()}
#[allow(non_snake_case)]
pub fn C(str: &'static str) -> CName {str.to_string()}
pub type OpIndex = usize;
lazy_static! {
pub static ref MACHINE_ID : AtomicUsize = {
let a = ATOMIC_USIZE_INIT;
a.store(MACHINE_ID_START, Ordering::SeqCst);
a
};
pub static ref INTERNAL_ID : AtomicUsize = {
let a = ATOMIC_USIZE_INIT;
a.store(INTERNAL_ID_START, Ordering::SeqCst);
a
};
}
pub const MACHINE_ID_START : usize = 0;
pub const MACHINE_ID_END : usize = 200;
pub const INTERNAL_ID_START: usize = 201;
pub const INTERNAL_ID_END : usize = 500;
pub const USER_ID_START : usize = 1001;
#[deprecated]
#[allow(dead_code)]
/// it could happen that one same machine register get different IDs
/// during serialization and restoring
/// currently I hand-write fixed ID for each machine register
pub fn new_machine_id() -> MuID {
let ret = MACHINE_ID.fetch_add(1, Ordering::SeqCst);
if ret >= MACHINE_ID_END {
panic!("machine id overflow")
}
ret
}
pub fn new_internal_id() -> MuID {
let ret = INTERNAL_ID.fetch_add(1, Ordering::SeqCst);
if ret >= INTERNAL_ID_END {
panic!("internal id overflow")
}
ret
}
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MuFunction {
pub hdr: MuEntityHeader,
pub sig: P<MuFuncSig>,
pub cur_ver: Option<MuID>,
pub all_vers: Vec<MuID>
}
impl MuFunction {
pub fn new(id: MuID, sig: P<MuFuncSig>) -> MuFunction {
MuFunction {
hdr: MuEntityHeader::unnamed(id),
sig: sig,
cur_ver: None,
all_vers: vec![]
}
}
pub fn new_version(&mut self, fv: MuID) {
if self.cur_ver.is_some() {
let obsolete_ver = self.cur_ver.unwrap();
self.all_vers.push(obsolete_ver);
}
self.cur_ver = Some(fv);
}
}
impl fmt::Display for MuFunction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Func {}", self.hdr)
}
}
#[derive(RustcEncodable, RustcDecodable)]
pub struct MuFunctionVersion {
pub hdr: MuEntityHeader,
pub func_id: MuID,
pub sig: P<MuFuncSig>,
orig_content: Option<FunctionContent>,
pub content: Option<FunctionContent>,
is_defined: bool,
is_compiled: bool,
pub context: FunctionContext,
pub force_inline: bool,
pub block_trace: Option<Vec<MuID>> // only available after Trace Generation Pass
}
impl fmt::Display for MuFunctionVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FuncVer {} of Func #{}", self.hdr, self.func_id)
}
}
impl fmt::Debug for MuFunctionVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FuncVer {} of Func #{}\n", self.hdr, self.func_id).unwrap();
write!(f, "Signature: {}\n", self.sig).unwrap();
write!(f, "IR:\n").unwrap();
if self.content.is_some() {
write!(f, "{:?}\n", self.content.as_ref().unwrap()).unwrap();
} else {
write!(f, "Empty\n").unwrap();
}
if self.block_trace.is_some() {
write!(f, "Block Trace: {:?}\n", self.block_trace.as_ref().unwrap())
} else {
write!(f, "Trace not available\n")
}
}
}
impl MuFunctionVersion {
pub fn new(id: MuID, func: MuID, sig: P<MuFuncSig>) -> MuFunctionVersion {
MuFunctionVersion{
hdr: MuEntityHeader::unnamed(id),
func_id: func,
sig: sig,
orig_content: None,
content: None,
is_defined: false,
is_compiled: false,
context: FunctionContext::new(),
block_trace: None,
force_inline: false
}
}
pub fn new_(hdr: MuEntityHeader, id: MuID, sig: P<MuFuncSig>, content: FunctionContent, context: FunctionContext) -> MuFunctionVersion {
MuFunctionVersion {
hdr: hdr,
func_id: id,
sig: sig,
orig_content: Some(content.clone()),
content: Some(content),
is_defined: true,
is_compiled: false,
context: context,
block_trace: None,
force_inline: false
}
}
pub fn get_orig_ir(&self) -> Option<&FunctionContent> {
self.orig_content.as_ref()
}
pub fn define(&mut self, content: FunctionContent) {
if self.is_defined {
panic!("alread defined the function: {}", self);
}
self.is_defined = true;
self.orig_content = Some(content.clone());
self.content = Some(content);
}
pub fn is_compiled(&self) -> bool {
self.is_compiled
}
pub fn set_compiled(&mut self) {
self.is_compiled = true;
}
pub fn new_ssa(&mut self, id: MuID, ty: P<MuType>) -> P<TreeNode> {
let val = P(Value{
hdr: MuEntityHeader::unnamed(id),
ty: ty,
v: Value_::SSAVar(id)
});
self.context.values.insert(id, SSAVarEntry::new(val.clone()));
P(TreeNode {
op: pick_op_code_for_ssa(&val.ty),
v: TreeNode_::Value(val)
})
}
pub fn new_constant(&mut self, v: P<Value>) -> P<TreeNode> {
P(TreeNode{
op: pick_op_code_for_value(&v.ty),
v: TreeNode_::Value(v)
})
}
pub fn new_global(&mut self, v: P<Value>) -> P<TreeNode> {
P(TreeNode{
op: pick_op_code_for_value(&v.ty),
v: TreeNode_::Value(v)
})
}
pub fn new_inst(&mut self, v: Instruction) -> Box<TreeNode> {
Box::new(TreeNode{
op: pick_op_code_for_inst(&v),
v: TreeNode_::Instruction(v),
})
}
/// get Map(CallSiteID -> FuncID) that are called by this function
pub fn get_static_call_edges(&self) -> LinkedHashMap<MuID, MuID> {
let mut ret = LinkedHashMap::new();
let f_content = self.content.as_ref().unwrap();
for (_, block) in f_content.blocks.iter() {
let block_content = block.content.as_ref().unwrap();
for inst in block_content.body.iter() {
match inst.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.read().unwrap();
match inst.v {
Instruction_::ExprCall{ref data, ..}
| Instruction_::ExprCCall{ref data, ..}
| Instruction_::Call {ref data, ..}
| Instruction_::CCall {ref data, ..} => {
let ref callee = ops[data.func];
match callee.v {
TreeNode_::Instruction(_) => {},
TreeNode_::Value(ref pv) => match pv.v {
Value_::Constant(Constant::FuncRef(id)) => {ret.insert(inst.id(), id);},
_ => {}
}
}
},
_ => {
// do nothing
}
}
},
_ => {
unreachable!()
}
}
}
}
ret
}
pub fn has_throw(&self) -> bool {
let f_content = self.content.as_ref().unwrap();
for (_, block) in f_content.blocks.iter() {
let block_content = block.content.as_ref().unwrap();
for inst in block_content.body.iter() {
match inst.v {
TreeNode_::Instruction(ref inst) => {
match inst.v {
Instruction_::Throw(_) => {return true;}
_ => {
// do nothing
}
}
},
_ => {
unreachable!()
}
}
}
}
false
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct FunctionContent {
pub entry: MuID,
pub blocks: LinkedHashMap<MuID, Block>,
// this field only valid after control flow analysis
pub exception_blocks: LinkedHashSet<MuID>
}
impl fmt::Debug for FunctionContent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let entry = self.get_entry_block();
write!(f, "Entry block: ").unwrap();
write!(f, "{:?}\n", entry).unwrap();
write!(f, "Body:").unwrap();
for blk_id in self.blocks.keys() {
let block = self.get_block(*blk_id);
write!(f, "{:?}\n", block).unwrap();
}
Ok(())
}
}
impl FunctionContent {
pub fn new(entry: MuID, blocks: LinkedHashMap<MuID, Block>) -> FunctionContent {
FunctionContent {
entry: entry,
blocks: blocks,
exception_blocks: LinkedHashSet::new()
}
}
pub fn get_entry_block(&self) -> &Block {
self.get_block(self.entry)
}
pub fn get_entry_block_mut(&mut self) -> &mut Block {
let entry = self.entry;
self.get_block_mut(entry)
}
pub fn get_block(&self, id: MuID) -> &Block {
let ret = self.blocks.get(&id);
match ret {
Some(b) => b,
None => panic!("cannot find block #{}", id)
}
}
pub fn get_block_mut(&mut self, id: MuID) -> &mut Block {
let ret = self.blocks.get_mut(&id);
match ret {
Some(b) => b,
None => panic!("cannot find block #{}", id)
}
}
}
#[derive(Default, Debug, RustcEncodable, RustcDecodable)]
pub struct FunctionContext {
pub values: LinkedHashMap<MuID, SSAVarEntry>
}
impl FunctionContext {
fn new() -> FunctionContext {
FunctionContext {
values: LinkedHashMap::new()
}
}
pub fn make_temporary(&mut self, id: MuID, ty: P<MuType>) -> P<TreeNode> {
let val = P(Value{
hdr: MuEntityHeader::unnamed(id),
ty: ty,
v: Value_::SSAVar(id)
});
self.values.insert(id, SSAVarEntry::new(val.clone()));
P(TreeNode {
op: pick_op_code_for_ssa(&val.ty),
v: TreeNode_::Value(val)
})
}
pub fn get_temp_display(&self, id: MuID) -> String {
match self.get_value(id) {
Some(entry) => format!("{}", entry.value()),
None => "CANT_FOUND_ID".to_string()
}
}
pub fn get_value(&self, id: MuID) -> Option<&SSAVarEntry> {
self.values.get(&id)
}
pub fn get_value_mut(&mut self, id: MuID) -> Option<&mut SSAVarEntry> {
self.values.get_mut(&id)
}
}
#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct Block {
pub hdr: MuEntityHeader,
pub content: Option<BlockContent>,
pub control_flow: ControlFlow
}
impl fmt::Debug for Block {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "Block {}", self.hdr).unwrap();
writeln!(f, "with preds: {:?}", self.control_flow.preds).unwrap();
writeln!(f, " succs: {:?}", self.control_flow.succs).unwrap();
if self.content.is_some() {
writeln!(f, "{:?}", self.content.as_ref().unwrap()).unwrap();
} else {
writeln!(f, "Empty").unwrap();
}
Ok(())
}
}
impl Block {
pub fn new(id: MuID) -> Block {
Block{hdr: MuEntityHeader::unnamed(id), content: None, control_flow: ControlFlow::default()}
}
pub fn is_receiving_exception_arg(&self) -> bool {
return self.content.as_ref().unwrap().exn_arg.is_some()
}
pub fn number_of_irs(&self) -> usize {
if self.content.is_none() {
0
} else {
let content = self.content.as_ref().unwrap();
content.body.len()
}
}
}
#[derive(Debug, RustcEncodable, RustcDecodable, Clone)]
pub struct ControlFlow {
pub preds : Vec<MuID>,
pub succs : Vec<BlockEdge>
}
impl ControlFlow {
pub fn get_hottest_succ(&self) -> Option<MuID> {
if self.succs.len() == 0 {
None
} else {
let mut hot_blk = self.succs[0].target;
let mut hot_prob = self.succs[0].probability;
for edge in self.succs.iter() {
if edge.probability > hot_prob {
hot_blk = edge.target;
hot_prob = edge.probability;
}
}
Some(hot_blk)
}
}
}
impl fmt::Display for ControlFlow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "preds: [{}], ", vec_utils::as_str(&self.preds)).unwrap();
write!(f, "succs: [{}]", vec_utils::as_str(&self.succs))
}
}
impl default::Default for ControlFlow {
fn default() -> ControlFlow {
ControlFlow {preds: vec![], succs: vec![]}
}
}
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BlockEdge {
pub target: MuID,
pub kind: EdgeKind,
pub is_exception: bool,
pub probability: f32
}
impl fmt::Display for BlockEdge {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ({:?}{} - {})", self.target, self.kind, select_value!(self.is_exception, ", exceptional", ""), self.probability)
}
}
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum EdgeKind {
Forward, Backward
}
#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct BlockContent {
pub args: Vec<P<Value>>,
pub exn_arg: Option<P<Value>>,
pub body: Vec<Box<TreeNode>>,
pub keepalives: Option<Vec<P<Value>>>
}
impl fmt::Debug for BlockContent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "args: {}", vec_utils::as_str(&self.args)).unwrap();
if self.exn_arg.is_some() {
writeln!(f, "exception arg: {}", self.exn_arg.as_ref().unwrap()).unwrap();
}
if self.keepalives.is_some() {
writeln!(f, "keepalives: {}", vec_utils::as_str(self.keepalives.as_ref().unwrap())).unwrap();
}
for node in self.body.iter() {
writeln!(f, "{}", node).unwrap();
}
Ok(())
}
}
impl BlockContent {
pub fn get_out_arguments(&self) -> Vec<P<Value>> {
let n_insts = self.body.len();
let ref last_inst = self.body[n_insts - 1];
let mut ret : Vec<P<Value>> = vec![];
match last_inst.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.read().unwrap();
match inst.v {
Instruction_::Return(_)
| Instruction_::ThreadExit
| Instruction_::Throw(_)
| Instruction_::TailCall(_) => {
// they do not have explicit liveouts
}
Instruction_::Branch1(ref dest) => {
let mut live_outs = dest.get_arguments(&ops);
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::Branch2{ref true_dest, ref false_dest, ..} => {
let mut live_outs = true_dest.get_arguments(&ops);
live_outs.append(&mut false_dest.get_arguments(&ops));
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::Watchpoint{ref disable_dest, ref resume, ..} => {
let mut live_outs = vec![];
if disable_dest.is_some() {
live_outs.append(&mut disable_dest.as_ref().unwrap().get_arguments(&ops));
}
live_outs.append(&mut resume.normal_dest.get_arguments(&ops));
live_outs.append(&mut resume.exn_dest.get_arguments(&ops));
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::WPBranch{ref disable_dest, ref enable_dest, ..} => {
let mut live_outs = vec![];
live_outs.append(&mut disable_dest.get_arguments(&ops));
live_outs.append(&mut enable_dest.get_arguments(&ops));
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::Call{ref resume, ..}
| Instruction_::CCall{ref resume, ..}
| Instruction_::SwapStack{ref resume, ..}
| Instruction_::ExnInstruction{ref resume, ..} => {
let mut live_outs = vec![];
live_outs.append(&mut resume.normal_dest.get_arguments(&ops));
live_outs.append(&mut resume.exn_dest.get_arguments(&ops));
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::Switch{ref default, ref branches, ..} => {
let mut live_outs = vec![];
live_outs.append(&mut default.get_arguments(&ops));
for &(_, ref dest) in branches {
live_outs.append(&mut dest.get_arguments(&ops));
}
vec_utils::append_unique(&mut ret, &mut live_outs);