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.6% of users enabled 2FA.

test_call.rs 4.8 KB
Newer Older
qinsoon's avatar
qinsoon committed
1 2
use mu::ast::types::*;
use mu::ast::ir::*;
3
use mu::ast::ptr::*;
qinsoon's avatar
qinsoon committed
4 5 6 7 8 9 10
use mu::ast::inst::*;
use mu::vm::*;
use mu::compiler::*;

use std::sync::RwLock;
use std::sync::Arc;
use mu::testutil::aot;
11
use mu::utils::LinkedHashMap;
qinsoon's avatar
qinsoon committed
12 13 14 15 16 17 18

#[test]
fn test_ccall_exit() {
    VM::start_logging_trace();

    let vm = Arc::new(ccall_exit());

qinsoon's avatar
qinsoon committed
19
    let compiler = Compiler::new(CompilerPolicy::default(), &vm);
qinsoon's avatar
qinsoon committed
20 21 22 23 24 25 26 27 28 29 30

    let func_id = vm.id_of("ccall_exit");
    {
        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.cur_ver.unwrap()).unwrap().write().unwrap();

        compiler.compile(&mut func_ver);
    }

qinsoon's avatar
qinsoon committed
31
    vm.make_primordial_thread(func_id, true, vec![]);
qinsoon's avatar
qinsoon committed
32 33
    backend::emit_context(&vm);

qinsoon's avatar
qinsoon committed
34
    let executable = aot::link_primordial(vec!["ccall_exit".to_string()], "ccall_exit_test", &vm);
qinsoon's avatar
qinsoon committed
35 36 37 38 39 40 41 42 43
    let output = aot::execute_nocheck(executable);

    assert!(output.status.code().is_some());

    let ret_code = output.status.code().unwrap();
    println!("return code: {}", ret_code);
    assert!(ret_code == 10);
}

44
pub fn gen_ccall_exit(arg: P<TreeNode>, func_ver: &mut MuFunctionVersion, vm: &VM) -> Box<TreeNode> {
qinsoon's avatar
qinsoon committed
45 46
    // .typedef @int32 = int<32>
    let type_def_int32 = vm.declare_type(vm.next_id(), MuType_::int(32));
47
    vm.set_name(type_def_int32.as_entity(), Mu("exit_int32"));
qinsoon's avatar
qinsoon committed
48 49 50 51 52 53 54 55 56 57 58 59 60

    // .typedef @exit_sig = (@int32) -> !
    let exit_sig = vm.declare_func_sig(vm.next_id(), vec![], vec![type_def_int32.clone()]);
    vm.set_name(exit_sig.as_entity(), Mu("exit_sig"));

    // .typedef @ufp_exit = ufuncptr(@exit_sig)
    let type_def_ufp_exit = vm.declare_type(vm.next_id(), MuType_::UFuncPtr(exit_sig.clone()));
    vm.set_name(type_def_ufp_exit.as_entity(), Mu("ufp_exit"));

    // .const @exit = EXTERN SYMBOL "exit"
    let const_exit = vm.declare_const(vm.next_id(), type_def_ufp_exit.clone(), Constant::ExternSym(C("exit")));
    vm.set_name(const_exit.as_entity(), Mu("exit"));

qinsoon's avatar
qinsoon committed
61
    // exprCCALL %const_exit (%const_int32_10)
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    let const_exit_local = func_ver.new_constant(const_exit.clone());

    func_ver.new_inst(Instruction{
        hdr: MuEntityHeader::unnamed(vm.next_id()),
        value: None,
        ops: RwLock::new(vec![const_exit_local, arg]),
        v: Instruction_::ExprCCall {
            data: CallData {
                func: 0,
                args: vec![1],
                convention: CallConvention::Foreign(ForeignFFI::C)
            },
            is_abort: false
        }
    })
}

fn ccall_exit() -> VM {
    let vm = VM::new();

    // .typedef @int32 = int<32>
    let type_def_int32 = vm.declare_type(vm.next_id(), MuType_::int(32));
    vm.set_name(type_def_int32.as_entity(), Mu("int32"));

qinsoon's avatar
qinsoon committed
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
    // .const @int32_10 = 10
    let const_int32_10 = vm.declare_const(vm.next_id(), type_def_int32.clone(), Constant::Int(10));
    vm.set_name(const_int32_10.as_entity(), Mu("const_int32_10"));

    // .const @int32_0 = 0
    let const_int32_0 = vm.declare_const(vm.next_id(), type_def_int32.clone(), Constant::Int(0));
    vm.set_name(const_int32_0.as_entity(), Mu("const_int32_0"));

    // .funcsig @ccall_exit_sig = () -> !
    let ccall_exit_sig = vm.declare_func_sig(vm.next_id(), vec![], vec![]);
    vm.set_name(ccall_exit_sig.as_entity(), Mu("ccall_exit_sig"));

    // .funcdecl @ccall_exit <@ccall_exit_sig>
    let func_id = vm.next_id();
    let func = MuFunction::new(func_id, ccall_exit_sig.clone());
    vm.set_name(func.as_entity(), Mu("ccall_exit"));
    vm.declare_func(func);

    // .funcdef @ccall_exit VERSION @ccall_exit_v1 <@ccall_exit_sig>
    let mut func_ver = MuFunctionVersion::new(vm.next_id(), func_id, ccall_exit_sig.clone());
    vm.set_name(func_ver.as_entity(), Mu("ccall_exit_v1"));

    // %entry():
    let mut blk_entry = Block::new(vm.next_id());
    vm.set_name(blk_entry.as_entity(), Mu("entry"));

qinsoon's avatar
qinsoon committed
112
    // exprCCALL %const_exit (%const_int32_10)
qinsoon's avatar
qinsoon committed
113
    let const_int32_10_local = func_ver.new_constant(const_int32_10.clone());
114
    let blk_entry_ccall = gen_ccall_exit(const_int32_10_local.clone(), &mut func_ver, &vm);
qinsoon's avatar
qinsoon committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

    // RET %const_int32_0
    let const_int32_0_local = func_ver.new_constant(const_int32_0.clone());

    let blk_entry_ret = func_ver.new_inst(Instruction{
        hdr: MuEntityHeader::unnamed(vm.next_id()),
        value: None,
        ops: RwLock::new(vec![const_int32_0_local]),
        v: Instruction_::Return(vec![0])
    });

    blk_entry.content = Some(BlockContent {
        args: vec![],
        exn_arg: None,
        body: vec![blk_entry_ccall, blk_entry_ret],
        keepalives: None
    });

133 134 135
    func_ver.define(FunctionContent::new(
        blk_entry.id(),
        {
136 137 138
            let mut map = LinkedHashMap::new();
            map.insert(blk_entry.id(), blk_entry);
            map
qinsoon's avatar
qinsoon committed
139
        }
140
    ));
qinsoon's avatar
qinsoon committed
141 142 143 144

    vm.define_func_version(func_ver);

    vm
145
}