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

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

7
use utils::vec_utils;
8
9
10

use std::fmt;

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

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

qinsoon's avatar
qinsoon committed
22
23
24
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
25
26
27
        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
28
            
29
            let ref ops = self.ops;
qinsoon's avatar
qinsoon committed
30
            try!(s.emit_struct_field("ops", 2, |s| ops.encode(s)));
qinsoon's avatar
qinsoon committed
31
            
qinsoon's avatar
qinsoon committed
32
            try!(s.emit_struct_field("v", 3, |s| self.v.encode(s)));
qinsoon's avatar
qinsoon committed
33
34
35
36
37
38
39
40
            
            Ok(()) 
        })        
    }
}

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

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

70
impl Instruction {
71
72
73
74
75
76
77
    pub fn clone_with_id(&self, new_id: MuID) -> Instruction {
        let mut clone = self.clone();
        clone.hdr = self.hdr.clone_with_id(new_id);

        clone
    }

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
    pub fn has_exception_clause(&self) -> bool {
        ir_semantics::is_potentially_excepting_instruction(&self.v)
    }

    pub fn get_exception_target(&self) -> Option<MuID> {
        use inst::Instruction_::*;
        match self.v {
            Watchpoint {ref resume, ..}
            | Call {ref resume, ..}
            | CCall {ref resume, ..}
            | SwapStack {ref resume, ..}
            | ExnInstruction {ref resume, ..} => {
                Some(resume.exn_dest.target)
            },

            BinOp(_, _, _)
            | BinOpWithStatus(_, _, _, _)
            | CmpOp(_, _, _)
            | ConvOp{..}
            | ExprCall{..}
            | ExprCCall{..}
            | Load{..}
            | Store{..}
            | CmpXchg{..}
            | AtomicRMW{..}
            | New(_)
            | AllocA(_)
            | NewHybrid(_, _)
            | AllocAHybrid(_, _)
            | NewStack(_)
            | NewThread(_, _)
            | NewThreadExn(_, _)
            | NewFrameCursor(_)
            | GetIRef(_)
            | GetFieldIRef{..}
            | GetElementIRef{..}
            | ShiftIRef{..}
            | GetVarPartIRef{..}
            | Fence(_)
            | Return(_)
            | ThreadExit
            | Throw(_)
            | TailCall(_)
            | Branch1(_)
            | Branch2{..}
            | Select{..}
            | WPBranch{..}
            | Switch{..}
            | CommonInst_GetThreadLocal
            | CommonInst_SetThreadLocal(_)
            | CommonInst_Pin(_)
            | CommonInst_Unpin(_)
            | Move(_)
            | PrintHex(_) => None
        }
    }

135
136
137
138
139
140
141
    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 {
142
        let ref ops = self.ops;
143
        if self.value.is_some() {
qinsoon's avatar
qinsoon committed
144
            write!(f, "{} = {}", vec_utils::as_str(self.value.as_ref().unwrap()), self.v.debug_str(ops))
145
146
147
148
149
150
        } else {
            write!(f, "{}", self.v.debug_str(ops))
        }
    }
}

qinsoon's avatar
qinsoon committed
151
#[allow(non_camel_case_types)]
qinsoon's avatar
qinsoon committed
152
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
153
154
pub enum Instruction_ {
    // non-terminal instruction
qinsoon's avatar
qinsoon committed
155

156
    // expressions
qinsoon's avatar
qinsoon committed
157
158

    BinOp(BinOp, OpIndex, OpIndex),
qinsoon's avatar
qinsoon committed
159
160
    BinOpWithStatus(BinOp, BinOpStatus, OpIndex, OpIndex),

161
    CmpOp(CmpOp, OpIndex, OpIndex),
162
163
164
165
166
167
    ConvOp{
        operation: ConvOp,
        from_ty: P<MuType>,
        to_ty: P<MuType>,
        operand: OpIndex
    },
qinsoon's avatar
qinsoon committed
168

169
170
171
    // yields a tuple of results from the call
    ExprCall{
        data: CallData,
qinsoon's avatar
qinsoon committed
172
        is_abort: bool, // T to abort, F to rethrow - FIXME: current, always rethrow for now
173
    },
qinsoon's avatar
qinsoon committed
174

qinsoon's avatar
qinsoon committed
175
176
177
178
179
    ExprCCall{
        data: CallData,
        is_abort: bool
    },

180
181
182
183
184
185
    // yields the memory value
    Load{
        is_ptr: bool,
        order: MemoryOrder,
        mem_loc: OpIndex
    },
qinsoon's avatar
qinsoon committed
186

187
188
189
    // yields nothing
    Store{
        is_ptr: bool,
qinsoon's avatar
qinsoon committed
190
        order: MemoryOrder,
191
192
193
        mem_loc: OpIndex,
        value: OpIndex
    },
qinsoon's avatar
qinsoon committed
194

195
196
197
198
199
200
201
202
203
204
    // 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
205

206
207
208
209
210
211
212
213
    // 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
214

215
216
    // yields a reference of the type
    New(P<MuType>),
qinsoon's avatar
qinsoon committed
217

218
219
    // yields an iref of the type
    AllocA(P<MuType>),
qinsoon's avatar
qinsoon committed
220

221
222
    // yields ref
    NewHybrid(P<MuType>, OpIndex),
qinsoon's avatar
qinsoon committed
223

224
225
    // yields iref
    AllocAHybrid(P<MuType>, OpIndex),
qinsoon's avatar
qinsoon committed
226

227
228
229
    // yields stack ref
    NewStack(OpIndex), // func
                           // TODO: common inst
qinsoon's avatar
qinsoon committed
230

231
232
    // yields thread reference
    NewThread(OpIndex, Vec<OpIndex>), // stack, args
qinsoon's avatar
qinsoon committed
233

234
235
    // yields thread reference (thread resumes with exceptional value)
    NewThreadExn(OpIndex, OpIndex), // stack, exception
qinsoon's avatar
qinsoon committed
236

237
238
    // yields frame cursor
    NewFrameCursor(OpIndex), // stack
qinsoon's avatar
qinsoon committed
239

240
241
    // ref<T> -> iref<T>
    GetIRef(OpIndex),
qinsoon's avatar
qinsoon committed
242

243
244
245
246
    // iref|uptr<struct|hybrid<T>> int<M> -> iref|uptr<U>
    GetFieldIRef{
        is_ptr: bool,
        base: OpIndex, // iref or uptr
247
        index: usize // constant
248
    },
qinsoon's avatar
qinsoon committed
249

250
251
252
253
254
255
    // 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
256

257
258
259
260
261
262
    // iref|uptr<T> int<M> -> iref|uptr<T>
    ShiftIRef{
        is_ptr: bool,
        base: OpIndex,
        offset: OpIndex
    },
qinsoon's avatar
qinsoon committed
263

264
265
266
267
268
    // iref|uptr<hybrid<T U>> -> iref|uptr<U>
    GetVarPartIRef{
        is_ptr: bool,
        base: OpIndex
    },
qinsoon's avatar
qinsoon committed
269

270
271
272
273
274
275
276
277
278
//    PushFrame{
//        stack: P<Value>,
//        func: P<Value>
//    },
//    PopFrame{
//        stack: P<Value>
//    }

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

280
281
282
    // terminal instruction
    Return(Vec<OpIndex>),
    ThreadExit, // TODO:  common inst
283
    Throw(OpIndex),
284
285
286
287
288
289
290
291
    TailCall(CallData),
    Branch1(Destination),
    Branch2{
        cond: OpIndex,
        true_dest: Destination,
        false_dest: Destination,
        true_prob: f32
    },
qinsoon's avatar
qinsoon committed
292
293
294
295
296
    Select{
        cond: OpIndex,
        true_val: OpIndex,
        false_val: OpIndex
    },
297
298
299
300
301
302
303
304
    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
305
    },
306
    WPBranch{
qinsoon's avatar
qinsoon committed
307
        wp: WPID,
308
309
310
311
312
313
314
        disable_dest: Destination,
        enable_dest: Destination
    },
    Call{
        data: CallData,
        resume: ResumptionData
    },
qinsoon's avatar
qinsoon committed
315
316
317
318
    CCall{
        data: CallData,
        resume: ResumptionData
    },
319
320
321
322
323
324
325
326
327
328
329
330
    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
331
        inner: Box<Instruction>,
332
        resume: ResumptionData
333
334
335
336
    },

    // common inst
    CommonInst_GetThreadLocal,
337
338
    CommonInst_SetThreadLocal(OpIndex),

qinsoon's avatar
qinsoon committed
339
340
341
342
    // pin/unpin
    CommonInst_Pin  (OpIndex),
    CommonInst_Unpin(OpIndex),

343
    // internal use: mov from ops[0] to value
344
345
346
    Move(OpIndex),
    // internal use: print op as hex value
    PrintHex(OpIndex)
347
348
349
350
351
352
}

impl Instruction_ {
    fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
        match self {
            &Instruction_::BinOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]),
qinsoon's avatar
qinsoon committed
353
354
355
            &Instruction_::BinOpWithStatus(op, status, op1, op2) => {
                format!("{:?} {:?} {} {}", op, status, ops[op1], ops[op2])
            }
356
            &Instruction_::CmpOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]),
qinsoon's avatar
qinsoon committed
357
358
359
            &Instruction_::ConvOp{operation, ref from_ty, ref to_ty, operand} => {
                format!("{:?} {} {} {}", operation, from_ty, to_ty, ops[operand])
            }
360
361
362
363
            &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
364
365
366
367
            &Instruction_::ExprCCall{ref data, is_abort} => {
                let abort = select_value!(is_abort, "ABORT_ON_EXN", "RETHROW");
                format!("CCALL {} {}", data.debug_str(ops), abort)
            }
368
369
            &Instruction_::Load{is_ptr, mem_loc, order} => {
                let ptr = select_value!(is_ptr, "PTR", "");
qinsoon's avatar
qinsoon committed
370
                format!("LOAD {} {:?} {}", ptr, order, ops[mem_loc])
371
372
373
374
375
            },
            &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
376
            &Instruction_::CmpXchg{is_ptr, is_weak, success_order, fail_order,
377
378
379
                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
380
381
                format!("CMPXCHG {} {} {:?} {:?} {} {} {}",
                    ptr, weak, success_order, fail_order, ops[mem_loc], ops[expected_value], ops[desired_value])
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
            },
            &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", "");
398
                format!("GETFIELDIREF {} {} {}", ptr, ops[base], index)
399
400
401
402
403
404
405
406
407
408
409
410
411
            },
            &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
412

413
414
415
            &Instruction_::Fence(order) => {
                format!("FENCE {:?}", order)
            },
qinsoon's avatar
qinsoon committed
416

417
418
            &Instruction_::Return(ref vals) => format!("RET {}", op_vector_str(vals, ops)),
            &Instruction_::ThreadExit => "THREADEXIT".to_string(),
419
            &Instruction_::Throw(exn_obj) => format!("THROW {}", ops[exn_obj]),
420
421
422
423
424
            &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))
            },
qinsoon's avatar
qinsoon committed
425
426
427
            &Instruction_::Select{cond, true_val, false_val} => {
                format!("SELECT if {} then {} else {}", ops[cond], ops[true_val], ops[false_val])
            }
428
429
430
431
432
433
434
435
436
437
438
439
440
441
            &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
442
            &Instruction_::CCall{ref data, ref resume} => format!("CCALL {} {}", data.debug_str(ops), resume.debug_str(ops)),
443
444
445
446
447
448
449
450
451
452
453
454
455
            &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
456

457
458
459
460
                ret
            },
            &Instruction_::ExnInstruction{ref inner, ref resume} => {
                format!("{} {}", inner.debug_str(ops), resume.debug_str(ops))
461
            },
462
463

            // common inst
464
            &Instruction_::CommonInst_GetThreadLocal => format!("COMMONINST GetThreadLocal"),
465
466
            &Instruction_::CommonInst_SetThreadLocal(op) => format!("COMMONINST SetThreadLocal {}", ops[op]),

qinsoon's avatar
qinsoon committed
467
468
469
            &Instruction_::CommonInst_Pin(op)   => format!("COMMONINST Pin {}",   ops[op]),
            &Instruction_::CommonInst_Unpin(op) => format!("COMMONINST Unpin {}", ops[op]),

470
            // move
471
472
473
            &Instruction_::Move(from) => format!("MOVE {}", ops[from]),
            // print hex
            &Instruction_::PrintHex(i) => format!("PRINTHEX {}", ops[i])
474
        }
qinsoon's avatar
qinsoon committed
475
    }
476
477
}

qinsoon's avatar
qinsoon committed
478
479
480
481
482
483
484
485
486
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct BinOpStatus {
    pub flag_n: bool,
    pub flag_z: bool,
    pub flag_c: bool,
    pub flag_v: bool
}

impl BinOpStatus {
487
488
489
490
    pub fn none() -> BinOpStatus {
        BinOpStatus {flag_n: false, flag_z: false, flag_c: false, flag_v: false}
    }

qinsoon's avatar
qinsoon committed
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
    pub fn n() -> BinOpStatus {
        BinOpStatus {flag_n: true, flag_z: false, flag_c: false, flag_v: false}
    }

    pub fn z() -> BinOpStatus {
        BinOpStatus {flag_n: false, flag_z: true, flag_c: false, flag_v: false}
    }

    pub fn c() -> BinOpStatus {
        BinOpStatus {flag_n: false, flag_z: false, flag_c: true, flag_v: false}
    }

    pub fn v() -> BinOpStatus {
        BinOpStatus {flag_n: false, flag_z: false, flag_c: false, flag_v: true}
    }
}

impl fmt::Debug for BinOpStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.flag_n {
            write!(f, "#N").unwrap();
        }
        if self.flag_z {
            write!(f, "#Z").unwrap();
        }
        if self.flag_c {
            write!(f, "#C").unwrap();
        }
        if self.flag_v {
            write!(f, "#V").unwrap();
        }
        Ok(())
    }
}

qinsoon's avatar
qinsoon committed
526
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
527
528
529
530
531
532
533
534
535
536
pub enum MemoryOrder {
    NotAtomic,
    Relaxed,
    Consume,
    Acquire,
    Release,
    AcqRel,
    SeqCst
}

qinsoon's avatar
qinsoon committed
537
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
538
539
540
541
542
pub enum CallConvention {
    Mu,
    Foreign(ForeignFFI)
}

qinsoon's avatar
qinsoon committed
543
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
544
545
546
547
pub enum ForeignFFI {
    C
}

qinsoon's avatar
qinsoon committed
548
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
549
550
551
552
553
554
555
556
pub struct CallData {
    pub func: OpIndex,
    pub args: Vec<OpIndex>,
    pub convention: CallConvention
}

impl CallData {
    fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
qinsoon's avatar
qinsoon committed
557
558
559
560
561
        let func_name = match ops[self.func].name() {
            Some(name) => name,
            None => "Anonymous Function".to_string()
        };
        format!("{:?} {} [{}]", self.convention, func_name, op_vector_str(&self.args, ops))
562
563
564
    }
}

qinsoon's avatar
qinsoon committed
565
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
566
567
568
569
570
571
572
573
574
575
576
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
577
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
578
pub struct Destination {
qinsoon's avatar
qinsoon committed
579
    pub target: MuID,
580
581
582
583
584
    pub args: Vec<DestArg>
}

impl Destination {
    fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
585
586
        let mut ret = format!("{}", self.target);
        ret.push('(');
587
588
589
590
591
592
593
        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(", ");
            }
        }
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
594
        ret.push(')');
qinsoon's avatar
qinsoon committed
595

596
597
        ret
    }
598
599
600
601
602
603
604
605
606
607
608

    pub fn get_arguments_as_node(&self, ops: &Vec<P<TreeNode>>) -> Vec<P<TreeNode>> {
       vec_utils::map(&self.args,
           |x| {
               match x {
                   &DestArg::Normal(i) => ops[i].clone(),
                   &DestArg::Freshbound(_) => unimplemented!()
               }
       })
    }

609
610
611
612
613
614
615
616
617
    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!()
                }
        })
    }
618
619
}

qinsoon's avatar
qinsoon committed
620
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
621
622
623
624
625
626
627
628
629
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
630
            &DestArg::Freshbound(n) => format!("${}", n)
631
632
        }
    }
633
}