Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mu-impl-fast
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
40
Issues
40
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
mu
mu-impl-fast
Commits
da783a85
Commit
da783a85
authored
Aug 15, 2017
by
Isaac Oscar Gariano
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reimplemented new thread and stack things for aarch64
parent
7d018fc8
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
457 additions
and
340 deletions
+457
-340
src/ast/src/inst.rs
src/ast/src/inst.rs
+11
-2
src/compiler/backend/arch/aarch64/inst_sel.rs
src/compiler/backend/arch/aarch64/inst_sel.rs
+37
-181
src/compiler/backend/arch/aarch64/mod.rs
src/compiler/backend/arch/aarch64/mod.rs
+179
-2
src/compiler/backend/arch/x86_64/mod.rs
src/compiler/backend/arch/x86_64/mod.rs
+5
-1
src/compiler/backend/mod.rs
src/compiler/backend/mod.rs
+4
-0
src/runtime/asm_common_aarch64.S.inc
src/runtime/asm_common_aarch64.S.inc
+11
-0
src/runtime/entrypoints.rs
src/runtime/entrypoints.rs
+14
-2
src/runtime/runtime_asm_aarch64_sysv.S
src/runtime/runtime_asm_aarch64_sysv.S
+68
-129
src/runtime/thread.rs
src/runtime/thread.rs
+34
-21
src/vm/api/api_impl/muirbuilder.rs
src/vm/api/api_impl/muirbuilder.rs
+89
-0
src/vm/vm.rs
src/vm/vm.rs
+5
-2
No files found.
src/ast/src/inst.rs
View file @
da783a85
...
...
@@ -96,7 +96,8 @@ impl Instruction {
match
self
.v
{
ExprCall
{
..
}
|
ExprCCall
{
..
}
|
Load
{
..
}
|
Store
{
..
}
|
CmpXchg
{
..
}
|
AtomicRMW
{
..
}
|
New
(
_
)
|
AllocA
(
_
)
|
NewHybrid
(
_
,
_
)
|
AllocAHybrid
(
_
,
_
)
|
NewStack
(
_
)
|
NewThread
(
_
,
_
)
|
NewThreadExn
(
_
,
_
)
|
NewFrameCursor
(
_
)
|
Fence
(
_
)
|
Return
(
_
)
|
ThreadExit
|
Throw
(
_
)
|
NewThreadExn
(
_
,
_
)
|
NewFrameCursor
(
_
)
|
Fence
(
_
)
|
Return
(
_
)
|
ThreadExit
|
KillStack
(
_
)
|
Throw
(
_
)
|
TailCall
(
_
)
|
Branch1
(
_
)
|
Branch2
{
..
}
|
Watchpoint
{
..
}
|
WPBranch
{
..
}
|
Call
{
..
}
|
CCall
{
..
}|
SwapStackExpr
{
..
}|
SwapStackExc
{
..
}
|
SwapStackKill
{
..
}
|
Switch
{
..
}
|
ExnInstruction
{
..
}
|
CommonInst_GetThreadLocal
|
CommonInst_SetThreadLocal
(
_
)
|
CommonInst_Pin
(
_
)
|
CommonInst_Unpin
(
_
)
|
...
...
@@ -246,6 +247,12 @@ pub enum Instruction_ {
/// args: functionref of the entry function
NewStack
(
OpIndex
),
/// Kills the given Mu stack
/// args: stackref to kill
KillStack
(
OpIndex
),
CurrentStack
,
/// create a new Mu thread, yields thread reference
/// args: stackref of a Mu stack, a list of arguments
NewThread
(
OpIndex
,
Vec
<
OpIndex
>
),
// stack, args
...
...
@@ -511,7 +518,7 @@ impl Instruction_ {
&
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_
::
NewStack
(
func
)
=>
format!
(
"NEW
_
STACK {}"
,
ops
[
func
]),
&
Instruction_
::
NewThread
(
stack
,
ref
args
)
=>
{
format!
(
"NEWTHREAD {} PASS_VALUES {}"
,
...
...
@@ -557,6 +564,8 @@ impl Instruction_ {
&
Instruction_
::
Return
(
ref
vals
)
=>
format!
(
"RET {}"
,
op_vector_str
(
vals
,
ops
)),
&
Instruction_
::
ThreadExit
=>
"THREADEXIT"
.to_string
(),
&
Instruction_
::
CurrentStack
=>
"CURRENT_STACK"
.to_string
(),
&
Instruction_
::
KillStack
(
s
)
=>
format!
(
"RET {}"
,
ops
[
s
]),
&
Instruction_
::
Throw
(
exn_obj
)
=>
format!
(
"THROW {}"
,
ops
[
exn_obj
]),
&
Instruction_
::
TailCall
(
ref
call
)
=>
format!
(
"TAILCALL {}"
,
call
.debug_str
(
ops
)),
&
Instruction_
::
Branch1
(
ref
dest
)
=>
format!
(
"BRANCH {}"
,
dest
.debug_str
(
ops
)),
...
...
src/compiler/backend/arch/aarch64/inst_sel.rs
View file @
da783a85
This diff is collapsed.
Click to expand it.
src/compiler/backend/arch/aarch64/mod.rs
View file @
da783a85
...
...
@@ -849,7 +849,6 @@ pub fn get_callee_saved_offset(reg: MuID) -> isize {
}*/
pub
fn
is_callee_saved
(
reg_id
:
MuID
)
->
bool
{
for
reg
in
CALLEE_SAVED_GPRS
.iter
()
{
if
reg_id
==
reg
.extract_ssa_id
()
.unwrap
()
{
return
true
;
...
...
@@ -864,6 +863,10 @@ pub fn is_callee_saved(reg_id: MuID) -> bool {
false
}
// The stack size needed for a call to the given function signature
pub
fn
call_stack_size
(
sig
:
P
<
MuFuncSig
>
,
vm
:
&
VM
)
->
usize
{
compute_argument_locations
(
&
sig
.ret_tys
,
&
SP
,
0
,
&
vm
)
.
2
}
// TODO: Check that these numbers are reasonable (THEY ARE ONLY AN ESTIMATE)
use
ast
::
inst
::
*
;
pub
fn
estimate_insts_for_ir
(
inst
:
&
Instruction
)
->
usize
{
...
...
@@ -907,7 +910,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
// runtime
New
(
_
)
|
NewHybrid
(
_
,
_
)
=>
10
,
NewStack
(
_
)
|
NewThread
(
_
,
_
)
|
NewThreadExn
(
_
,
_
)
|
NewFrameCursor
(
_
)
=>
10
,
ThreadExit
=>
10
,
ThreadExit
=>
10
,
CurrentStack
=>
10
,
KillStack
(
_
)
=>
10
,
NewStack
(
_
)
=>
10
,
Throw
(
_
)
=>
10
,
SwapStackExpr
{
..
}
|
SwapStackExc
{
..
}
|
SwapStackKill
{
..
}
=>
10
,
CommonInst_GetThreadLocal
|
CommonInst_SetThreadLocal
(
_
)
=>
10
,
...
...
@@ -2830,3 +2833,177 @@ fn is_int_ex_reg(val: &P<Value>) -> bool {
fn
is_fp_reg
(
val
:
&
P
<
Value
>
)
->
bool
{
RegGroup
::
get_from_value
(
&
val
)
==
RegGroup
::
FPR
&&
(
val
.is_reg
()
||
val
.is_const
())
}
// TODO: Thoroughly test this
// (compare with code generated by GCC with variouse different types???)
// The algorithm presented here is derived from the ARM AAPCS64 reference
// Returns a vector indicating whether each should be passed as an IRef (and not directly),
// a vector referencing to the location of each argument (in memory or a register) and
// the amount of stack space used
// NOTE: It currently does not support vectors/SIMD types (or aggregates of such types)
fn
compute_argument_locations
(
arg_types
:
&
Vec
<
P
<
MuType
>>
,
stack
:
&
P
<
Value
>
,
offset
:
i64
,
vm
:
&
VM
)
->
(
Vec
<
bool
>
,
Vec
<
P
<
Value
>>
,
usize
)
{
if
arg_types
.len
()
==
0
{
// nothing to do
return
(
vec!
[],
vec!
[],
0
);
}
let
mut
ngrn
=
0
as
usize
;
// The Next General-purpose Register Number
let
mut
nsrn
=
0
as
usize
;
// The Next SIMD and Floating-point Register Number
let
mut
nsaa
=
0
as
usize
;
// The next stacked argument address (an offset from the SP)
use
ast
::
types
::
MuType_
::
*
;
// reference[i] = true indicates the argument is passed an IRef to a location on the stack
let
mut
reference
:
Vec
<
bool
>
=
vec!
[];
for
t
in
arg_types
{
reference
.push
(
hfa_length
(
t
)
==
0
&&
// HFA's aren't converted to IRef's
match
t
.v
{
// size can't be statically determined
Hybrid
(
_
)
=>
panic!
(
"Hybrid argument not supported"
),
// type is too large
Struct
(
_
)
|
Array
(
_
,
_
)
if
vm
.get_backend_type_size
(
t
.id
())
>
16
=>
true
,
Vector
(
_
,
_
)
=>
unimplemented!
(),
_
=>
false
}
);
}
// TODO: How does passing arguments by reference effect the stack size??
let
mut
locations
:
Vec
<
P
<
Value
>>
=
vec!
[];
for
i
in
0
..
arg_types
.len
()
{
let
i
=
i
as
usize
;
let
t
=
if
reference
[
i
]
{
P
(
MuType
::
new
(
new_internal_id
(),
MuType_
::
IRef
(
arg_types
[
i
]
.clone
())
))
}
else
{
arg_types
[
i
]
.clone
()
};
let
size
=
align_up
(
vm
.get_backend_type_size
(
t
.id
()),
8
);
let
align
=
get_type_alignment
(
&
t
,
vm
);
match
t
.v
{
Hybrid
(
_
)
=>
panic!
(
"hybrid argument not supported"
),
Vector
(
_
,
_
)
=>
unimplemented!
(),
Float
|
Double
=>
{
if
nsrn
<
8
{
locations
.push
(
get_alias_for_length
(
ARGUMENT_FPRS
[
nsrn
]
.id
(),
get_bit_size
(
&
t
,
vm
)
));
nsrn
+=
1
;
}
else
{
nsrn
=
8
;
locations
.push
(
make_value_base_offset
(
&
stack
,
offset
+
(
nsaa
as
i64
),
&
t
,
vm
));
nsaa
+=
size
;
}
}
Struct
(
_
)
|
Array
(
_
,
_
)
=>
{
let
hfa_n
=
hfa_length
(
&
t
);
if
hfa_n
>
0
{
if
nsrn
+
hfa_n
<=
8
{
// Note: the argument will occupy succesiv registers
// (one for each element)
locations
.push
(
get_alias_for_length
(
ARGUMENT_FPRS
[
nsrn
]
.id
(),
get_bit_size
(
&
t
,
vm
)
/
hfa_n
));
nsrn
+=
hfa_n
;
}
else
{
nsrn
=
8
;
locations
.push
(
make_value_base_offset
(
&
stack
,
offset
+
(
nsaa
as
i64
),
&
t
,
vm
));
nsaa
+=
size
;
}
}
else
{
if
align
==
16
{
ngrn
=
align_up
(
ngrn
,
2
);
// align NGRN to the next even number
}
if
size
<=
8
*
(
8
-
ngrn
)
{
// The struct should be packed, starting here
// (note: this may result in multiple struct fields in the same regsiter
// or even floating points in a GPR)
locations
.push
(
ARGUMENT_GPRS
[
ngrn
]
.clone
());
// How many GPRS are taken up by t
ngrn
+=
if
size
%
8
!=
0
{
size
/
8
+
1
}
else
{
size
/
8
};
}
else
{
ngrn
=
8
;
nsaa
=
align_up
(
nsaa
,
align_up
(
align
,
8
));
locations
.push
(
make_value_base_offset
(
&
stack
,
offset
+
(
nsaa
as
i64
)
as
i64
,
&
t
,
vm
));
nsaa
+=
size
;
}
}
}
Void
=>
panic!
(
"void argument not supported"
),
// Integral or pointer type
_
=>
{
if
size
<=
8
{
if
ngrn
<
8
{
locations
.push
(
get_alias_for_length
(
ARGUMENT_GPRS
[
ngrn
]
.id
(),
get_bit_size
(
&
t
,
vm
)
));
ngrn
+=
1
;
}
else
{
nsaa
=
align_up
(
nsaa
,
align_up
(
align
,
8
));
locations
.push
(
make_value_base_offset
(
&
stack
,
offset
+
(
nsaa
as
i64
)
as
i64
,
&
t
,
vm
));
nsaa
+=
size
;
}
}
else
if
size
==
16
{
ngrn
=
align_up
(
ngrn
,
2
);
// align NGRN to the next even number
if
ngrn
<
7
{
locations
.push
(
ARGUMENT_GPRS
[
ngrn
]
.clone
());
ngrn
+=
2
;
}
else
{
ngrn
=
8
;
nsaa
=
align_up
(
nsaa
,
16
);
locations
.push
(
make_value_base_offset
(
&
stack
,
offset
+
(
nsaa
as
i64
)
as
i64
,
&
t
,
vm
));
nsaa
+=
16
;
}
}
else
{
unimplemented!
();
// Integer type is too large
}
}
}
}
(
reference
,
locations
,
align_up
(
nsaa
,
16
)
as
usize
)
}
src/compiler/backend/arch/x86_64/mod.rs
View file @
da783a85
...
...
@@ -654,7 +654,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
// runtime call
New
(
_
)
|
NewHybrid
(
_
,
_
)
=>
10
,
NewStack
(
_
)
|
NewThread
(
_
,
_
)
|
NewThreadExn
(
_
,
_
)
|
NewFrameCursor
(
_
)
=>
10
,
ThreadExit
=>
10
,
ThreadExit
=>
10
,
CurrentStack
=>
10
,
KillStack
(
_
)
=>
10
,
Throw
(
_
)
=>
10
,
SwapStackExpr
{
..
}
|
SwapStackExc
{
..
}
|
SwapStackKill
{
..
}
=>
10
,
CommonInst_GetThreadLocal
|
CommonInst_SetThreadLocal
(
_
)
=>
10
,
...
...
@@ -668,3 +668,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
_
=>
unimplemented!
()
}
}
pub
fn
call_stack_size
(
sig
:
P
<
MuFuncSig
>
,
vm
:
&
VM
)
->
usize
{
0
}
src/compiler/backend/mod.rs
View file @
da783a85
...
...
@@ -116,6 +116,8 @@ pub use compiler::backend::x86_64::spill_rewrite;
pub
use
compiler
::
backend
::
x86_64
::
ARGUMENT_GPRS
;
#[cfg(target_arch
=
"x86_64"
)]
pub
use
compiler
::
backend
::
x86_64
::
ARGUMENT_FPRS
;
#[cfg(target_arch
=
"x86_64"
)]
pub
use
compiler
::
backend
::
x86_64
::
call_stack_size
;
/// --- aarch64 backend ---
#[cfg(target_arch
=
"aarch64"
)]
...
...
@@ -184,6 +186,8 @@ pub use compiler::backend::aarch64::spill_rewrite;
pub
use
compiler
::
backend
::
aarch64
::
ARGUMENT_GPRS
;
#[cfg(target_arch
=
"aarch64"
)]
pub
use
compiler
::
backend
::
aarch64
::
ARGUMENT_FPRS
;
#[cfg(target_arch
=
"aarch64"
)]
pub
use
compiler
::
backend
::
aarch64
::
call_stack_size
;
use
vm
::
VM
;
use
ast
::
types
::
*
;
...
...
src/runtime/asm_common_aarch64.S.inc
View file @
da783a85
...
...
@@ -94,6 +94,17 @@ pop_pair d3, d2, \stack
pop_pair
d1
,
d0
,
\stack
.
endm
.
macro
load_arguments
stack
=
SP
LDP
D0
,
D1
,
[
\stack
,
#-2*8]
LDP
D2
,
D3
,
[
\stack
,
#-4*8]
LDP
D4
,
D5
,
[
\stack
,
#-6*8]
LDP
D6
,
D7
,
[
\stack
,
#-8*8]
LDP
X0
,
X1
,
[
\stack
,
#-10*8]
LDP
X2
,
X3
,
[
\stack
,
#-12*8]
LDP
X4
,
X5
,
[
\stack
,
#-14*8]
LDP
X6
,
X7
,
[
\stack
,
#-16*8]
.
endm
.
macro
mov_args_to_callee_saved
MOV
X19
,
X0
MOV
X20
,
X1
...
...
src/runtime/entrypoints.rs
View file @
da783a85
...
...
@@ -57,14 +57,26 @@ lazy_static! {
// impl: runtime_asm_ARCH_OS.s
// decl: thread.rs
pub
static
ref
SWAP_BACK_TO_NATIVE_STACK
:
RuntimeEntrypoint
=
RuntimeEntrypoint
{
pub
static
ref
MUENTRY_THREAD_EXIT
:
RuntimeEntrypoint
=
RuntimeEntrypoint
{
sig
:
P
(
MuFuncSig
{
hdr
:
MuEntityHeader
::
unnamed
(
ir
::
new_internal_id
()),
ret_tys
:
vec!
[],
arg_tys
:
vec!
[
ADDRESS_TYPE
.clone
()]
}),
aot
:
ValueLocation
::
Relocatable
(
RegGroup
::
GPR
,
String
::
from
(
"muentry_swap_back_to_native_stack"
)),
String
::
from
(
"muentry_thread_exit"
)),
jit
:
RwLock
::
new
(
None
),
};
}
lazy_static!
{
// impl/decl: thread.rs
pub
static
ref
MUENTRY_NEW_STACK
:
RuntimeEntrypoint
=
RuntimeEntrypoint
{
sig
:
P
(
MuFuncSig
{
hdr
:
MuEntityHeader
::
unnamed
(
ir
::
new_internal_id
()),
ret_tys
:
vec!
[
STACKREF_TYPE
.clone
()],
arg_tys
:
vec!
[
ADDRESS_TYPE
.clone
(),
ADDRESS_TYPE
.clone
()]
}),
aot
:
ValueLocation
::
Relocatable
(
RegGroup
::
GPR
,
String
::
from
(
"muentry_new_stack"
)),
jit
:
RwLock
::
new
(
None
),
};
...
...
src/runtime/runtime_asm_aarch64_sysv.S
View file @
da783a85
...
...
@@ -16,75 +16,6 @@
#include "asm_common_aarch64.S.inc"
#
swap_stack_to
(
new_sp
:
Address
,
entry
:
Address
,
old_sp_loc
:
Address
)
#
X0
X1
X2
begin_func
swap_to_mu_stack
#
--
on
old
stack
--
enter_frame
#
push
all
callee
-
saved
registers
push_callee_saved
#
*
old_sp_loc
=
SP
MOV
X9
,
SP
STR
X9
,
[
X2
]
#
sp
=
new_sp
MOV
SP
,
X0
#
x9
=
entry
MOV
X9
,
X1
#
--
on
new
stack
--
#
arguments
(
reverse
order
of
thread
.
rs
-
runtime_load_args
)
pop_arguments
#
If
entry
tries
to
return
(
IT
SHOULDN
'T) it will call entry_returned (which will panic!)
ADR
LR
,
entry_returned
#
branch
to
entry
//
MOV
FP
,
0
//
End
of
call
frame
RET
X9
end_func
swap_to_mu_stack
#
The
error
message
to
print
when
entry
returns
.
type
.
Lentry_returned_message
,
@
object
.
section
.
rodata
.
str1
.1
,
"aMS"
,
@
progbits
,
1
.
Lentry_returned_message
:
.
asciz
"ERROR: The entry function returned\n"
.
size
.
Lentry_returned_message
,
36
#
Prints
an
error
mesage
and
calls
exit
(
1
)
begin_func
entry_returned
ADRP
x0
,
.
Lentry_returned_message
ADD
x0
,
x0
,
:
lo12
:
.
Lentry_returned_message
//
Loads
x0
with
the
adress
of
.
Lentry_returned_message
MOV
X1
,
#
35
//
Length
of
string
MOV
X2
,
#
1
//
Number
of
elements
ADRP
X3
,
:
got
:
stderr
LDR
X3
,
[
X3
,
:
got_lo12
:
stderr
]
LDR
X3
,
[
X3
]
//
Load
X3
with
the
address
of
stderr
BL
fwrite
//
calls
fwrite
(
x0
,
x1
,
x2
,
x3
)
MOV
W0
,
1
BL
exit
//
call
exit
(
1
)
end_func
entry_returned
//
_swap_back_to_native_stack
(
sp_loc
:
Address
)
//
X0
begin_func
muentry_swap_back_to_native_stack
#
SP
=
*
sp_loc
LDR
X9
,
[
X0
]
MOV
SP
,
X9
pop_callee_saved
#
Restore
the
previouse
frame
(
and
return
to
its
return
location
)
exit_frame
RET
end_func
muentry_swap_back_to_native_stack
#
_get_current_frame_bp
()
->
Address
#
X0
begin_func
get_current_frame_bp
...
...
@@ -114,40 +45,17 @@ begin_func exception_restore
BR
X0
end_func
exception_restore
#
swap
to
the
new
stack
whilst
passing
values
and
saving
the
old
stack
#
muentry_swapstack_ret_pass
(
new_stack
args
...
,
new_sp
:
Address
,
old_sp_loc
:
&
mut
Adress
)
#
X0
...
X7
[
x8
]
X9
X10
begin_func
muentry_swapstack_ret_pass
enter_frame
push_callee_saved
#
Save
the
current
stack
pointer
MOV
X11
,
SP
STR
X11
,
[
X10
]
#
Swap
to
new
stack
MOV
SP
,
X9
#
Swapstack
internals
.
macro
stack_pass
new_sp
MOV
SP
,
\
new_sp
#
On
the
new
stack
,
reverse
the
above
pop_callee_saved
exit_frame
RET
end_func
muentry_swapstack_ret_pass
#
Same
as
swapstack_ret_pass
except
will
throw
an
exception
to
the
new
stack
instead
of
passing
values
#
muentry_swapstack_ret_throw
(
exception
:
Address
,
new_sp
:
Address
,
old_sp_loc
:
&
mut
Adress
)
#
X0
X1
X2
begin_func
muentry_swapstack_ret_throw
enter_frame
push_callee_saved
#
Save
the
current
stack
pointer
MOV
X3
,
SP
STR
X3
,
[
X2
]
#
Swap
to
new
stack
MOV
SP
,
X1
.
endm
.
macro
stack_throw
new_sp
MOV
SP
,
\
new_sp
#
The
new
stack
will
have
the
same
layout
as
the
stack
when
muentry_throw_exception
#
calls
throw_exception_internal
,
so
we
can
do
that
directly
here
...
...
@@ -155,47 +63,78 @@ begin_func muentry_swapstack_ret_throw
ADD
FP
,
SP
,
144
MOV
X1
,
FP
BL
throw_exception_internal
.
endm
#
won
't return
end_func
muentry_swapstack_ret_throw
.
macro
stack_ret
old_sp
enter_frame
push_callee_saved
#
swap
to
the
new
stack
whilst
passing
values
and
killing
the
old
stack
#
muentry_swapstack_kill_pass
(
new_stack
args
...
,
new_sp
:
Address
,
old_stack
:
*
mut
MuStack
)
#
X0
...
X7
[
x8
]
X9
X10
begin_func
muentry_swapstack_kill_pass
#
Swap
to
new
stack
MOV
SP
,
X9
MOV
X11
,
SP
STR
X11
,
[
\
old_sp
]
.
endm
.
macro
stack_kill
old_sp
mov_args_to_callee_saved
MOV
X0
,
X10
MOV
X0
,
\
old_sp
B
muentry_kill_stack
mov_callee_saved_to_args
.
endm
#
On
the
new
stack
,
reverse
muentry_swapstack_ret_pass
pop_callee_saved
exit_frame
RET
end_func
muentry_swapstack_kill_pass
#
starts
a
muthread
that
passes
values
to
the
target
(
with
the
given
memory
area
containg
values
of
argument
registers
)
#
(
new_sp
:
Address
,
old_sp_loc
:
Address
)
#
X0
X1
,
begin_func
muthread_start_pass
stack_ret
X1
MOV
X9
,
X0
#
X1
will
be
overriden
by
the
next
instructions
load_arguments
X9
stack_pass
X9
end_func
muthread_start_pass
#
Same
as
muentry_swapstack_kill_pass
except
will
throw
an
exception
to
the
new
stack
instead
of
passing
values
#
muentry_swapstack_kill_throw
(
exception
:
Address
,
new_sp
:
Address
,
old_stack
:
*
mut
MuStack
)
#
Same
as
muentry_swapstack_ret_throw
#
muthread_start_throw
(
exception
:
Address
,
new_sp
:
Address
,
old_sp_loc
:
&
mut
Adress
)
#
X0
X1
X2
begin_func
muentry_swapstack_kill_throw
#
Swap
to
new
stack
MOV
SP
,
X1
begin_func
muthread_start_throw
stack_ret
X2
stack_throw
X1
end_func
muthread_start_throw
#
restores
the
thread
#
(
new_sp
:
Address
)
#
X0
begin_func
muentry_thread_exit
#
Rust
code
will
be
responsible
for
actually
killing
the
stack
stack_pass
X0
end_func
muentry_thread_exit
mov_args_to_callee_saved
MOV
X0
,
X9
B
muentry_kill_stack
mov_callee_saved_to_args
#
swap
to
the
new
stack
whilst
passing
values
and
saving
the
old
stack
#
muentry_swapstack_ret_pass
(
new_stack
args
...
,
new_sp
:
Address
,
old_sp_loc
:
&
mut
Adress
)
#
X0
...
X7
[
x8
]
X9
X10
begin_func
muentry_swapstack_ret_pass
stack_ret
X10
stack_pass
X9
end_func
muentry_swapstack_ret_pass
#
The
new
stack
will
have
the
same
layout
as
the
stack
when
muentry_throw_exception
#
calls
throw_exception_internal
,
so
we
can
do
that
directly
here
#
Same
as
swapstack_ret_pass
except
will
throw
an
exception
to
the
new
stack
instead
of
passing
values
#
muentry_swapstack_ret_throw
(
exception
:
Address
,
new_sp
:
Address
,
old_sp_loc
:
&
mut
Adress
)
#
X0
X1
X2
begin_func
muentry_swapstack_ret_throw
stack_ret
X2
stack_throw
X1
end_func
muentry_swapstack_ret_throw
#
Add
the
total
size
pushed
by
'push_callee_saved'
to
get
the
FP
for
the
new
stack
ADD
FP
,
SP
,
144
MOV
X1
,
FP
BL
throw_exception_internal
#
swap
to
the
new
stack
whilst
passing
values
and
killing
the
old
stack
#
muentry_swapstack_kill_pass
(
new_stack
args
...
,
new_sp
:
Address
,
old_stack
:
*
mut
MuStack
)
#
X0
...
X7
[
x8
]
X9
X10
begin_func
muentry_swapstack_kill_pass
stack_kill
X10
stack_pass
X9
end_func
muentry_swapstack_kill_pass
#
won
't return
end_func
muentry_swapstack_kill_throw
\ No newline at end of file
#
Same
as
muentry_swapstack_kill_pass
except
will
throw
an
exception
to
the
new
stack
instead
of
passing
values
#
muentry_swapstack_kill_throw
(
exception
:
Address
,
new_sp
:
Address
,
old_stack
:
*
mut
MuStack
)
#
X0
X1
X2
begin_func
muentry_swapstack_kill_throw
stack_kill
X2
stack_throw
X1
end_func
muentry_swapstack_kill_throw
src/runtime/thread.rs
View file @
da783a85
...
...
@@ -19,10 +19,13 @@ use vm::VM;
use
runtime
;
use
runtime
::
ValueLocation
;
use
runtime
::
mm
;
use
compiler
::
backend
::
CALLEE_SAVED_COUNT
;
use
utils
::
ByteSize
;
use
utils
::
Address
;
use
utils
::
Word
;
use
utils
::
POINTER_SIZE
;
use
utils
::
WORD_SIZE
;
use
utils
::
mem
::
memmap
;
use
utils
::
mem
::
memsec
;
...
...
@@ -107,7 +110,7 @@ pub struct MuStack {
impl
MuStack
{
/// creates a new MuStack for given entry function and function address
pub
fn
new
(
id
:
MuID
,
func_addr
:
ValueLocation
,
func
:
&
MuFunction
)
->
MuStack
{
pub
fn
new
(
id
:
MuID
,
func_addr
:
Address
,
stack_arg_size
:
usize
)
->
MuStack
{
// allocate memory for the stack
let
anon_mmap
=
{
// reserve two guard pages more than we need for the stack
...
...
@@ -141,17 +144,31 @@ impl MuStack {
);
}
debug!
(
"creating stack {} with entry
func {:?}"
,
id
,
func
);
debug!
(
"creating stack {} with entry
address {:?}"
,
id
,
func_addr
);
debug!
(
"overflow_guard : {}"
,
overflow_guard
);
debug!
(
"lower_bound : {}"
,
lower_bound
);
debug!
(
"upper_bound : {}"
,
upper_bound
);
debug!
(
"underflow_guard: {}"
,
underflow_guard
);
// Set up the stack
let
mut
sp
=
upper_bound
;
sp
-=
stack_arg_size
;
// Allocate space for the arguments
// Push entry as the return address
sp
-=
POINTER_SIZE
;
unsafe
{
sp
.store
(
func_addr
);
}
// Push a null frame pointer
sp
-=
POINTER_SIZE
;
unsafe
{
sp
.store
(
Address
::
zero
());
}
// Reserve space for callee saved registers (they will be loaded with undefined values)
sp
-=
WORD_SIZE
*
CALLEE_SAVED_COUNT
;
MuStack
{
hdr
:
MuEntityHeader
::
unnamed
(
id
),
func
:
Some
((
func_addr
,
func
.id
())),
state
:
MuStackState
::
Ready
(
func
.sig.arg_tys
.clone
()),
func
:
None
,
state
:
MuStackState
::
Unknown
,
size
:
STACK_SIZE
,
overflow_guard
:
overflow_guard
,
...
...
@@ -159,7 +176,7 @@ impl MuStack {
upper_bound
:
upper_bound
,
underflow_guard
:
upper_bound
,
sp
:
upper_bound
,
sp
:
sp
,
bp
:
upper_bound
,
ip
:
unsafe
{
Address
::
zero
()
},
...
...
@@ -230,9 +247,6 @@ impl MuStack {
}
}
// save it back
self
.sp
=
stack_ptr
;
if
cfg!
(
debug_assertions
)
{
self
.print_stack
(
Some
(
20
));
}
...
...
@@ -277,7 +291,8 @@ pub enum MuStackState {
/// running mu code
Active
,
/// can be destroyed
Dead
Dead
,
Unknown
,
}
/// MuThread represents metadata for a Mu thread.
...
...
@@ -374,14 +389,7 @@ extern "C" {
/// new_sp: stack pointer for the mu stack
/// entry : entry function for the mu stack
/// old_sp_loc: the location to store native stack pointer so we can later swap back
fn
swap_to_mu_stack
(
new_sp
:
Address
,
entry
:
Address
,
old_sp_loc
:
Address
);
/// swaps from a mu stack back to native stack
/// emitted by the compiler for THREADEXIT IR
/// args:
/// sp_loc: the location of native stack pointer
#[allow(dead_code)]
// we are not using this function directly, but compiler will emit calls to it
fn
muentry_swap_back_to_native_stack
(
sp_loc
:
Address
);
fn
muthread_start_pass
(
new_sp
:
Address
,
old_sp_loc
:
Address
);
/// gets base poniter for current frame
pub
fn
get_current_frame_bp
()
->
Address
;
...
...
@@ -466,8 +474,6 @@ impl MuThread {
vm
:
Arc
<
VM
>
)
->
JoinHandle
<
()
>
{
let
new_sp
=
stack
.sp
;
let
entry
=
runtime
::
resolve_symbol
(
vm
.name_of
(
stack
.func
.as_ref
()
.unwrap
()
.
1
));
debug!
(
"entry : 0x{:x}"
,
entry
);
match
thread
::
Builder
::
new
()
.name
(
format!
(
"Mu Thread #{}"
,
id
))
...
...
@@ -483,7 +489,7 @@ impl MuThread {
debug!
(
"sp_store: 0x{:x}"
,
sp_threadlocal_loc
);
unsafe
{
swap_to_mu_stack
(
new_sp
,
entry
,
sp_threadlocal_loc
);
muthread_start_pass
(
new_sp
,
sp_threadlocal_loc
);
}
debug!
(
"returned to Rust stack. Going to quit"
);
...
...
@@ -663,6 +669,13 @@ pub unsafe extern "C" fn muentry_prepare_swapstack_kill(new_stack: *mut MuStack)
((
*
new_stack
)
.sp
,
cur_stack
)
}
#[no_mangle]
pub
unsafe
extern
"C"
fn
muentry_new_stack
(
entry
:
Address
,
stack_size
:
usize
)
->
*
mut
MuStack
{
let
ref
vm
=
MuThread
::
current_mut
()
.vm
;
let
stack
=
Box
::
new
(
MuStack
::
new
(
vm
.next_id
(),
entry
,
stack_size
));
return
Box
::
into_raw
(
stack
);
}
// Kills the given stack. WARNING! do not call this whilst on the given stack
#[no_mangle]
pub
unsafe
extern
"C"
fn
muentry_kill_stack
(
stack
:
*
mut
MuStack
)
{
...
...
src/vm/api/api_impl/muirbuilder.rs
View file @
da783a85
...
...
@@ -1269,6 +1269,7 @@ struct BundleLoader<'lb, 'lvm> {