WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

inst.rs 14.8 KB
Newer Older
qinsoon's avatar
qinsoon committed
1
2
3
4
5
use ir::*;
use ptr::*;
use types::*;
use op::*;

6
use utils::vec_utils;
7
8

use std::fmt;
qinsoon's avatar
qinsoon committed
9
use std::sync::RwLock;
10

qinsoon's avatar
qinsoon committed
11
#[derive(Debug)]
12
pub struct Instruction {
qinsoon's avatar
qinsoon committed
13
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
14
    pub value : Option<Vec<P<Value>>>,
qinsoon's avatar
qinsoon committed
15
    pub ops : RwLock<Vec<P<TreeNode>>>,
16
17
18
    pub v: Instruction_
}

qinsoon's avatar
qinsoon committed
19
20
impl_mu_entity!(Instruction);

qinsoon's avatar
qinsoon committed
21
22
23
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
impl Encodable for Instruction {
    fn encode<S: Encoder> (&self, s: &mut S) -> Result<(), S::Error> {
qinsoon's avatar
qinsoon committed
24
25
26
        s.emit_struct("Instruction", 4, |s| {
            try!(s.emit_struct_field("hdr", 0, |s| self.hdr.encode(s)));
            try!(s.emit_struct_field("value", 1, |s| self.value.encode(s)));
qinsoon's avatar
qinsoon committed
27
28
            
            let ops = &self.ops.read().unwrap();
qinsoon's avatar
qinsoon committed
29
            try!(s.emit_struct_field("ops", 2, |s| ops.encode(s)));
qinsoon's avatar
qinsoon committed
30
            
qinsoon's avatar
qinsoon committed
31
            try!(s.emit_struct_field("v", 3, |s| self.v.encode(s)));
qinsoon's avatar
qinsoon committed
32
33
34
35
36
37
38
39
            
            Ok(()) 
        })        
    }
}

impl Decodable for Instruction {
    fn decode<D: Decoder>(d: &mut D) -> Result<Instruction, D::Error> {
qinsoon's avatar
qinsoon committed
40
41
42
        d.read_struct("Instruction", 4, |d| {
            let hdr = try!(d.read_struct_field("hdr", 0, |d| Decodable::decode(d)));
            let value = try!(d.read_struct_field("value", 1, |d| Decodable::decode(d)));
qinsoon's avatar
qinsoon committed
43
            
qinsoon's avatar
qinsoon committed
44
            let ops = try!(d.read_struct_field("ops", 2, |d| Decodable::decode(d)));
qinsoon's avatar
qinsoon committed
45
            
qinsoon's avatar
qinsoon committed
46
            let v = try!(d.read_struct_field("v", 3, |d| Decodable::decode(d)));
qinsoon's avatar
qinsoon committed
47
48
            
            Ok(Instruction{
qinsoon's avatar
qinsoon committed
49
                hdr: hdr,
qinsoon's avatar
qinsoon committed
50
51
52
53
54
55
56
57
58
59
60
                value: value,
                ops: RwLock::new(ops),
                v: v
            })
        })
    }
}

impl Clone for Instruction {
    fn clone(&self) -> Self {
        Instruction {
qinsoon's avatar
qinsoon committed
61
            hdr: self.hdr.clone(),
qinsoon's avatar
qinsoon committed
62
63
64
65
66
67
68
            value: self.value.clone(),
            ops: RwLock::new(self.ops.read().unwrap().clone()),
            v: self.v.clone()
        }
    }
}

69
70
71
72
73
74
75
76
impl Instruction {
    fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
        self.v.debug_str(ops)
    }
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
77
        let ops = &self.ops.read().unwrap();
78
        if self.value.is_some() {
qinsoon's avatar
qinsoon committed
79
            write!(f, "{} = {}", vec_utils::as_str(self.value.as_ref().unwrap()), self.v.debug_str(ops))
80
81
82
83
84
85
        } else {
            write!(f, "{}", self.v.debug_str(ops))
        }
    }
}

qinsoon's avatar
qinsoon committed
86
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
87
88
pub enum Instruction_ {
    // non-terminal instruction
qinsoon's avatar
qinsoon committed
89

90
    // expressions
qinsoon's avatar
qinsoon committed
91
92

    BinOp(BinOp, OpIndex, OpIndex),
93
    CmpOp(CmpOp, OpIndex, OpIndex),
94
95
96
97
98
99
    ConvOp{
        operation: ConvOp,
        from_ty: P<MuType>,
        to_ty: P<MuType>,
        operand: OpIndex
    },
qinsoon's avatar
qinsoon committed
100

101
102
103
    // yields a tuple of results from the call
    ExprCall{
        data: CallData,
qinsoon's avatar
qinsoon committed
104
        is_abort: bool, // T to abort, F to rethrow - FIXME: current, always rethrow for now
105
    },
qinsoon's avatar
qinsoon committed
106

qinsoon's avatar
qinsoon committed
107
108
109
110
111
    ExprCCall{
        data: CallData,
        is_abort: bool
    },

112
113
114
115
116
117
    // yields the memory value
    Load{
        is_ptr: bool,
        order: MemoryOrder,
        mem_loc: OpIndex
    },
qinsoon's avatar
qinsoon committed
118

119
120
121
    // yields nothing
    Store{
        is_ptr: bool,
qinsoon's avatar
qinsoon committed
122
        order: MemoryOrder,
123
124
125
        mem_loc: OpIndex,
        value: OpIndex
    },
qinsoon's avatar
qinsoon committed
126

127
128
129
130
131
132
133
134
135
136
    // yields pair (oldvalue, boolean (T = success, F = failure))
    CmpXchg{
        is_ptr: bool,
        is_weak: bool,
        success_order: MemoryOrder,
        fail_order: MemoryOrder,
        mem_loc: OpIndex,
        expected_value: OpIndex,
        desired_value: OpIndex
    },
qinsoon's avatar
qinsoon committed
137

138
139
140
141
142
143
144
145
    // yields old memory value
    AtomicRMW{
        is_ptr: bool, // T for iref, F for ptr
        order: MemoryOrder,
        op: AtomicRMWOp,
        mem_loc: OpIndex,
        value: OpIndex // operand for op
    },
qinsoon's avatar
qinsoon committed
146

147
148
    // yields a reference of the type
    New(P<MuType>),
qinsoon's avatar
qinsoon committed
149

150
151
    // yields an iref of the type
    AllocA(P<MuType>),
qinsoon's avatar
qinsoon committed
152

153
154
    // yields ref
    NewHybrid(P<MuType>, OpIndex),
qinsoon's avatar
qinsoon committed
155

156
157
    // yields iref
    AllocAHybrid(P<MuType>, OpIndex),
qinsoon's avatar
qinsoon committed
158

159
160
161
    // yields stack ref
    NewStack(OpIndex), // func
                           // TODO: common inst
qinsoon's avatar
qinsoon committed
162

163
164
    // yields thread reference
    NewThread(OpIndex, Vec<OpIndex>), // stack, args
qinsoon's avatar
qinsoon committed
165

166
167
    // yields thread reference (thread resumes with exceptional value)
    NewThreadExn(OpIndex, OpIndex), // stack, exception
qinsoon's avatar
qinsoon committed
168

169
170
    // yields frame cursor
    NewFrameCursor(OpIndex), // stack
qinsoon's avatar
qinsoon committed
171

172
173
    // ref<T> -> iref<T>
    GetIRef(OpIndex),
qinsoon's avatar
qinsoon committed
174

175
176
177
178
    // iref|uptr<struct|hybrid<T>> int<M> -> iref|uptr<U>
    GetFieldIRef{
        is_ptr: bool,
        base: OpIndex, // iref or uptr
179
        index: usize // constant
180
    },
qinsoon's avatar
qinsoon committed
181

182
183
184
185
186
187
    // iref|uptr<array<T N>> int<M> -> iref|uptr<T>
    GetElementIRef{
        is_ptr: bool,
        base: OpIndex,
        index: OpIndex // can be constant or ssa var
    },
qinsoon's avatar
qinsoon committed
188

189
190
191
192
193
194
    // iref|uptr<T> int<M> -> iref|uptr<T>
    ShiftIRef{
        is_ptr: bool,
        base: OpIndex,
        offset: OpIndex
    },
qinsoon's avatar
qinsoon committed
195

196
197
198
199
200
    // iref|uptr<hybrid<T U>> -> iref|uptr<U>
    GetVarPartIRef{
        is_ptr: bool,
        base: OpIndex
    },
qinsoon's avatar
qinsoon committed
201

202
203
204
205
206
207
208
209
210
//    PushFrame{
//        stack: P<Value>,
//        func: P<Value>
//    },
//    PopFrame{
//        stack: P<Value>
//    }

    Fence(MemoryOrder),
qinsoon's avatar
qinsoon committed
211

212
213
214
    // terminal instruction
    Return(Vec<OpIndex>),
    ThreadExit, // TODO:  common inst
215
    Throw(OpIndex),
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
    TailCall(CallData),
    Branch1(Destination),
    Branch2{
        cond: OpIndex,
        true_dest: Destination,
        false_dest: Destination,
        true_prob: f32
    },
    Watchpoint{ // Watchpoint NONE ResumptionData
                //   serves as an unconditional trap. Trap to client, and resume with ResumptionData
                // Watchpoint (WPID dest) ResumptionData
                //   when disabled, jump to dest
                //   when enabled, trap to client and resume
        id: Option<WPID>,
        disable_dest: Option<Destination>,
        resume: ResumptionData
qinsoon's avatar
qinsoon committed
232
    },
233
    WPBranch{
qinsoon's avatar
qinsoon committed
234
        wp: WPID,
235
236
237
238
239
240
241
        disable_dest: Destination,
        enable_dest: Destination
    },
    Call{
        data: CallData,
        resume: ResumptionData
    },
qinsoon's avatar
qinsoon committed
242
243
244
245
    CCall{
        data: CallData,
        resume: ResumptionData
    },
246
247
248
249
250
251
252
253
254
255
256
257
    SwapStack{
        stack: OpIndex,
        is_exception: bool,
        args: Vec<OpIndex>,
        resume: ResumptionData
    },
    Switch{
        cond: OpIndex,
        default: Destination,
        branches: Vec<(OpIndex, Destination)>
    },
    ExnInstruction{
qinsoon's avatar
qinsoon committed
258
        inner: Box<Instruction>,
259
260
261
262
263
264
265
266
267
        resume: ResumptionData
    }
}

impl Instruction_ {
    fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
        match self {
            &Instruction_::BinOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]),
            &Instruction_::CmpOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]),
qinsoon's avatar
qinsoon committed
268
269
270
            &Instruction_::ConvOp{operation, ref from_ty, ref to_ty, operand} => {
                format!("{:?} {} {} {}", operation, from_ty, to_ty, ops[operand])
            }
271
272
273
274
            &Instruction_::ExprCall{ref data, is_abort} => {
                let abort = select_value!(is_abort, "ABORT_ON_EXN", "RETHROW");
                format!("CALL {} {}", data.debug_str(ops), abort)
            },
qinsoon's avatar
qinsoon committed
275
276
277
278
            &Instruction_::ExprCCall{ref data, is_abort} => {
                let abort = select_value!(is_abort, "ABORT_ON_EXN", "RETHROW");
                format!("CCALL {} {}", data.debug_str(ops), abort)
            }
279
280
            &Instruction_::Load{is_ptr, mem_loc, order} => {
                let ptr = select_value!(is_ptr, "PTR", "");
qinsoon's avatar
qinsoon committed
281
                format!("LOAD {} {:?} {}", ptr, order, ops[mem_loc])
282
283
284
285
286
            },
            &Instruction_::Store{value, is_ptr, mem_loc, order} => {
                let ptr = select_value!(is_ptr, "PTR", "");
                format!("STORE {} {:?} {} {}", ptr, order, ops[mem_loc], ops[value])
            },
qinsoon's avatar
qinsoon committed
287
            &Instruction_::CmpXchg{is_ptr, is_weak, success_order, fail_order,
288
289
290
                mem_loc, expected_value, desired_value} => {
                let ptr = select_value!(is_ptr, "PTR", "");
                let weak = select_value!(is_weak, "WEAK", "");
qinsoon's avatar
qinsoon committed
291
292
                format!("CMPXCHG {} {} {:?} {:?} {} {} {}",
                    ptr, weak, success_order, fail_order, ops[mem_loc], ops[expected_value], ops[desired_value])
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
            },
            &Instruction_::AtomicRMW{is_ptr, order, op, mem_loc, value} => {
                let ptr = select_value!(is_ptr, "PTR", "");
                format!("ATOMICRMW {} {:?} {:?} {} {}", ptr, order, op, ops[mem_loc], ops[value])
            },
            &Instruction_::New(ref ty) => format!("NEW {}", ty),
            &Instruction_::AllocA(ref ty) => format!("ALLOCA {}", ty),
            &Instruction_::NewHybrid(ref ty, len) => format!("NEWHYBRID {} {}", ty, ops[len]),
            &Instruction_::AllocAHybrid(ref ty, len) => format!("ALLOCAHYBRID {} {}", ty, ops[len]),
            &Instruction_::NewStack(func) => format!("NEWSTACK {}", ops[func]),
            &Instruction_::NewThread(stack, ref args) => format!("NEWTHREAD {} PASS_VALUES {}", ops[stack], op_vector_str(args, ops)),
            &Instruction_::NewThreadExn(stack, exn) => format!("NEWTHREAD {} THROW_EXC {}", ops[stack], ops[exn]),
            &Instruction_::NewFrameCursor(stack) => format!("NEWFRAMECURSOR {}", ops[stack]),
            &Instruction_::GetIRef(reference) => format!("GETIREF {}", ops[reference]),
            &Instruction_::GetFieldIRef{is_ptr, base, index} => {
                let ptr = select_value!(is_ptr, "PTR", "");
309
                format!("GETFIELDIREF {} {} {}", ptr, ops[base], index)
310
311
312
313
314
315
316
317
318
319
320
321
322
            },
            &Instruction_::GetElementIRef{is_ptr, base, index} => {
                let ptr = select_value!(is_ptr, "PTR", "");
                format!("GETELEMENTIREF {} {} {}", ptr, ops[base], ops[index])
            },
            &Instruction_::ShiftIRef{is_ptr, base, offset} => {
                let ptr = select_value!(is_ptr, "PTR", "");
                format!("SHIFTIREF {} {} {}", ptr, ops[base], ops[offset])
            },
            &Instruction_::GetVarPartIRef{is_ptr, base} => {
                let ptr = select_value!(is_ptr, "PTR", "");
                format!("GETVARPARTIREF {} {}", ptr, ops[base])
            },
qinsoon's avatar
qinsoon committed
323

324
325
326
            &Instruction_::Fence(order) => {
                format!("FENCE {:?}", order)
            },
qinsoon's avatar
qinsoon committed
327

328
329
            &Instruction_::Return(ref vals) => format!("RET {}", op_vector_str(vals, ops)),
            &Instruction_::ThreadExit => "THREADEXIT".to_string(),
330
            &Instruction_::Throw(exn_obj) => format!("THROW {}", ops[exn_obj]),
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
            &Instruction_::TailCall(ref call) => format!("TAILCALL {}", call.debug_str(ops)),
            &Instruction_::Branch1(ref dest) => format!("BRANCH {}", dest.debug_str(ops)),
            &Instruction_::Branch2{cond, ref true_dest, ref false_dest, ..} => {
                format!("BRANCH2 {} {} {}", ops[cond], true_dest.debug_str(ops), false_dest.debug_str(ops))
            },
            &Instruction_::Watchpoint{id, ref disable_dest, ref resume} => {
                match id {
                    Some(id) => {
                        format!("WATCHPOINT {} {} {}", id, disable_dest.as_ref().unwrap().debug_str(ops), resume.debug_str(ops))
                    },
                    None => {
                        format!("TRAP {}", resume.debug_str(ops))
                    }
                }
            },
            &Instruction_::WPBranch{wp, ref disable_dest, ref enable_dest} => {
                format!("WPBRANCH {} {} {}", wp, disable_dest.debug_str(ops), enable_dest.debug_str(ops))
            },
            &Instruction_::Call{ref data, ref resume} => format!("CALL {} {}", data.debug_str(ops), resume.debug_str(ops)),
qinsoon's avatar
qinsoon committed
350
            &Instruction_::CCall{ref data, ref resume} => format!("CCALL {} {}", data.debug_str(ops), resume.debug_str(ops)),
351
352
353
354
355
356
357
358
359
360
361
362
363
            &Instruction_::SwapStack{stack, is_exception, ref args, ref resume} => {
                format!("SWAPSTACK {} {} {} {}", ops[stack], is_exception, op_vector_str(args, ops), resume.debug_str(ops))
            },
            &Instruction_::Switch{cond, ref default, ref branches} => {
                let mut ret = format!("SWITCH {} {} {{", ops[cond], default.debug_str(ops));
                for i in 0..branches.len() {
                    let (op, ref dest) = branches[i];
                    ret.push_str(format!("{} {}", ops[op], dest.debug_str(ops)).as_str());
                    if i != branches.len() - 1 {
                        ret.push_str(", ");
                    }
                }
                ret.push_str("}}");
qinsoon's avatar
qinsoon committed
364

365
366
367
368
369
370
                ret
            },
            &Instruction_::ExnInstruction{ref inner, ref resume} => {
                format!("{} {}", inner.debug_str(ops), resume.debug_str(ops))
            }
        }
qinsoon's avatar
qinsoon committed
371
    }
372
373
}

qinsoon's avatar
qinsoon committed
374
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
375
376
377
378
379
380
381
382
383
384
pub enum MemoryOrder {
    NotAtomic,
    Relaxed,
    Consume,
    Acquire,
    Release,
    AcqRel,
    SeqCst
}

qinsoon's avatar
qinsoon committed
385
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
386
387
388
389
390
pub enum CallConvention {
    Mu,
    Foreign(ForeignFFI)
}

qinsoon's avatar
qinsoon committed
391
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
392
393
394
395
pub enum ForeignFFI {
    C
}

qinsoon's avatar
qinsoon committed
396
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
397
398
399
400
401
402
403
404
405
406
407
408
pub struct CallData {
    pub func: OpIndex,
    pub args: Vec<OpIndex>,
    pub convention: CallConvention
}

impl CallData {
    fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
        format!("{:?} {} [{}]", self.convention, ops[self.func], op_vector_str(&self.args, ops))
    }
}

qinsoon's avatar
qinsoon committed
409
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
410
411
412
413
414
415
416
417
418
419
420
pub struct ResumptionData {
    pub normal_dest: Destination,
    pub exn_dest: Destination
}

impl ResumptionData {
    fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
        format!("normal: {}, exception: {}", self.normal_dest.debug_str(ops), self.exn_dest.debug_str(ops))
    }
}

qinsoon's avatar
qinsoon committed
421
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
422
pub struct Destination {
qinsoon's avatar
qinsoon committed
423
    pub target: MuID,
424
425
426
427
428
    pub args: Vec<DestArg>
}

impl Destination {
    fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
qinsoon's avatar
qinsoon committed
429
        let mut ret = format!("{} with ", self.target);
430
431
432
433
434
435
436
437
438
        ret.push('[');
        for i in 0..self.args.len() {
            let ref arg = self.args[i];
            ret.push_str(arg.debug_str(ops).as_str());
            if i != self.args.len() - 1 {
                ret.push_str(", ");
            }
        }
        ret.push(']');
qinsoon's avatar
qinsoon committed
439

440
441
        ret
    }
442
443
444
445
446
447
448
449
450
451
    
    pub fn get_arguments(&self, ops: &Vec<P<TreeNode>>) -> Vec<P<Value>> {
        vec_utils::map(&self.args, 
            |x| {
                match x {
                    &DestArg::Normal(i) => ops[i].clone_value(),
                    &DestArg::Freshbound(_) => unimplemented!()
                }
        })
    }
452
453
}

qinsoon's avatar
qinsoon committed
454
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
455
456
457
458
459
460
461
462
463
pub enum DestArg {
    Normal(OpIndex),
    Freshbound(usize)
}

impl DestArg {
    fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
        match self {
            &DestArg::Normal(index) => format!("{}", ops[index]),
qinsoon's avatar
qinsoon committed
464
            &DestArg::Freshbound(n) => format!("${}", n)
465
466
        }
    }
qinsoon's avatar
qinsoon committed
467
}