mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
Move more of the GC logic into the runtime.
This commit is contained in:
parent
a27cbd4ee8
commit
5abc483d9a
@ -196,7 +196,7 @@ let trans_crate
|
|||||||
(lltask:Llvm.llvalue)
|
(lltask:Llvm.llvalue)
|
||||||
(src:Llvm.llvalue)
|
(src:Llvm.llvalue)
|
||||||
: unit =
|
: unit =
|
||||||
upcall llbuilder lltask "upcall_free" None [| src |]
|
upcall llbuilder lltask "upcall_free" None [| src; const_i32 0 |]
|
||||||
in
|
in
|
||||||
|
|
||||||
(*
|
(*
|
||||||
|
@ -1082,7 +1082,7 @@ let trans_visitor
|
|||||||
[|
|
[|
|
||||||
get_copy_glue t None;
|
get_copy_glue t None;
|
||||||
get_drop_glue t None;
|
get_drop_glue t None;
|
||||||
get_free_glue t (slot_mem_ctrl (interior_slot t)) None;
|
get_free_glue t (type_has_state t) None;
|
||||||
get_sever_glue t None;
|
get_sever_glue t None;
|
||||||
get_mark_glue t None;
|
get_mark_glue t None;
|
||||||
|];
|
|];
|
||||||
@ -1580,7 +1580,7 @@ let trans_visitor
|
|||||||
|
|
||||||
and get_free_glue
|
and get_free_glue
|
||||||
(ty:Ast.ty)
|
(ty:Ast.ty)
|
||||||
(mctrl:mem_ctrl)
|
(is_gc:bool)
|
||||||
(curr_iso:Ast.ty_iso option)
|
(curr_iso:Ast.ty_iso option)
|
||||||
: fixup =
|
: fixup =
|
||||||
let g = GLUE_free ty in
|
let g = GLUE_free ty in
|
||||||
@ -1604,49 +1604,7 @@ let trans_visitor
|
|||||||
trans_call_simple_static_glue
|
trans_call_simple_static_glue
|
||||||
(get_drop_glue ty curr_iso) ty_params vr;
|
(get_drop_glue ty curr_iso) ty_params vr;
|
||||||
note_drop_step ty "back in free-glue, calling free";
|
note_drop_step ty "back in free-glue, calling free";
|
||||||
if type_has_state ty
|
trans_free cell is_gc;
|
||||||
then
|
|
||||||
note_drop_step ty "type has state"
|
|
||||||
else
|
|
||||||
note_drop_step ty "type has no state";
|
|
||||||
if mctrl = MEM_gc
|
|
||||||
then
|
|
||||||
begin
|
|
||||||
note_drop_step ty "MEM_gc, unlinking from GC chain";
|
|
||||||
let pcast c =
|
|
||||||
rty_ptr_at (fst (need_mem_cell c)) (Il.ScalarTy wordptr_ty)
|
|
||||||
in
|
|
||||||
let next = pcast (exterior_gc_next_cell cell) in
|
|
||||||
let prev = pcast (exterior_gc_prev_cell cell) in
|
|
||||||
|
|
||||||
note_drop_step ty "MEM_gc, next->prev = prev";
|
|
||||||
let skip_null_next_jmp = null_check next in
|
|
||||||
mov (exterior_gc_prev_cell next) (Il.Cell prev);
|
|
||||||
patch skip_null_next_jmp;
|
|
||||||
|
|
||||||
let skip_null_prev_jmp = null_check prev in
|
|
||||||
note_drop_step ty "MEM_gc, prev->next = next";
|
|
||||||
mov (exterior_gc_next_cell prev) (Il.Cell next);
|
|
||||||
let skip_set_task_chain_jmp = mark () in
|
|
||||||
emit (Il.jmp Il.JMP Il.CodeNone);
|
|
||||||
patch skip_null_prev_jmp;
|
|
||||||
note_drop_step ty "MEM_gc, task->chain = next";
|
|
||||||
let chain =
|
|
||||||
tp_imm (word_n Abi.task_field_gc_alloc_chain)
|
|
||||||
in
|
|
||||||
mov chain (Il.Cell next);
|
|
||||||
patch skip_set_task_chain_jmp;
|
|
||||||
|
|
||||||
note_drop_step ty "MEM_gc, freeing";
|
|
||||||
lea vr (fst (need_mem_cell
|
|
||||||
(exterior_gc_alloc_base cell)));
|
|
||||||
trans_free vr;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
note_drop_step ty "not MEM_gc";
|
|
||||||
trans_free cell;
|
|
||||||
end;
|
|
||||||
trace_str cx.ctxt_sess.Session.sess_trace_drop
|
trace_str cx.ctxt_sess.Session.sess_trace_drop
|
||||||
"free-glue complete";
|
"free-glue complete";
|
||||||
in
|
in
|
||||||
@ -2091,11 +2049,16 @@ let trans_visitor
|
|||||||
trans_cond_fail (Fmt.fmt_to_str Ast.fmt_expr e) fwd_jmps
|
trans_cond_fail (Fmt.fmt_to_str Ast.fmt_expr e) fwd_jmps
|
||||||
| _ -> bugi cx id "check expr on non-bool"
|
| _ -> bugi cx id "check expr on non-bool"
|
||||||
|
|
||||||
and trans_malloc (dst:Il.cell) (nbytes:Il.operand) : unit =
|
and trans_malloc
|
||||||
trans_upcall "upcall_malloc" dst [| nbytes |]
|
(dst:Il.cell)
|
||||||
|
(nbytes:Il.operand)
|
||||||
|
(gc_ctrl_word:Il.operand)
|
||||||
|
: unit =
|
||||||
|
trans_upcall "upcall_malloc" dst [| nbytes; gc_ctrl_word |]
|
||||||
|
|
||||||
and trans_free (src:Il.cell) : unit =
|
and trans_free (src:Il.cell) (is_gc:bool) : unit =
|
||||||
trans_void_upcall "upcall_free" [| Il.Cell src |]
|
let is_gc = if is_gc then 1L else 0L in
|
||||||
|
trans_void_upcall "upcall_free" [| Il.Cell src; imm is_gc |]
|
||||||
|
|
||||||
and trans_yield () : unit =
|
and trans_yield () : unit =
|
||||||
trans_void_upcall "upcall_yield" [| |];
|
trans_void_upcall "upcall_yield" [| |];
|
||||||
@ -2172,14 +2135,20 @@ let trans_visitor
|
|||||||
|
|
||||||
and trans_init_vec (dst:Ast.lval) (atoms:Ast.atom array) : unit =
|
and trans_init_vec (dst:Ast.lval) (atoms:Ast.atom array) : unit =
|
||||||
let (dst_cell, dst_slot) = trans_lval_init dst in
|
let (dst_cell, dst_slot) = trans_lval_init dst in
|
||||||
let unit_slot = match slot_ty dst_slot with
|
let dst_ty = slot_ty dst_slot in
|
||||||
|
let gc_ctrl =
|
||||||
|
if (slot_mem_ctrl dst_slot) = MEM_gc
|
||||||
|
then Il.Cell (get_tydesc None (slot_ty dst_slot))
|
||||||
|
else zero
|
||||||
|
in
|
||||||
|
let unit_slot = match dst_ty with
|
||||||
Ast.TY_vec s -> s
|
Ast.TY_vec s -> s
|
||||||
| _ -> bug () "init dst of vec-init has non-vec type"
|
| _ -> bug () "init dst of vec-init has non-vec type"
|
||||||
in
|
in
|
||||||
let fill = next_vreg_cell word_ty in
|
let fill = next_vreg_cell word_ty in
|
||||||
let unit_sz = slot_sz_in_current_frame unit_slot in
|
let unit_sz = slot_sz_in_current_frame unit_slot in
|
||||||
umul fill unit_sz (imm (Int64.of_int (Array.length atoms)));
|
umul fill unit_sz (imm (Int64.of_int (Array.length atoms)));
|
||||||
trans_upcall "upcall_new_vec" dst_cell [| Il.Cell fill |];
|
trans_upcall "upcall_new_vec" dst_cell [| Il.Cell fill; gc_ctrl |];
|
||||||
let vec = deref dst_cell in
|
let vec = deref dst_cell in
|
||||||
let body_mem =
|
let body_mem =
|
||||||
fst (need_mem_cell
|
fst (need_mem_cell
|
||||||
@ -2251,24 +2220,12 @@ let trans_visitor
|
|||||||
and exterior_rc_cell (cell:Il.cell) : Il.cell =
|
and exterior_rc_cell (cell:Il.cell) : Il.cell =
|
||||||
exterior_ctrl_cell cell Abi.exterior_rc_slot_field_refcnt
|
exterior_ctrl_cell cell Abi.exterior_rc_slot_field_refcnt
|
||||||
|
|
||||||
and exterior_gc_ctrl_cell (cell:Il.cell) : Il.cell =
|
|
||||||
exterior_ctrl_cell cell Abi.exterior_gc_slot_field_ctrl
|
|
||||||
|
|
||||||
and exterior_gc_next_cell (cell:Il.cell) : Il.cell =
|
|
||||||
exterior_ctrl_cell cell Abi.exterior_gc_slot_field_next
|
|
||||||
|
|
||||||
and exterior_gc_prev_cell (cell:Il.cell) : Il.cell =
|
|
||||||
exterior_ctrl_cell cell Abi.exterior_gc_slot_field_prev
|
|
||||||
|
|
||||||
and exterior_gc_alloc_base (cell:Il.cell) : Il.cell =
|
|
||||||
exterior_ctrl_cell cell Abi.exterior_gc_slot_alloc_base
|
|
||||||
|
|
||||||
and exterior_allocation_size
|
and exterior_allocation_size
|
||||||
(slot:Ast.slot)
|
(slot:Ast.slot)
|
||||||
: Il.operand =
|
: Il.operand =
|
||||||
let header_sz =
|
let header_sz =
|
||||||
match slot_mem_ctrl slot with
|
match slot_mem_ctrl slot with
|
||||||
MEM_gc -> word_n Abi.exterior_gc_header_size
|
MEM_gc
|
||||||
| MEM_rc_opaque
|
| MEM_rc_opaque
|
||||||
| MEM_rc_struct -> word_n Abi.exterior_rc_header_size
|
| MEM_rc_struct -> word_n Abi.exterior_rc_header_size
|
||||||
| MEM_interior -> bug () "exterior_allocation_size of MEM_interior"
|
| MEM_interior -> bug () "exterior_allocation_size of MEM_interior"
|
||||||
@ -2494,7 +2451,10 @@ let trans_visitor
|
|||||||
(* Drop the body. *)
|
(* Drop the body. *)
|
||||||
trans_call_dynamic_glue tydesc
|
trans_call_dynamic_glue tydesc
|
||||||
Abi.tydesc_field_drop_glue None [| ty_params; alias body |];
|
Abi.tydesc_field_drop_glue None [| ty_params; alias body |];
|
||||||
trans_free binding;
|
(* FIXME: this will fail if the user has lied about the
|
||||||
|
* state-ness of their obj. We need to store state-ness in the
|
||||||
|
* captured tydesc, and use that. *)
|
||||||
|
trans_free binding (type_has_state ty);
|
||||||
mov binding zero;
|
mov binding zero;
|
||||||
patch rc_jmp;
|
patch rc_jmp;
|
||||||
patch null_jmp
|
patch null_jmp
|
||||||
@ -2620,6 +2580,7 @@ let trans_visitor
|
|||||||
curr_iso
|
curr_iso
|
||||||
|
|
||||||
and free_ty
|
and free_ty
|
||||||
|
(is_gc:bool)
|
||||||
(ty_params:Il.cell)
|
(ty_params:Il.cell)
|
||||||
(ty:Ast.ty)
|
(ty:Ast.ty)
|
||||||
(cell:Il.cell)
|
(cell:Il.cell)
|
||||||
@ -2632,9 +2593,9 @@ let trans_visitor
|
|||||||
| Ast.TY_vec s ->
|
| Ast.TY_vec s ->
|
||||||
iter_seq_slots ty_params cell cell s
|
iter_seq_slots ty_params cell cell s
|
||||||
(fun _ src slot iso -> drop_slot ty_params src slot iso) curr_iso;
|
(fun _ src slot iso -> drop_slot ty_params src slot iso) curr_iso;
|
||||||
trans_free cell
|
trans_free cell is_gc
|
||||||
|
|
||||||
| _ -> trans_free cell
|
| _ -> trans_free cell is_gc
|
||||||
|
|
||||||
and maybe_iso
|
and maybe_iso
|
||||||
(curr_iso:Ast.ty_iso option)
|
(curr_iso:Ast.ty_iso option)
|
||||||
@ -2700,38 +2661,24 @@ let trans_visitor
|
|||||||
let ty = slot_ty slot in
|
let ty = slot_ty slot in
|
||||||
match slot_mem_ctrl slot with
|
match slot_mem_ctrl slot with
|
||||||
MEM_gc ->
|
MEM_gc ->
|
||||||
note_gc_step slot "mark GC slot: check for null:";
|
let tmp = next_vreg_cell Il.voidptr_t in
|
||||||
emit (Il.cmp (Il.Cell cell) zero);
|
trans_upcall "upcall_mark" tmp [| Il.Cell cell |];
|
||||||
let null_cell_jump = mark () in
|
let marked_jump =
|
||||||
emit (Il.jmp Il.JE Il.CodeNone);
|
trans_compare Il.JE (Il.Cell tmp) zero;
|
||||||
let gc_word = exterior_gc_ctrl_cell cell in
|
in
|
||||||
let tmp = next_vreg_cell Il.voidptr_t in
|
(* Iterate over exterior slots marking outgoing links. *)
|
||||||
(* if this has been marked already, jump to exit.*)
|
let (body_mem, _) =
|
||||||
note_gc_step slot "mark GC slot: check for mark:";
|
need_mem_cell
|
||||||
emit (Il.binary Il.AND tmp (Il.Cell gc_word) one);
|
(get_element_ptr (deref cell)
|
||||||
trace_word cx.ctxt_sess.Session.sess_trace_gc tmp;
|
Abi.exterior_gc_slot_field_body)
|
||||||
|
in
|
||||||
let already_marked_jump =
|
let ty = maybe_iso curr_iso ty in
|
||||||
trans_compare Il.JNE (Il.Cell tmp) zero;
|
let curr_iso = maybe_enter_iso ty curr_iso in
|
||||||
in
|
lea tmp body_mem;
|
||||||
(* Set mark bit in allocation header. *)
|
trans_call_simple_static_glue
|
||||||
emit (Il.binary Il.OR gc_word (Il.Cell gc_word) one);
|
(get_mark_glue ty curr_iso)
|
||||||
note_gc_step slot "mark GC slot: set mark";
|
ty_params tmp;
|
||||||
(* Iterate over exterior slots marking outgoing links. *)
|
List.iter patch marked_jump;
|
||||||
let (body_mem, _) =
|
|
||||||
need_mem_cell
|
|
||||||
(get_element_ptr (deref cell)
|
|
||||||
Abi.exterior_gc_slot_field_body)
|
|
||||||
in
|
|
||||||
let ty = maybe_iso curr_iso ty in
|
|
||||||
let curr_iso = maybe_enter_iso ty curr_iso in
|
|
||||||
lea tmp body_mem;
|
|
||||||
trans_call_simple_static_glue
|
|
||||||
(get_mark_glue ty curr_iso)
|
|
||||||
ty_params tmp;
|
|
||||||
patch null_cell_jump;
|
|
||||||
List.iter patch already_marked_jump;
|
|
||||||
note_gc_step slot "mark GC slot: done marking:";
|
|
||||||
|
|
||||||
| MEM_interior when type_is_structured ty ->
|
| MEM_interior when type_is_structured ty ->
|
||||||
(iflog (fun _ ->
|
(iflog (fun _ ->
|
||||||
@ -2814,42 +2761,26 @@ let trans_visitor
|
|||||||
let slot = {slot with Ast.slot_ty = Some ty} in
|
let slot = {slot with Ast.slot_ty = Some ty} in
|
||||||
let mctrl = slot_mem_ctrl slot in
|
let mctrl = slot_mem_ctrl slot in
|
||||||
match mctrl with
|
match mctrl with
|
||||||
MEM_rc_opaque ->
|
MEM_rc_opaque
|
||||||
(* Refcounted opaque objects we handle without glue functions. *)
|
|
||||||
let _ = check_exterior_rty cell in
|
|
||||||
let null_jmp = null_check cell in
|
|
||||||
let j = drop_refcount_and_cmp (exterior_rc_cell cell) in
|
|
||||||
free_ty ty_params ty cell curr_iso;
|
|
||||||
(* Null the slot out to prevent double-free if the frame
|
|
||||||
* unwinds.
|
|
||||||
*)
|
|
||||||
mov cell zero;
|
|
||||||
patch j;
|
|
||||||
patch null_jmp
|
|
||||||
|
|
||||||
| MEM_gc
|
| MEM_gc
|
||||||
| MEM_rc_struct ->
|
| MEM_rc_struct ->
|
||||||
(* Refcounted "structured exterior" objects we handle via
|
|
||||||
* glue functions.
|
|
||||||
*)
|
|
||||||
|
|
||||||
(*
|
|
||||||
* 'GC memory' is treated similarly, just happens to have
|
|
||||||
* an extra couple cells on the front.
|
|
||||||
*)
|
|
||||||
|
|
||||||
(* FIXME (issue #25): check to see that the exterior has
|
|
||||||
* further exterior members; if it doesn't we can elide the
|
|
||||||
* call to the glue function. *)
|
|
||||||
let _ = check_exterior_rty cell in
|
let _ = check_exterior_rty cell in
|
||||||
let null_jmp = null_check cell in
|
let null_jmp = null_check cell in
|
||||||
let rc = exterior_rc_cell cell in
|
let rc = exterior_rc_cell cell in
|
||||||
let _ = note_gc_step slot "dropping refcount on " in
|
|
||||||
let _ = trace_word cx.ctxt_sess.Session.sess_trace_gc rc in
|
|
||||||
let j = drop_refcount_and_cmp rc in
|
let j = drop_refcount_and_cmp rc in
|
||||||
trans_call_simple_static_glue
|
|
||||||
(get_free_glue ty mctrl curr_iso)
|
(* FIXME (issue #25): check to see that the exterior has
|
||||||
ty_params cell;
|
* further exterior members; if it doesn't we can elide the
|
||||||
|
* call to the glue function. *)
|
||||||
|
|
||||||
|
if mctrl = MEM_rc_opaque
|
||||||
|
then
|
||||||
|
free_ty false ty_params ty cell curr_iso
|
||||||
|
else
|
||||||
|
trans_call_simple_static_glue
|
||||||
|
(get_free_glue ty (mctrl = MEM_gc) curr_iso)
|
||||||
|
ty_params cell;
|
||||||
|
|
||||||
(* Null the slot out to prevent double-free if the frame
|
(* Null the slot out to prevent double-free if the frame
|
||||||
* unwinds.
|
* unwinds.
|
||||||
*)
|
*)
|
||||||
@ -2904,57 +2835,22 @@ let trans_visitor
|
|||||||
|
|
||||||
(* Returns the offset of the slot-body in the initialized allocation. *)
|
(* Returns the offset of the slot-body in the initialized allocation. *)
|
||||||
and init_exterior_slot (cell:Il.cell) (slot:Ast.slot) : unit =
|
and init_exterior_slot (cell:Il.cell) (slot:Ast.slot) : unit =
|
||||||
match slot_mem_ctrl slot with
|
let mctrl = slot_mem_ctrl slot in
|
||||||
MEM_gc ->
|
match mctrl with
|
||||||
iflog (fun _ -> annotate "init GC exterior: malloc");
|
MEM_gc
|
||||||
let sz = exterior_allocation_size slot in
|
| MEM_rc_opaque
|
||||||
(*
|
| MEM_rc_struct ->
|
||||||
* Malloc and then immediately shift down to point to
|
let ctrl =
|
||||||
* the pseudo-rc cell.
|
if mctrl = MEM_gc
|
||||||
*)
|
then Il.Cell (get_tydesc None (slot_ty slot))
|
||||||
note_gc_step slot "init GC exterior: malloc slot:";
|
else zero
|
||||||
trans_malloc cell sz;
|
in
|
||||||
add_to cell
|
iflog (fun _ -> annotate "init exterior: malloc");
|
||||||
(imm (word_n Abi.exterior_gc_malloc_return_adjustment));
|
let sz = exterior_allocation_size slot in
|
||||||
note_gc_step slot "init GC exterior: load control word";
|
trans_malloc cell sz ctrl;
|
||||||
let ctrl = exterior_gc_ctrl_cell cell in
|
iflog (fun _ -> annotate "init exterior: load refcount");
|
||||||
let tydesc = get_tydesc None (slot_ty slot) in
|
let rc = exterior_rc_cell cell in
|
||||||
let rc = exterior_rc_cell cell in
|
mov rc one
|
||||||
note_gc_step slot "init GC exterior: set refcount";
|
|
||||||
mov rc one;
|
|
||||||
trace_word cx.ctxt_sess.Session.sess_trace_gc rc;
|
|
||||||
mov ctrl (Il.Cell tydesc);
|
|
||||||
note_gc_step slot "init GC exterior: load chain next-ptr";
|
|
||||||
let next = exterior_gc_next_cell cell in
|
|
||||||
let prev = exterior_gc_prev_cell cell in
|
|
||||||
let chain = tp_imm (word_n Abi.task_field_gc_alloc_chain) in
|
|
||||||
|
|
||||||
note_gc_step slot "init GC exterior: new->prev = 0";
|
|
||||||
mov prev zero;
|
|
||||||
|
|
||||||
note_gc_step slot "init GC exterior: new->next = curr";
|
|
||||||
mov next (Il.Cell chain);
|
|
||||||
|
|
||||||
let null_jmp = null_check chain in
|
|
||||||
let prev = rty_ptr_at (fst (need_mem_cell chain)) word_rty in
|
|
||||||
let chain_prev = exterior_gc_prev_cell prev in
|
|
||||||
note_gc_step slot "init GC exterior: curr->prev = new";
|
|
||||||
mov chain_prev (Il.Cell cell);
|
|
||||||
patch null_jmp;
|
|
||||||
|
|
||||||
note_gc_step slot "init GC exterior: chain = new";
|
|
||||||
mov chain (Il.Cell cell);
|
|
||||||
|
|
||||||
note_gc_step slot "init GC exterior: done initializing"
|
|
||||||
|
|
||||||
| MEM_rc_opaque
|
|
||||||
| MEM_rc_struct ->
|
|
||||||
iflog (fun _ -> annotate "init RC exterior: malloc");
|
|
||||||
let sz = exterior_allocation_size slot in
|
|
||||||
trans_malloc cell sz;
|
|
||||||
iflog (fun _ -> annotate "init RC exterior: load refcount");
|
|
||||||
let rc = exterior_rc_cell cell in
|
|
||||||
mov rc one
|
|
||||||
|
|
||||||
| MEM_interior -> bug () "init_exterior_slot of MEM_interior"
|
| MEM_interior -> bug () "init_exterior_slot of MEM_interior"
|
||||||
|
|
||||||
@ -3452,7 +3348,7 @@ let trans_visitor
|
|||||||
mov fn_cell (crate_rel_imm glue_fixup);
|
mov fn_cell (crate_rel_imm glue_fixup);
|
||||||
iflog (fun _ ->
|
iflog (fun _ ->
|
||||||
annotate "heap-allocate closure to binding slot of pair");
|
annotate "heap-allocate closure to binding slot of pair");
|
||||||
trans_malloc closure_cell (imm closure_sz);
|
trans_malloc closure_cell (imm closure_sz) zero;
|
||||||
trans_init_closure
|
trans_init_closure
|
||||||
(deref closure_cell)
|
(deref closure_cell)
|
||||||
target_fn_ptr target_binding_ptr
|
target_fn_ptr target_binding_ptr
|
||||||
@ -4092,6 +3988,7 @@ let trans_visitor
|
|||||||
match src_ty with
|
match src_ty with
|
||||||
Ast.TY_str
|
Ast.TY_str
|
||||||
| Ast.TY_vec _ ->
|
| Ast.TY_vec _ ->
|
||||||
|
let is_gc = if type_has_state src_ty then 1L else 0L in
|
||||||
let src_cell = need_cell src_oper in
|
let src_cell = need_cell src_oper in
|
||||||
let src_vec = deref src_cell in
|
let src_vec = deref src_cell in
|
||||||
let src_fill = get_element_ptr src_vec Abi.vec_elt_fill in
|
let src_fill = get_element_ptr src_vec Abi.vec_elt_fill in
|
||||||
@ -4108,7 +4005,8 @@ let trans_visitor
|
|||||||
trans_upcall "upcall_vec_grow"
|
trans_upcall "upcall_vec_grow"
|
||||||
dst_cell
|
dst_cell
|
||||||
[| Il.Cell dst_cell;
|
[| Il.Cell dst_cell;
|
||||||
Il.Cell src_fill |];
|
Il.Cell src_fill;
|
||||||
|
imm is_gc |];
|
||||||
|
|
||||||
(*
|
(*
|
||||||
* By now, dst_cell points to a vec/str with room for us
|
* By now, dst_cell points to a vec/str with room for us
|
||||||
@ -4583,7 +4481,7 @@ let trans_visitor
|
|||||||
|
|
||||||
(* Load second cell of pair with pointer to fresh state tuple.*)
|
(* Load second cell of pair with pointer to fresh state tuple.*)
|
||||||
iflog (fun _ -> annotate "malloc state-tuple to obj.state cell");
|
iflog (fun _ -> annotate "malloc state-tuple to obj.state cell");
|
||||||
trans_malloc dst_pair_state_cell state_malloc_sz;
|
trans_malloc dst_pair_state_cell state_malloc_sz zero;
|
||||||
|
|
||||||
(* Copy args into the state tuple. *)
|
(* Copy args into the state tuple. *)
|
||||||
let state_ptr = next_vreg_cell (need_scalar_ty state_ptr_rty) in
|
let state_ptr = next_vreg_cell (need_scalar_ty state_ptr_rty) in
|
||||||
|
@ -595,6 +595,19 @@ struct frame_glue_fns {
|
|||||||
uintptr_t reloc_glue_off;
|
uintptr_t reloc_glue_off;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct gc_alloc {
|
||||||
|
gc_alloc *prev;
|
||||||
|
gc_alloc *next;
|
||||||
|
uintptr_t ctrl_word;
|
||||||
|
uint8_t data[];
|
||||||
|
bool mark() {
|
||||||
|
if (ctrl_word & 1)
|
||||||
|
return false;
|
||||||
|
ctrl_word |= 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct
|
struct
|
||||||
rust_task : public rc_base<rust_task>,
|
rust_task : public rc_base<rust_task>,
|
||||||
public dom_owned<rust_task>,
|
public dom_owned<rust_task>,
|
||||||
@ -604,7 +617,7 @@ rust_task : public rc_base<rust_task>,
|
|||||||
stk_seg *stk;
|
stk_seg *stk;
|
||||||
uintptr_t runtime_sp; // Runtime sp while task running.
|
uintptr_t runtime_sp; // Runtime sp while task running.
|
||||||
uintptr_t rust_sp; // Saved sp when not running.
|
uintptr_t rust_sp; // Saved sp when not running.
|
||||||
uintptr_t gc_alloc_chain; // Linked list of GC allocations.
|
gc_alloc *gc_alloc_chain; // Linked list of GC allocations.
|
||||||
rust_dom *dom;
|
rust_dom *dom;
|
||||||
rust_crate_cache *cache;
|
rust_crate_cache *cache;
|
||||||
|
|
||||||
@ -614,6 +627,8 @@ rust_task : public rc_base<rust_task>,
|
|||||||
uintptr_t* dptr; // Rendezvous pointer for send/recv.
|
uintptr_t* dptr; // Rendezvous pointer for send/recv.
|
||||||
rust_task *spawner; // Parent-link.
|
rust_task *spawner; // Parent-link.
|
||||||
size_t idx;
|
size_t idx;
|
||||||
|
size_t gc_alloc_thresh;
|
||||||
|
size_t gc_alloc_accum;
|
||||||
|
|
||||||
// Wait queue for tasks waiting for this task.
|
// Wait queue for tasks waiting for this task.
|
||||||
rust_wait_queue waiting_tasks;
|
rust_wait_queue waiting_tasks;
|
||||||
@ -633,6 +648,12 @@ rust_task : public rc_base<rust_task>,
|
|||||||
bool blocked_on(rust_cond *cond);
|
bool blocked_on(rust_cond *cond);
|
||||||
bool dead();
|
bool dead();
|
||||||
|
|
||||||
|
void link_gc(gc_alloc *gcm);
|
||||||
|
void unlink_gc(gc_alloc *gcm);
|
||||||
|
void *malloc(size_t sz, type_desc *td=0);
|
||||||
|
void *realloc(void *data, size_t sz, bool gc_mem=false);
|
||||||
|
void free(void *p, bool gc_mem=false);
|
||||||
|
|
||||||
const char *state_str();
|
const char *state_str();
|
||||||
void transition(ptr_vec<rust_task> *svec, ptr_vec<rust_task> *dvec);
|
void transition(ptr_vec<rust_task> *svec, ptr_vec<rust_task> *dvec);
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ static uint32_t read_type_bit_mask() {
|
|||||||
bits |= strstr(env_str, "dwarf") ? rust_log::DWARF : 0;
|
bits |= strstr(env_str, "dwarf") ? rust_log::DWARF : 0;
|
||||||
bits |= strstr(env_str, "cache") ? rust_log::CACHE : 0;
|
bits |= strstr(env_str, "cache") ? rust_log::CACHE : 0;
|
||||||
bits |= strstr(env_str, "timer") ? rust_log::TIMER : 0;
|
bits |= strstr(env_str, "timer") ? rust_log::TIMER : 0;
|
||||||
|
bits |= strstr(env_str, "gc") ? rust_log::GC : 0;
|
||||||
bits |= strstr(env_str, "all") ? rust_log::ALL : 0;
|
bits |= strstr(env_str, "all") ? rust_log::ALL : 0;
|
||||||
}
|
}
|
||||||
return bits;
|
return bits;
|
||||||
|
@ -44,6 +44,7 @@ public:
|
|||||||
CACHE = 0x100,
|
CACHE = 0x100,
|
||||||
UPCALL = 0x200,
|
UPCALL = 0x200,
|
||||||
TIMER = 0x400,
|
TIMER = 0x400,
|
||||||
|
GC = 0x800,
|
||||||
ALL = 0xffffffff
|
ALL = 0xffffffff
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -407,6 +407,84 @@ rust_task::dead()
|
|||||||
return state == &dom->dead_tasks;
|
return state == &dom->dead_tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rust_task::link_gc(gc_alloc *gcm) {
|
||||||
|
I(dom, gcm->prev == NULL);
|
||||||
|
I(dom, gcm->next == NULL);
|
||||||
|
gcm->prev = NULL;
|
||||||
|
gcm->next = gc_alloc_chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rust_task::unlink_gc(gc_alloc *gcm) {
|
||||||
|
if (gcm->prev)
|
||||||
|
gcm->prev->next = gcm->next;
|
||||||
|
if (gcm->next)
|
||||||
|
gcm->next->prev = gcm->prev;
|
||||||
|
gcm->prev = NULL;
|
||||||
|
gcm->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
rust_task::malloc(size_t sz, type_desc *td)
|
||||||
|
{
|
||||||
|
if (td) {
|
||||||
|
sz += sizeof(gc_alloc);
|
||||||
|
}
|
||||||
|
void *mem = dom->malloc(sz);
|
||||||
|
if (!mem)
|
||||||
|
return mem;
|
||||||
|
if (td) {
|
||||||
|
gc_alloc *gcm = (gc_alloc*) mem;
|
||||||
|
dom->log(rust_log::TASK|rust_log::MEM|rust_log::GC,
|
||||||
|
"task 0x%" PRIxPTR " allocated %d GC bytes = 0x%" PRIxPTR,
|
||||||
|
(uintptr_t)this, sz, gcm);
|
||||||
|
memset((void*) gcm, 0, sizeof(gc_alloc));
|
||||||
|
link_gc(gcm);
|
||||||
|
gcm->ctrl_word = (uintptr_t)td;
|
||||||
|
gc_alloc_accum += sz;
|
||||||
|
mem = (void*) &(gcm->data);
|
||||||
|
}
|
||||||
|
return mem;;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
rust_task::realloc(void *data, size_t sz, bool is_gc)
|
||||||
|
{
|
||||||
|
if (is_gc) {
|
||||||
|
gc_alloc *gcm = (gc_alloc*)(((char *)data) - sizeof(gc_alloc));
|
||||||
|
unlink_gc(gcm);
|
||||||
|
sz += sizeof(gc_alloc);
|
||||||
|
gcm = (gc_alloc*) dom->realloc((void*)gcm, sz);
|
||||||
|
dom->log(rust_log::TASK|rust_log::MEM|rust_log::GC,
|
||||||
|
"task 0x%" PRIxPTR " reallocated %d GC bytes = 0x%" PRIxPTR,
|
||||||
|
(uintptr_t)this, sz, gcm);
|
||||||
|
if (!gcm)
|
||||||
|
return gcm;
|
||||||
|
link_gc(gcm);
|
||||||
|
data = (void*) &(gcm->data);
|
||||||
|
} else {
|
||||||
|
data = dom->realloc(data, sz);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rust_task::free(void *p, bool is_gc)
|
||||||
|
{
|
||||||
|
if (is_gc) {
|
||||||
|
gc_alloc *gcm = (gc_alloc*)(((char *)p) - sizeof(gc_alloc));
|
||||||
|
unlink_gc(gcm);
|
||||||
|
dom->log(rust_log::TASK|rust_log::MEM|rust_log::GC,
|
||||||
|
"task 0x%" PRIxPTR " freeing GC memory = 0x%" PRIxPTR,
|
||||||
|
(uintptr_t)this, gcm);
|
||||||
|
dom->free(gcm);
|
||||||
|
} else {
|
||||||
|
dom->free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
rust_task::transition(ptr_vec<rust_task> *src, ptr_vec<rust_task> *dst)
|
rust_task::transition(ptr_vec<rust_task> *src, ptr_vec<rust_task> *dst)
|
||||||
{
|
{
|
||||||
|
@ -324,19 +324,20 @@ upcall_exit(rust_task *task)
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" CDECL uintptr_t
|
extern "C" CDECL uintptr_t
|
||||||
upcall_malloc(rust_task *task, size_t nbytes)
|
upcall_malloc(rust_task *task, size_t nbytes, type_desc *td)
|
||||||
{
|
{
|
||||||
LOG_UPCALL_ENTRY(task);
|
LOG_UPCALL_ENTRY(task);
|
||||||
|
|
||||||
void *p = task->dom->malloc(nbytes);
|
void *p = task->malloc(nbytes, td);
|
||||||
task->dom->log(rust_log::UPCALL|rust_log::MEM,
|
task->dom->log(rust_log::UPCALL|rust_log::MEM,
|
||||||
"upcall malloc(%u) = 0x%" PRIxPTR,
|
"upcall malloc(%u) = 0x%" PRIxPTR
|
||||||
nbytes, (uintptr_t)p);
|
" with gc-chain head = 0x%" PRIxPTR,
|
||||||
|
nbytes, (uintptr_t)p, task->gc_alloc_chain);
|
||||||
return (uintptr_t) p;
|
return (uintptr_t) p;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" CDECL void
|
extern "C" CDECL void
|
||||||
upcall_free(rust_task *task, void* ptr)
|
upcall_free(rust_task *task, void* ptr, uintptr_t is_gc)
|
||||||
{
|
{
|
||||||
LOG_UPCALL_ENTRY(task);
|
LOG_UPCALL_ENTRY(task);
|
||||||
|
|
||||||
@ -344,7 +345,24 @@ upcall_free(rust_task *task, void* ptr)
|
|||||||
dom->log(rust_log::UPCALL|rust_log::MEM,
|
dom->log(rust_log::UPCALL|rust_log::MEM,
|
||||||
"upcall free(0x%" PRIxPTR ")",
|
"upcall free(0x%" PRIxPTR ")",
|
||||||
(uintptr_t)ptr);
|
(uintptr_t)ptr);
|
||||||
dom->free(ptr);
|
task->free(ptr, (bool) is_gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" CDECL uintptr_t
|
||||||
|
upcall_mark(rust_task *task, void* ptr)
|
||||||
|
{
|
||||||
|
LOG_UPCALL_ENTRY(task);
|
||||||
|
|
||||||
|
rust_dom *dom = task->dom;
|
||||||
|
if (ptr) {
|
||||||
|
gc_alloc *gcm = (gc_alloc*) (((char*)ptr) - sizeof(gc_alloc));
|
||||||
|
uintptr_t marked = (uintptr_t) gcm->mark();
|
||||||
|
dom->log(rust_log::UPCALL|rust_log::MEM|rust_log::GC,
|
||||||
|
"upcall mark(0x%" PRIxPTR ") = %" PRIdPTR,
|
||||||
|
(uintptr_t)gcm, marked);
|
||||||
|
return marked;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" CDECL rust_str *
|
extern "C" CDECL rust_str *
|
||||||
@ -368,14 +386,15 @@ upcall_new_str(rust_task *task, char const *s, size_t fill)
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" CDECL rust_vec *
|
extern "C" CDECL rust_vec *
|
||||||
upcall_new_vec(rust_task *task, size_t fill)
|
upcall_new_vec(rust_task *task, size_t fill, type_desc *td)
|
||||||
{
|
{
|
||||||
LOG_UPCALL_ENTRY(task);
|
LOG_UPCALL_ENTRY(task);
|
||||||
rust_dom *dom = task->dom;
|
rust_dom *dom = task->dom;
|
||||||
dom->log(rust_log::UPCALL|rust_log::MEM,
|
dom->log(rust_log::UPCALL|rust_log::MEM,
|
||||||
"upcall new_vec(%" PRIdPTR ")", fill);
|
"upcall new_vec(%" PRIdPTR ")",
|
||||||
|
fill);
|
||||||
size_t alloc = next_power_of_two(sizeof(rust_vec) + fill);
|
size_t alloc = next_power_of_two(sizeof(rust_vec) + fill);
|
||||||
void *mem = dom->malloc(alloc);
|
void *mem = task->malloc(alloc, td);
|
||||||
if (!mem) {
|
if (!mem) {
|
||||||
task->fail(3);
|
task->fail(3);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -389,7 +408,7 @@ upcall_new_vec(rust_task *task, size_t fill)
|
|||||||
|
|
||||||
|
|
||||||
extern "C" CDECL rust_str *
|
extern "C" CDECL rust_str *
|
||||||
upcall_vec_grow(rust_task *task, rust_vec *v, size_t n_bytes)
|
upcall_vec_grow(rust_task *task, rust_vec *v, size_t n_bytes, uintptr_t is_gc)
|
||||||
{
|
{
|
||||||
LOG_UPCALL_ENTRY(task);
|
LOG_UPCALL_ENTRY(task);
|
||||||
rust_dom *dom = task->dom;
|
rust_dom *dom = task->dom;
|
||||||
|
Loading…
Reference in New Issue
Block a user