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.

Commit a4f8045f authored by qinsoon's avatar qinsoon
Browse files

Merge remote-tracking branch 'origin/develop' into open-source

parents 5145efb5 c0089a9f
......@@ -30,21 +30,16 @@ stages:
- build
- test
build_vm:
build:
stage: build
script:
- rustc --version
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo build --release
build_test:
stage: build
script:
- rustc --version
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo test --release --no-run
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo test --release --no-run --color=always
artifacts:
paths:
- target/release/libmu.so
- target/release/libmu.a
- target/release/lib-*
before_script:
- export PATH=$PATH:/root/.cargo/bin
......@@ -56,68 +51,68 @@ before_script:
test:cargo:api:
stage: test
script:
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_api 2> /dev/null
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 ./test-release --color=always test_api 2> /dev/null
test:cargo:ir:
stage: test
script:
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_ir 2> /dev/null
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 ./test-release --color=always test_ir 2> /dev/null
test:cargo:compiler:
stage: test
script:
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_compiler 2> /dev/null
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 ./test-release --color=always test_compiler 2> /dev/null
test:cargo:runtime:
stage: test
script:
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_runtime 2> /dev/null
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 ./test-release --color=always test_runtime 2> /dev/null
testjit:milestones:
stage: test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_milestones.py -v
- RUST_BACKTRACE=1 pytest tests/test_jit/test_milestones.py -v --color=yes
testjit:binops:
stage: test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_binops.py -v
- RUST_BACKTRACE=1 pytest tests/test_jit/test_binops.py -v --color=yes
testjit:cmpops:
stage: test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_cmpops.py -v
- RUST_BACKTRACE=1 pytest tests/test_jit/test_cmpops.py -v --color=yes
testjit:controlflow:
stage: test
script:
- cd tests/test_jit
- RUST_BACKTRACE=1 pytest test_controlflow.py -v
- RUST_BACKTRACE=1 pytest test_controlflow.py -v --color=yes
testjit:convops:
stage: test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_convops.py -v
- RUST_BACKTRACE=1 pytest tests/test_jit/test_convops.py -v --color=yes
testjit:double:
stage: test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_double.py -v
- RUST_BACKTRACE=1 pytest tests/test_jit/test_double.py -v --color=yes
testjit:memops:
stage: test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_memops.py -v
- RUST_BACKTRACE=1 pytest tests/test_jit/test_memops.py -v --color=yes
testjit:milestones:
stage: test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_milestones.py -v
- RUST_BACKTRACE=1 pytest tests/test_jit/test_milestones.py -v --color=yes
testjit:otherops:
stage: test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_otherops.py -v
- RUST_BACKTRACE=1 pytest tests/test_jit/test_otherops.py -v --color=yes
testjit:rpython:
stage: test
......@@ -128,7 +123,7 @@ testjit:rpython:
- git checkout mu-rewrite
- git apply pypy.patch
- cd $CI_PROJECT_DIR/tests/test_jit
- MU_LOG_LEVEL=info LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy pytest test_rpython*.py -v
- MU_LOG_LEVEL=info LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy pytest test_rpython*.py -v --color=yes
testjit:som:
stage: test
......@@ -142,4 +137,4 @@ testjit:som:
- git checkout mu-rewrite
- git apply pypy.patch
- cd $CI_PROJECT_DIR/tests/test_jit
- MU_LOG_LEVEL=info LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy:RPySOM/src RPYSOM=RPySOM pytest test_som.py -v
\ No newline at end of file
- MU_LOG_LEVEL=info LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy:RPySOM/src RPYSOM=RPySOM pytest test_som.py -v --color=yes
\ No newline at end of file
......@@ -34,7 +34,7 @@ gcc = "*"
ast = {path = "src/ast"}
utils = {path = "src/utils"}
gc = {path = "src/gc"}
rodal = { git = "https://gitlab.anu.edu.au/mu/rodal", version = "*" }
rodal = { git = "https://gitlab.anu.edu.au/mu/rodal", version = ">= 0.0.5" }
libc="*"
field-offset = "*"
libloading = "*"
......
......@@ -29,15 +29,29 @@ rm -rf $MU_ZEBU/tests/test_jit/emit
#cargo clean
cargo test --release --no-run --color=always 2>&1 | tee build_out.txt
$(exit ${PIPESTATUS[0]}) # this command will exit the shell but only if the above cargo test failed
/usr/bin/time -f "finished in %e secs" -a -o cargo_test_out.txt ./test-release --color=always 2>/dev/null | tee cargo_test_out.txt
cd $MU_ZEBU/tests/test_jit/mu-client-pypy
git pull
cd $MU_ZEBU/tests/test_jit/
cd $MU_ZEBU/tests/test_jit/RPySOM
git pull
if [ -d "./mu-client-pypy" ]
then
git -C ./mu-client-pypy pull
else
git clone https://gitlab.anu.edu.au/mu/mu-client-pypy.git
git -C ./mu-client-pypy checkout mu-rewrite
git -C ./mu-client-pypy apply pypy.patch
fi
cd $MU_ZEBU/tests/test_jit/
ZEBU_BUILD=release LD_LIBRARY_PATH=. PYTHONPATH=mu-client-pypy:RPySOM/src pytest test_*.py -v --color=yes 2>&1 | tee $MU_ZEBU/pytest_out.txt
if [ -d "./RPySOM" ]
then
git -C ./RPySOM pull
else
git clone https://github.com/microvm/RPySOM.git
git -C ./RPySOM submodule init
git -C ./RPySOM submodule update
fi
pytest test_*.py -v --color=yes 2>&1 | tee $MU_ZEBU/pytest_out.txt
......@@ -25,4 +25,4 @@ utils = {path = "../utils"}
lazy_static = "*"
log = "*"
simple_logger = "*"
rodal = { git = "https://gitlab.anu.edu.au/mu/rodal", version = "*" }
rodal = { git = "https://gitlab.anu.edu.au/mu/rodal", version = ">= 0.0.5" }
......@@ -835,10 +835,7 @@ pub struct CallData {
impl CallData {
fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
let func_name = match ops[self.func].name() {
Some(name) => name,
None => "Anonymous Function".to_string()
};
let func_name = ops[self.func].name();
format!("{:?} {} [{}]", self.convention, func_name, op_vector_str(&self.args, ops))
}
}
......
......@@ -138,7 +138,17 @@ pub struct MuFunctionVersion {
pub force_inline: bool,
pub block_trace: Option<Vec<MuID>> // only available after Trace Generation Pass
}
rodal_struct!(Callsite{name, exception_destination, stack_arg_size});
pub struct Callsite {
pub name: MuName,
pub exception_destination: Option<MuName>,
pub stack_arg_size: usize,
}
impl Callsite {
pub fn new(name: MuName, exception_destination: Option<MuName>, stack_arg_size: usize)->Callsite {
Callsite{name: name, exception_destination: exception_destination, stack_arg_size: stack_arg_size}
}
}
impl fmt::Display for MuFunctionVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FuncVer {} of Func #{}", self.hdr, self.func_id)
......@@ -383,7 +393,7 @@ impl FunctionContent {
pub fn get_block_by_name(&self, name: String) -> &Block {
for block in self.blocks.values() {
if block.name().unwrap() == name {
if block.name() == name {
return block;
}
}
......@@ -1061,12 +1071,13 @@ pub enum MemoryLocation {
Symbolic{
base: Option<P<Value>>,
label: MuName,
is_global: bool
is_global: bool,
is_native: bool,
}
}
#[cfg(target_arch = "x86_64")]
rodal_enum!(MemoryLocation{{Address: scale, base, offset, index}, {Symbolic: is_global, base, label}});
rodal_enum!(MemoryLocation{{Address: scale, base, offset, index}, {Symbolic: is_global, is_native, base, label}});
#[cfg(target_arch = "x86_64")]
impl fmt::Display for MemoryLocation {
......@@ -1124,13 +1135,17 @@ pub enum MemoryLocation {
},
Symbolic{
label: MuName,
is_global: bool
is_global: bool,
is_native: bool,
}
}
#[cfg(target_arch = "aarch64")]
rodal_enum!(MemoryLocation{{VirtualAddress: signed, base, offset, scale},
{Address: base, offset, shift, signed}, {Symbolic: is_global, label}});
rodal_enum!(MemoryLocation{
{VirtualAddress: signed, base, offset, scale},
{Address: base, offset, shift, signed},
{Symbolic: is_global, is_native, label}}
);
#[cfg(target_arch = "aarch64")]
impl fmt::Display for MemoryLocation {
......@@ -1172,7 +1187,7 @@ impl fmt::Display for MemoryLocation {
#[derive(Debug)] // Display, PartialEq, Clone
pub struct MuEntityHeader {
id: MuID,
name: Option<MuName>
name: MuName
}
rodal_struct!(MuEntityHeader{id, name});
......@@ -1186,73 +1201,163 @@ impl Clone for MuEntityHeader {
}
}
/// turns a client supplied name into a valid name for internal use and code generation.
/// The name should not contain special characters that may be escaped.
/// This name is stored with every Mu Entity while the original name from client is
/// stored somewhere else only for query use.
pub fn name_check(name: MuName) -> MuName {
let name = name.replace('.', "$");
if name.starts_with("@") || name.starts_with("%") {
let (_, name) = name.split_at(1);
/// returns true if name is a valid_c identifier
/// (i.e. it contains only ASCII letters, digits and underscores
/// and does not start with "__" or an digit.
pub fn is_valid_c_identifier(name: &MuName) -> bool {
let mut i = 0;
let mut underscore = false; // whether the first character is an underscore
for c in name.chars() {
match c {
'_' => {
if i == 0 { underscore = true; }
else if i == 1 && underscore { return false; }
},
'0'...'9' => {
if i == 0 { return false; }
},
'a'...'z' | 'A' ... 'Z' => { }
_ => { return false; }
}
i += 1;
}
return true;
}
return name.to_string();
/// changes name to mangled name
/// This will always return a valid C identifier
pub fn mangle_name(name: MuName) -> MuName {
let name = name.replace('@', "");
if name.starts_with("__mu_") {
// TODO: Get rid of this, since it will be trigered if a client provides a name starting with "__mu"
// which is totally valid, it's only here for the moment to debug name handling
panic!("Trying to mangle \"{}\", which is allready mangled", name.clone());
}
assert!(!name.starts_with("%"));
// Note: a ':' and '#' is only used by names generated by zebu itself
let name = name.replace('Z', "ZZ").replace('.', "Zd").replace('-', "Zh").replace(':', "Zc").replace('#', "Za");
"__mu_".to_string() + name.as_str()
}
// WARNING: This only reverses mangle_name above when no warning is issued)
pub fn demangle_name(mut name: MuName) -> MuName {
let name = if cfg!(target_os = "macos") && name.starts_with("___mu_") {
name.split_off(1)
} else {
name
};
if name.starts_with("%") {
panic!("The name '{}'' is local", name);
}
if !name.starts_with("__mu_") {
panic!("Trying to demangle \"{}\", which is not mangled", name.clone());
}
let name = name.split_at("__mu_".len()).1.to_string();
let name = name.replace("Za", "#").replace("Zc", ":").replace("Zh", "-").replace("Zd", ".").replace("ZZ", "Z");
name
}
// TODO: Why the hell isn't this working?
pub fn demangle_text(text: String) -> String {
let text = text.as_bytes();
let n = text.len();
let mut output = String::new();
// We have a mangled name
let mut last_i = 0; // The last i value that we dumped to output
let mut i = 0;
// TODO: this should work for utf-8 stuff right? (sinces all mangled names are in ascii)
while i < n {
let c = text[i] as char;
// We're at the beginining of the string
// wait for a word boundry
if c.is_alphanumeric() || c == '_' {
// We just found a mangled name
if text[i..].starts_with("__mu_".as_bytes()) {
output += std::str::from_utf8(&text[last_i..i]).unwrap();
let start = i;
// Find the end of the name
while i < n {
let c = text[i] as char;
if !c.is_alphanumeric() && c != '_' {
break; // We found the end!
}
i += 1;
}
output += demangle_name(String::from_utf8(text[start..i].to_vec()).unwrap()).as_str();
// Skip to the end of the name
last_i = i;
continue;
} else {
// Skip to the end of this alphanumeric sequence
while i < n {
let c = text[i] as char;
if !c.is_alphanumeric() && c != '_' {
break; // We found the end!
}
i += 1;
}
}
continue;
}
// Not the start of mangled name, continue
i += 1;
}
output + std::str::from_utf8(&text[last_i..n]).unwrap() // Return output plus whatever is left of the string
}
impl MuEntityHeader {
pub fn unnamed(id: MuID) -> MuEntityHeader {
MuEntityHeader {
id: id,
name: None
name: format!("#{}", id)
}
}
pub fn named(id: MuID, name: MuName) -> MuEntityHeader {
MuEntityHeader {
id: id,
name: Some(name_check(name))
name: name.replace('@', "")
}
}
pub fn id(&self) -> MuID {
self.id
}
pub fn name(&self) -> Option<MuName> {
pub fn name(&self) -> MuName {
self.name.clone()
}
/// an abbreviate (easy reading) version of the name
fn abbreviate_name(&self) -> Option<MuName> {
match self.name() {
Some(name) => {
let split: Vec<&str> = name.split('$').collect();
let mut ret = "".to_string();
for i in 0..split.len() - 1 {
ret.push(match split[i].chars().next() {
Some(c) => c,
None => '_'
});
ret.push('.');
}
fn abbreviate_name(&self) -> MuName {
let split: Vec<&str> = self.name.split('.').collect();
ret.push_str(split.last().unwrap());
let mut ret = "".to_string();
Some(ret)
}
None => None
for i in 0..split.len() - 1 {
ret.push(match split[i].chars().next() {
Some(c) => c,
None => '_'
});
ret.push('.');
}
ret.push_str(split.last().unwrap());
ret
}
pub fn clone_with_id(&self, new_id: MuID) -> MuEntityHeader {
let mut clone = self.clone();
clone.id = new_id;
clone.name = format!("{}-#{}", clone.name, clone.id);
clone
}
}
......@@ -1266,24 +1371,16 @@ impl PartialEq for MuEntityHeader {
impl fmt::Display for MuEntityHeader {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if DISPLAY_ID {
if self.name().is_none() {
write!(f, "{}", self.id)
if PRINT_ABBREVIATE_NAME {
write!(f, "{} #{}", self.abbreviate_name(), self.id)
} else {
if PRINT_ABBREVIATE_NAME {
write!(f, "{} #{}", self.abbreviate_name().unwrap(), self.id)
} else {
write!(f, "{} #{}", self.name().unwrap(), self.id)
}
write!(f, "{} #{}", self.name(), self.id)
}
} else {
if self.name().is_none() {
write!(f, "{}", self.id)
if PRINT_ABBREVIATE_NAME {
write!(f, "{}", self.abbreviate_name())
} else {
if PRINT_ABBREVIATE_NAME {
write!(f, "{}", self.abbreviate_name().unwrap())
} else {
write!(f, "{}", self.name().unwrap())
}
write!(f, "{}", self.name())
}
}
}
......@@ -1292,7 +1389,7 @@ impl fmt::Display for MuEntityHeader {
/// MuEntity trait allows accessing id and name on AST data structures
pub trait MuEntity {
fn id(&self) -> MuID;
fn name(&self) -> Option<MuName>;
fn name(&self) -> MuName;
fn as_entity(&self) -> &MuEntity;
}
......@@ -1314,7 +1411,7 @@ impl MuEntity for TreeNode {
}
}
fn name(&self) -> Option<MuName> {
fn name(&self) -> MuName {
match self.v {
TreeNode_::Instruction(ref inst) => inst.name(),
TreeNode_::Value(ref pv) => pv.name()
......
......@@ -46,7 +46,7 @@ macro_rules! impl_mu_entity {
#[inline(always)]
fn id(&self) -> MuID {self.hdr.id()}
#[inline(always)]
fn name(&self) -> Option<MuName> {self.hdr.name()}
fn name(&self) -> MuName {self.hdr.name()}
fn as_entity(&self) -> &MuEntity {
let ref_ty : &$entity = self;
ref_ty as &MuEntity
......
......@@ -49,7 +49,6 @@ pub trait CodeGenerator {
// emit code to adjust frame
fn emit_frame_grow(&mut self); // Emits a SUB
fn emit_frame_shrink(&mut self); // Emits an ADD
// Used to pass a string that the assembler will interpret as an immediate argument
// (This is neccesary to support the use of ELF relocations like ':tprel_hi12:foo')
......@@ -109,7 +108,7 @@ pub trait CodeGenerator {
// branching
// calls
fn emit_bl(&mut self, callsite: String, func: MuName, pe: Option<MuName>) -> ValueLocation;
fn emit_bl(&mut self, callsite: String, func: MuName, pe: Option<MuName>, is_native: bool) -> ValueLocation;
fn emit_blr(&mut self, callsite: String, func: Reg, pe: Option<MuName>) -> ValueLocation;
// Branches
......
......@@ -794,8 +794,8 @@ pub fn get_return_address(frame_pointer: Address) -> Address {
// Gets the stack pointer before the current frame was created
#[inline(always)]
pub fn get_previous_stack_pointer(frame_pointer: Address) -> Address {
frame_pointer + 16 as ByteSize
pub fn get_previous_stack_pointer(frame_pointer: Address, stack_arg_size: usize) -> Address {
frame_pointer + 16 as ByteSize + stack_arg_size
}
#[inline(always)]
......@@ -2179,7 +2179,7 @@ pub fn emit_addr_sym(backend: &mut CodeGenerator, dest: &P<Value>, src: &P<Value
match src.v {
Value_::Memory(ref mem) => {
match mem {
&MemoryLocation::Symbolic{ref label, is_global} => {
&MemoryLocation::Symbolic{ref label, is_global, is_native} => {
if is_global {
// Set dest to be the page address of the entry for src in the GOT
backend.emit_adrp(&dest, &src);
......@@ -2189,7 +2189,12 @@ pub fn emit_addr_sym(backend: &mut CodeGenerator, dest: &P<Value>, src: &P<Value
let offset = P(Value {
hdr: MuEntityHeader::unnamed(vm.next_id()),
ty: UINT64_TYPE.clone(),
v: Value_::Constant(Constant::ExternSym(format!(":got_lo12:{}", label)))
v: Value_::Constant(Constant::ExternSym(
if is_native {
format!("/*C*/:got_lo12:{}", label)
} else {
format!(":got_lo12:{}", mangle_name(label.clone()))
}))
});
// [dest + low 12 bits of the GOT entry for src]
......@@ -2451,7 +2456,8 @@ fn make_value_symbolic(label: MuName, global: bool, ty: &P<MuType>, vm: &VM) ->
ty : ty.clone(),
v : Value_::Memory(MemoryLocation::Symbolic {
label: label,
is_global: global
is_global: global,
is_native: false,
})
})
}
......
......@@ -54,8 +54,7 @@ pub trait CodeGenerator {
// emit code to adjust frame size
fn emit_frame_grow(&mut self);
fn emit_frame_shrink(&mut self);
fn emit_nop(&mut self, bytes: usize);
// comparison
......@@ -221,7 +220,7 @@ pub trait CodeGenerator {
fn emit_js(&mut self, dest: MuName);
// call
fn emit_call_near_rel32(&mut self, callsite: String, func: MuName, pe: Option<MuName>) -> ValueLocation;
fn emit_call_near_rel32(&mut self, callsite: String, func: MuName, pe: Option<MuName>, is_native: bool) -> ValueLocation;
fn emit_call_near_r64 (&mut self, callsite: String, func: &P<Value>, pe: Option<MuName>) -> ValueLocation;
fn emit_call_near_mem64(&mut self, callsite: String, func: &P<Value>, pe: Option<MuName>) -> ValueLocation;
......
......@@ -532,8 +532,8 @@ pub fn get_return_address(frame_pointer: Address) -> Address {
/// gets the stack pointer before the current frame was created
#[inline(always)]
pub fn get_previous_stack_pointer(frame_pointer: Address) -> Address {
frame_pointer + 16 as ByteSize
pub fn get_previous_stack_pointer(frame_pointer: Address, stack_arg_size: usize) -> Address {
frame_pointer + 16 as ByteSize + stack_arg_size
}