mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-19 03:13:40 +00:00
compiler/hlds_rtti.m:
compiler/mlds.m:
As above.
compiler/add_pragma_tabling.m:
compiler/ml_accurate_gc.m:
compiler/ml_code_util.m:
compiler/ml_elim_nested.m:
compiler/ml_util.m:
compiler/mlds_dump.m:
compiler/mlds_to_c_class.m:
compiler/mlds_to_c_data.m:
compiler/mlds_to_c_file.m:
compiler/mlds_to_c_func.m:
compiler/mlds_to_c_name.m:
compiler/mlds_to_c_stmt.m:
compiler/mlds_to_cs_name.m:
compiler/mlds_to_java_name.m:
compiler/proc_label.m:
compiler/rtti_to_mlds.m:
Conform to the changes above.
Simplify some code that does output.
Delete some no-longer-relevant comments.
595 lines
25 KiB
Mathematica
595 lines
25 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2009,2011-2012 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: ml_accurate_gc.m.
|
|
% Main author: fjh.
|
|
%
|
|
% This module is part of the MLDS code generator.
|
|
% It generates the data and code required for accurate gc.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module ml_backend.ml_accurate_gc.
|
|
:- interface.
|
|
|
|
:- import_module ml_backend.ml_gen_info.
|
|
:- import_module ml_backend.mlds.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to handle accurate GC.
|
|
%
|
|
|
|
% ml_gen_gc_statement(Var, Type, Context, Code):
|
|
%
|
|
% If accurate GC is enabled, and the specified variable might contain
|
|
% pointers, generate code to call "private_builtin.gc_trace" to trace
|
|
% the variable.
|
|
%
|
|
:- pred ml_gen_gc_statement(mlds_local_var_name::in, mer_type::in,
|
|
prog_context::in, mlds_gc_statement::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% ml_gen_gc_statement_poly(Var, DeclType, ActualType, Context, Code):
|
|
%
|
|
% This is the same as ml_gen_gc_statement, except that it takes two
|
|
% type arguments, rather than one. The first (DeclType) is the type that
|
|
% the variable was declared with, while the second (ActualType) is that
|
|
% type that the variable is known to have. This is used to generate GC
|
|
% tracing code for the temporaries variables used when calling procedures
|
|
% with polymorphically-typed output arguments. In that case, DeclType
|
|
% may be a type variable from the callee's type declaration, but ActualType
|
|
% will be the type from the caller.
|
|
%
|
|
% We can't just use DeclType to generate the GC trace code, because
|
|
% there is no way to compute the type_info for type variables that
|
|
% come from the callee rather than the current procedure. And we can't
|
|
% just use ActualType, since DeclType may contain pointers even when
|
|
% ActualType doesn't (e.g. because DeclType may be a boxed float).
|
|
% So we need to pass both.
|
|
%
|
|
:- pred ml_gen_gc_statement_poly(mlds_local_var_name::in,
|
|
mer_type::in, mer_type::in, prog_context::in,
|
|
mlds_gc_statement::out, ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
% ml_gen_gc_statement_with_typeinfo(Var, DeclType, TypeInfoRval,
|
|
% Context, Code):
|
|
%
|
|
% This is the same as ml_gen_gc_statement_poly, except that rather
|
|
% than passing ActualType, the caller constructs the typeinfo itself,
|
|
% and just passes the rval for it to this routine.
|
|
%
|
|
% This is used by ml_closure_gen.m to generate GC tracing code
|
|
% for the local variables in closure wrapper functions.
|
|
%
|
|
:- pred ml_gen_gc_statement_with_typeinfo(mlds_local_var_name::in,
|
|
mer_type::in, mlds_rval::in, prog_context::in,
|
|
mlds_gc_statement::out, ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.
|
|
:- import_module check_hlds.polymorphism_type_info.
|
|
:- import_module hlds.
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.instmap.
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.builtin_modules.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.program_representation.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module ml_backend.ml_code_gen.
|
|
:- import_module ml_backend.ml_code_util.
|
|
:- import_module parse_tree.builtin_lib_types.
|
|
:- import_module parse_tree.prog_type.
|
|
:- import_module parse_tree.set_of_var.
|
|
:- import_module parse_tree.var_table.
|
|
|
|
:- import_module bool.
|
|
:- import_module cord.
|
|
:- import_module counter.
|
|
:- import_module int.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to handle accurate GC.
|
|
%
|
|
|
|
ml_gen_gc_statement(VarName, Type, Context, GCStmt, !Info) :-
|
|
ml_gen_gc_statement_poly(VarName, Type, Type, Context, GCStmt, !Info).
|
|
|
|
ml_gen_gc_statement_poly(VarName, DeclType, ActualType, Context, GCStmt,
|
|
!Info) :-
|
|
ml_gen_info_get_gc(!.Info, GC),
|
|
( if GC = gc_accurate then
|
|
HowToGetTypeInfo = construct_from_type(ActualType),
|
|
ml_do_gen_gc_statement(VarName, DeclType, HowToGetTypeInfo, Context,
|
|
GCStmt, !Info)
|
|
else
|
|
GCStmt = gc_no_stmt
|
|
).
|
|
|
|
ml_gen_gc_statement_with_typeinfo(VarName, DeclType, TypeInfoRval, Context,
|
|
GCStmt, !Info) :-
|
|
ml_gen_info_get_gc(!.Info, GC),
|
|
( if GC = gc_accurate then
|
|
HowToGetTypeInfo = already_provided(TypeInfoRval),
|
|
ml_do_gen_gc_statement(VarName, DeclType, HowToGetTypeInfo, Context,
|
|
GCStmt, !Info)
|
|
else
|
|
GCStmt = gc_no_stmt
|
|
).
|
|
|
|
:- type how_to_get_type_info
|
|
---> construct_from_type(mer_type)
|
|
; already_provided(mlds_rval).
|
|
|
|
:- pred ml_do_gen_gc_statement(mlds_local_var_name::in, mer_type::in,
|
|
how_to_get_type_info::in, prog_context::in,
|
|
mlds_gc_statement::out, ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
ml_do_gen_gc_statement(VarName, DeclType, HowToGetTypeInfo, Context, GCStmt,
|
|
!Info) :-
|
|
( if
|
|
ml_gen_info_get_module_info(!.Info, ModuleInfo),
|
|
MLDS_DeclType = mercury_type_to_mlds_type(ModuleInfo, DeclType),
|
|
ml_type_might_contain_pointers_for_gc(MLDS_DeclType) = yes,
|
|
% Don't generate GC tracing code in no_type_info_builtins.
|
|
ml_gen_info_get_pred_proc_id(!.Info, proc(PredId, _ProcId)),
|
|
predicate_id(ModuleInfo, PredId, PredModule, PredName, PredArity),
|
|
not no_type_info_builtin(PredModule, PredName, PredArity)
|
|
then
|
|
(
|
|
HowToGetTypeInfo = construct_from_type(ActualType0),
|
|
% We need to handle type_info/1 and typeclass_info/1
|
|
% types specially, to avoid infinite recursion here...
|
|
( if trace_type_info_type(ActualType0, ActualType1) then
|
|
ActualType = ActualType1
|
|
else
|
|
ActualType = ActualType0
|
|
),
|
|
ml_gen_gc_trace_code(VarName, DeclType, ActualType,
|
|
Context, GC_TraceCode, !Info)
|
|
;
|
|
HowToGetTypeInfo = already_provided(TypeInfoRval),
|
|
ml_gen_trace_var(!.Info, VarName, DeclType, TypeInfoRval,
|
|
Context, GC_TraceCode)
|
|
),
|
|
GCStmt = gc_trace_code(GC_TraceCode)
|
|
else
|
|
GCStmt = gc_no_stmt
|
|
).
|
|
|
|
% Return `yes' if the type needs to be traced by the accurate garbage
|
|
% collector, i.e. if it might contain pointers.
|
|
%
|
|
% Any type for which we return `yes' here must be word-sized, because
|
|
% we will call private_builtin.gc_trace with its address, and that
|
|
% procedure assumes that its argument is an `MR_Word *'.
|
|
%
|
|
% For floats, we can (and must) return `no' even though they might
|
|
% get boxed in some circumstances, because if they are boxed then they will
|
|
% be represented as mlds_generic_type.
|
|
%
|
|
% The only pointers in type_ctor_infos and base_typeclass_infos are
|
|
% to static code and/or static data, which do not need to be traced.
|
|
%
|
|
:- func ml_type_might_contain_pointers_for_gc(mlds_type) = bool.
|
|
|
|
ml_type_might_contain_pointers_for_gc(Type) = MightContainPointers :-
|
|
(
|
|
Type = mercury_nb_type(_, TypeCategory),
|
|
MightContainPointers =
|
|
ml_type_category_might_contain_pointers(TypeCategory)
|
|
;
|
|
Type = mlds_class_type(mlds_class_id(_, _, ClassKind)),
|
|
( if ClassKind = mlds_enum then
|
|
MightContainPointers = no
|
|
else
|
|
MightContainPointers = yes
|
|
)
|
|
;
|
|
( Type = mlds_mercury_array_type(_)
|
|
; Type = mlds_ptr_type(_)
|
|
; Type = mlds_array_type(_)
|
|
; Type = mlds_mostly_generic_array_type(_)
|
|
; Type = mlds_generic_type
|
|
; Type = mlds_generic_env_ptr_type
|
|
; Type = mlds_type_info_type
|
|
; Type = mlds_pseudo_type_info_type
|
|
; Type = mlds_rtti_type(_)
|
|
; Type = mlds_unknown_type
|
|
),
|
|
MightContainPointers = yes
|
|
;
|
|
( Type = mlds_builtin_type_int(_)
|
|
; Type = mlds_builtin_type_float
|
|
; Type = mlds_builtin_type_string
|
|
; Type = mlds_builtin_type_char
|
|
; Type = mlds_native_bool_type
|
|
; Type = mlds_foreign_type(_)
|
|
% We assume that foreign types are not allowed to contain pointers
|
|
% to the Mercury heap. XXX is this requirement too strict?
|
|
; Type = mlds_func_type(_)
|
|
; Type = mlds_cont_type(_)
|
|
; Type = mlds_commit_type
|
|
; Type = mlds_tabling_type(_)
|
|
% Values of mlds_tabling_type types may contain pointers, but
|
|
% they won't exist if we are using accurate GC.
|
|
),
|
|
MightContainPointers = no
|
|
).
|
|
|
|
:- func ml_type_category_might_contain_pointers(type_ctor_category) = bool.
|
|
|
|
ml_type_category_might_contain_pointers(CtorCat) = MayContainPointers :-
|
|
(
|
|
( CtorCat = ctor_cat_builtin(cat_builtin_int(_))
|
|
; CtorCat = ctor_cat_builtin(cat_builtin_char)
|
|
; CtorCat = ctor_cat_builtin(cat_builtin_float)
|
|
; CtorCat = ctor_cat_builtin_dummy
|
|
; CtorCat = ctor_cat_void
|
|
; CtorCat = ctor_cat_enum(_)
|
|
; CtorCat = ctor_cat_system(cat_system_type_ctor_info)
|
|
; CtorCat = ctor_cat_system(cat_system_base_typeclass_info)
|
|
; CtorCat = ctor_cat_user(cat_user_direct_dummy)
|
|
; CtorCat = ctor_cat_user(cat_user_abstract_dummy)
|
|
),
|
|
MayContainPointers = no
|
|
;
|
|
( CtorCat = ctor_cat_builtin(cat_builtin_string)
|
|
; CtorCat = ctor_cat_system(cat_system_type_info)
|
|
; CtorCat = ctor_cat_system(cat_system_typeclass_info)
|
|
; CtorCat = ctor_cat_higher_order
|
|
; CtorCat = ctor_cat_tuple
|
|
; CtorCat = ctor_cat_variable
|
|
; CtorCat = ctor_cat_user(cat_user_notag)
|
|
; CtorCat = ctor_cat_user(cat_user_abstract_notag)
|
|
; CtorCat = ctor_cat_user(cat_user_general)
|
|
),
|
|
MayContainPointers = yes
|
|
).
|
|
|
|
% trace_type_info_type(Type, RealType):
|
|
%
|
|
% Succeed iff Type is a type_info-related type which needs to be copied
|
|
% as if it were some other type, binding RealType to that other type.
|
|
%
|
|
:- pred trace_type_info_type(mer_type::in, mer_type::out) is semidet.
|
|
|
|
trace_type_info_type(Type, RealType) :-
|
|
Type = defined_type(TypeName, _, _),
|
|
TypeName = qualified(PrivateBuiltin, Name),
|
|
PrivateBuiltin = mercury_private_builtin_module,
|
|
( Name = "type_info", RealType = sample_type_info_type
|
|
; Name = "type_ctor_info", RealType = c_pointer_type
|
|
; Name = "typeclass_info", RealType = sample_typeclass_info_type
|
|
; Name = "base_typeclass_info", RealType = c_pointer_type
|
|
; Name = "zero_type_info", RealType = sample_type_info_type
|
|
; Name = "zero_type_ctor_info", RealType = c_pointer_type
|
|
; Name = "zero_typeclass_info", RealType = sample_typeclass_info_type
|
|
; Name = "zero_base_typeclass_info", RealType = c_pointer_type
|
|
).
|
|
|
|
% Generate code to call to `private_builtin.gc_trace'
|
|
% to trace the specified variable.
|
|
%
|
|
:- pred ml_gen_gc_trace_code(mlds_local_var_name::in, mer_type::in,
|
|
mer_type::in, prog_context::in, mlds_stmt::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
ml_gen_gc_trace_code(VarName, DeclType, ActualType, Context, GC_TraceCode,
|
|
!Info) :-
|
|
% Build HLDS code to construct the type_info for this type.
|
|
ml_gen_make_type_info_var(ActualType, Context,
|
|
TypeInfoVar, HLDS_TypeInfoGoals, !Info),
|
|
NonLocalsList = list.map(
|
|
(func(hlds_goal(_GX, GI)) = goal_info_get_nonlocals(GI)),
|
|
HLDS_TypeInfoGoals),
|
|
NonLocals = set_of_var.union_list(NonLocalsList),
|
|
InstMapDelta = instmap_delta_bind_var(TypeInfoVar),
|
|
goal_info_init(NonLocals, InstMapDelta, detism_det, purity_impure,
|
|
GoalInfo),
|
|
conj_list_to_goal(HLDS_TypeInfoGoals, GoalInfo, Conj),
|
|
|
|
% Convert this HLDS code to MLDS.
|
|
ml_gen_goal_as_block(model_det, Conj, MLDS_TypeInfoStmt0, !Info),
|
|
|
|
% Replace all heap allocation (new_object instructions) with stack
|
|
% allocation (local variable declarations) in the code to construct
|
|
% type_infos. This is safe because those type_infos will only be used
|
|
% in the immediately following call to gc_trace/1.
|
|
ml_gen_info_get_module_info(!.Info, ModuleInfo),
|
|
module_info_get_name(ModuleInfo, ModuleName),
|
|
fixup_newobj(mercury_module_name_to_mlds(ModuleName),
|
|
MLDS_TypeInfoStmt0, MLDS_TypeInfoStmt, NewObjLocalVarDefns),
|
|
|
|
% Build MLDS code to trace the variable.
|
|
ml_gen_var_direct(!.Info, TypeInfoVar, TypeInfoLval),
|
|
ml_gen_trace_var(!.Info, VarName, DeclType, ml_lval(TypeInfoLval), Context,
|
|
MLDS_TraceStmt),
|
|
|
|
% Generate declarations for any type_info variables used.
|
|
%
|
|
% Note: this will generate local declarations even for type_info variables
|
|
% which are not local to this goal. However, fortunately ml_elim_nested.m
|
|
% will transform the GC code to use the original definitions, which will
|
|
% get put in the GC frame, rather than these declarations, which will get
|
|
% ignored.
|
|
% XXX This is not a very robust way of doing things...
|
|
ml_gen_info_get_var_table(!.Info, VarTable),
|
|
GenLocalVarDecl =
|
|
( func(Var) = VarDefn :-
|
|
lookup_var_entry(VarTable, Var, Entry),
|
|
LocalVarName = ml_gen_local_var_name(Var, Entry),
|
|
LocalVarType = Entry ^ vte_type,
|
|
VarDefn = ml_gen_mlds_var_decl(LocalVarName,
|
|
mercury_type_to_mlds_type(ModuleInfo, LocalVarType),
|
|
gc_no_stmt, Context)
|
|
),
|
|
set_of_var.to_sorted_list(NonLocals, NonLocalVarList),
|
|
NonLocalVarDefns = list.map(GenLocalVarDecl, NonLocalVarList),
|
|
|
|
% Combine the MLDS code fragments together.
|
|
% XXX MLDS_DEFN
|
|
GC_TraceCode = ml_gen_block(NewObjLocalVarDefns ++ NonLocalVarDefns, [],
|
|
[MLDS_TypeInfoStmt, MLDS_TraceStmt], Context).
|
|
|
|
% ml_gen_trace_var(VarName, DeclType, TypeInfo, Context, Code):
|
|
% Generate a call to `private_builtin.gc_trace' for the specified variable,
|
|
% given the variable's name, type, and the already-constructed type_info
|
|
% for that type.
|
|
%
|
|
:- pred ml_gen_trace_var(ml_gen_info::in, mlds_local_var_name::in,
|
|
mer_type::in, mlds_rval::in, prog_context::in, mlds_stmt::out) is det.
|
|
|
|
ml_gen_trace_var(Info, VarName, Type, TypeInfoRval, Context, TraceStmt) :-
|
|
% Generate the lval for Var.
|
|
ml_gen_info_get_module_info(Info, ModuleInfo),
|
|
MLDS_Type = mercury_type_to_mlds_type(ModuleInfo, Type),
|
|
VarLval = ml_local_var(VarName, MLDS_Type),
|
|
|
|
% Generate the address of `private_builtin.gc_trace/1#0'.
|
|
PredName = "gc_trace",
|
|
PredFormArity = pred_form_arity(1),
|
|
PredLabel = mlds_user_pred_label(pf_predicate, no, PredName, PredFormArity,
|
|
model_det, no),
|
|
ProcId = hlds_pred.initial_proc_id,
|
|
PredModule = mercury_private_builtin_module,
|
|
MLDS_Module = mercury_module_name_to_mlds(PredModule),
|
|
ProcLabel = mlds_proc_label(PredLabel, ProcId),
|
|
FuncLabel = mlds_func_label(ProcLabel, proc_func),
|
|
QualFuncLabel = qual_func_label(MLDS_Module, FuncLabel),
|
|
CPointerType = mercury_nb_type(c_pointer_type,
|
|
ctor_cat_user(cat_user_general)),
|
|
ArgTypes = [mlds_pseudo_type_info_type, CPointerType],
|
|
Signature = mlds_func_signature(ArgTypes, []),
|
|
FuncAddr = ml_const(mlconst_code_addr(
|
|
mlds_code_addr(QualFuncLabel, Signature))),
|
|
|
|
% Generate the call
|
|
% `private_builtin.gc_trace(TypeInfo, (MR_C_Pointer) &Var);'.
|
|
CastVarAddr = ml_cast(CPointerType, ml_mem_addr(VarLval)),
|
|
TraceStmt = ml_stmt_call(Signature, FuncAddr,
|
|
[TypeInfoRval, CastVarAddr], [], ordinary_call, Context).
|
|
|
|
% Generate HLDS code to construct the type_info for this type.
|
|
%
|
|
:- pred ml_gen_make_type_info_var(mer_type::in, prog_context::in,
|
|
prog_var::out, list(hlds_goal)::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
ml_gen_make_type_info_var(Type, Context, TypeInfoVar, TypeInfoGoals, !Info) :-
|
|
ml_gen_info_get_module_info(!.Info, ModuleInfo0),
|
|
ml_gen_info_get_pred_proc_id(!.Info, PredProcId),
|
|
module_info_pred_proc_info(ModuleInfo0, PredProcId, PredInfo0, ProcInfo0),
|
|
% Generate the HLDS code to create the type_infos.
|
|
polymorphism_make_type_info_var_mi(Type, Context,
|
|
TypeInfoVar, TypeInfoGoals, ModuleInfo0, ModuleInfo1,
|
|
PredInfo0, PredInfo, ProcInfo0, ProcInfo),
|
|
module_info_set_pred_proc_info(PredProcId, PredInfo, ProcInfo,
|
|
ModuleInfo1, ModuleInfo),
|
|
% Save the new information back in the ml_gen_info.
|
|
proc_info_get_var_table(ProcInfo, VarTable),
|
|
ml_gen_info_set_module_info(ModuleInfo, !Info),
|
|
ml_gen_info_set_var_table(VarTable, !Info).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type fixup_newobj_info
|
|
---> fixup_newobj_info(
|
|
% The current module.
|
|
fnoi_module_name :: mlds_module_name,
|
|
|
|
% The local variable declarations accumulated so far.
|
|
fnoi_locals :: cord(mlds_local_var_defn),
|
|
|
|
% A counter used to allocate variable names.
|
|
fnoi_next_id :: counter
|
|
).
|
|
|
|
% Replace all heap allocation (new_object instructions) with stack
|
|
% allocation (local variable declarations) in the specified statement,
|
|
% returning the local variable declarations needed for the stack
|
|
% allocation.
|
|
%
|
|
:- pred fixup_newobj(mlds_module_name::in, mlds_stmt::in, mlds_stmt::out,
|
|
list(mlds_local_var_defn)::out) is det.
|
|
|
|
fixup_newobj(ModuleName, Stmt0, Stmt, Defns) :-
|
|
Info0 = fixup_newobj_info(ModuleName, cord.init, counter.init(0)),
|
|
fixup_newobj_in_stmt(Stmt0, Stmt, Info0, Info),
|
|
Defns = cord.to_list(Info ^ fnoi_locals).
|
|
|
|
:- pred fixup_newobj_in_stmt(mlds_stmt::in, mlds_stmt::out,
|
|
fixup_newobj_info::in, fixup_newobj_info::out) is det.
|
|
|
|
fixup_newobj_in_stmt(Stmt0, Stmt, !Fixup) :-
|
|
(
|
|
Stmt0 = ml_stmt_block(LocalVarDefns, FuncDefns, SubStmts0, Context),
|
|
list.map_foldl(fixup_newobj_in_stmt, SubStmts0, SubStmts, !Fixup),
|
|
Stmt = ml_stmt_block(LocalVarDefns, FuncDefns, SubStmts, Context)
|
|
;
|
|
Stmt0 = ml_stmt_while(Kind, Rval, BodyStmt0, LoopLocalVars, Context),
|
|
fixup_newobj_in_stmt(BodyStmt0, BodyStmt, !Fixup),
|
|
Stmt = ml_stmt_while(Kind, Rval, BodyStmt, LoopLocalVars, Context)
|
|
;
|
|
Stmt0 = ml_stmt_if_then_else(Cond, Then0, MaybeElse0, Context),
|
|
fixup_newobj_in_stmt(Then0, Then, !Fixup),
|
|
fixup_newobj_in_maybe_statement(MaybeElse0, MaybeElse, !Fixup),
|
|
Stmt = ml_stmt_if_then_else(Cond, Then, MaybeElse, Context)
|
|
;
|
|
Stmt0 = ml_stmt_switch(Type, Val, Range, Cases0, Default0, Context),
|
|
list.map_foldl(fixup_newobj_in_case, Cases0, Cases, !Fixup),
|
|
fixup_newobj_in_default(Default0, Default, !Fixup),
|
|
Stmt = ml_stmt_switch(Type, Val, Range, Cases, Default, Context)
|
|
;
|
|
( Stmt0 = ml_stmt_label(_Label, _Context)
|
|
; Stmt0 = ml_stmt_goto(_Target, _Context)
|
|
; Stmt0 = ml_stmt_computed_goto(_Rval, _Labels, _Context)
|
|
; Stmt0 = ml_stmt_call(_Sig, _Func, _Args, _RetLvals,
|
|
_TailCall, _Context)
|
|
; Stmt0 = ml_stmt_return(_Rvals, _Context)
|
|
; Stmt0 = ml_stmt_do_commit(_Ref, _Context)
|
|
),
|
|
Stmt = Stmt0
|
|
;
|
|
Stmt0 = ml_stmt_try_commit(Ref, BodyStmt0, HandlerStmt0, Context),
|
|
fixup_newobj_in_stmt(BodyStmt0, BodyStmt, !Fixup),
|
|
fixup_newobj_in_stmt(HandlerStmt0, HandlerStmt, !Fixup),
|
|
Stmt = ml_stmt_try_commit(Ref, BodyStmt, HandlerStmt, Context)
|
|
;
|
|
Stmt0 = ml_stmt_atomic(AtomicStmt0, Context),
|
|
fixup_newobj_in_atomic_statement(AtomicStmt0, Context, Stmt, !Fixup)
|
|
).
|
|
|
|
:- pred fixup_newobj_in_case(mlds_switch_case::in, mlds_switch_case::out,
|
|
fixup_newobj_info::in, fixup_newobj_info::out) is det.
|
|
|
|
fixup_newobj_in_case(Case0, Case, !Fixup) :-
|
|
Case0 = mlds_switch_case(FirstCond, LaterConds, Stmt0),
|
|
fixup_newobj_in_stmt(Stmt0, Stmt, !Fixup),
|
|
Case = mlds_switch_case(FirstCond, LaterConds, Stmt).
|
|
|
|
:- pred fixup_newobj_in_maybe_statement(
|
|
maybe(mlds_stmt)::in, maybe(mlds_stmt)::out,
|
|
fixup_newobj_info::in, fixup_newobj_info::out) is det.
|
|
|
|
fixup_newobj_in_maybe_statement(no, no, !Fixup).
|
|
fixup_newobj_in_maybe_statement(yes(Stmt0), yes(Stmt), !Fixup) :-
|
|
fixup_newobj_in_stmt(Stmt0, Stmt, !Fixup).
|
|
|
|
:- pred fixup_newobj_in_default(mlds_switch_default::in,
|
|
mlds_switch_default::out,
|
|
fixup_newobj_info::in, fixup_newobj_info::out) is det.
|
|
|
|
fixup_newobj_in_default(Default0, Default, !Fixup) :-
|
|
(
|
|
( Default0 = default_is_unreachable
|
|
; Default0 = default_do_nothing
|
|
),
|
|
Default = Default0
|
|
;
|
|
Default0 = default_case(Stmt0),
|
|
fixup_newobj_in_stmt(Stmt0, Stmt, !Fixup),
|
|
Default = default_case(Stmt)
|
|
).
|
|
|
|
:- pred fixup_newobj_in_atomic_statement(mlds_atomic_statement::in,
|
|
prog_context::in, mlds_stmt::out,
|
|
fixup_newobj_info::in, fixup_newobj_info::out) is det.
|
|
|
|
fixup_newobj_in_atomic_statement(AtomicStmt0, Context, Stmt, !Fixup) :-
|
|
( if
|
|
AtomicStmt0 = new_object(Lval, Ptag, _ExplicitSecTag,
|
|
PointerType, _MaybeSizeInWordsRval, _MaybeCtorName,
|
|
ArgRvalsTypes, _MayUseAtomic, _AllocId)
|
|
then
|
|
% Generate the declaration of the new local variable.
|
|
%
|
|
% XXX Using array(generic_type) is wrong for --high-level-data.
|
|
%
|
|
% We need to specify an initializer to tell the C back-end what the
|
|
% length of the array is. We initialize it with null pointers and then
|
|
% later generate assignment statements to fill in the values properly
|
|
% (see below).
|
|
counter.allocate(Id, !.Fixup ^ fnoi_next_id, NextId),
|
|
VarName = lvn_comp_var(lvnc_new_obj(Id)),
|
|
VarType = mlds_array_type(mlds_generic_type),
|
|
NullPointers = list.duplicate(list.length(ArgRvalsTypes),
|
|
init_obj(ml_const(mlconst_null(mlds_generic_type)))),
|
|
Initializer = init_array(NullPointers),
|
|
% This is used for the type_infos allocated during tracing,
|
|
% and we don't need to trace them.
|
|
GCStmt = gc_no_stmt,
|
|
VarDecl = ml_gen_mlds_var_decl_init(VarName, VarType,
|
|
Initializer, GCStmt, Context),
|
|
!Fixup ^ fnoi_next_id := NextId,
|
|
|
|
% XXX We should keep a more structured representation of the local
|
|
% variables, such as a map from variable names.
|
|
Locals0 = !.Fixup ^ fnoi_locals,
|
|
Locals = cord.snoc(Locals0, VarDecl),
|
|
!Fixup ^ fnoi_locals := Locals,
|
|
|
|
% Generate code to initialize the variable.
|
|
%
|
|
% Note that we need to use assignment statements, rather than an
|
|
% initializer, to initialize the local variable, because the
|
|
% initialization code needs to occur at exactly the point where the
|
|
% atomic_statement occurs, rather than at the local variable
|
|
% declaration.
|
|
|
|
VarLval = ml_local_var(VarName, VarType),
|
|
PtrRval = ml_cast(PointerType, ml_mem_addr(VarLval)),
|
|
list.map_foldl(init_field_n(PointerType, PtrRval, Context),
|
|
ArgRvalsTypes, ArgInitStmts, 0, _NumFields),
|
|
|
|
% Generate code to assign the address of the new local variable
|
|
% to the Lval.
|
|
( if Ptag = ptag(0u8) then
|
|
TaggedPtrRval = PtrRval
|
|
else
|
|
TaggedPtrRval = ml_cast(PointerType, ml_mkword(Ptag, PtrRval))
|
|
),
|
|
AssignStmt = ml_stmt_atomic(assign(Lval, TaggedPtrRval), Context),
|
|
Stmt = ml_stmt_block([], [], ArgInitStmts ++ [AssignStmt], Context)
|
|
else
|
|
Stmt = ml_stmt_atomic(AtomicStmt0, Context)
|
|
).
|
|
|
|
:- pred init_field_n(mlds_type::in, mlds_rval::in, prog_context::in,
|
|
mlds_typed_rval::in, mlds_stmt::out, int::in, int::out) is det.
|
|
|
|
init_field_n(PointerType, PointerRval, Context, ArgRvalType, Stmt,
|
|
FieldNum, FieldNum + 1) :-
|
|
ArgRvalType = ml_typed_rval(ArgRval, _ArgType),
|
|
FieldId = ml_field_offset(ml_const(mlconst_int(FieldNum))),
|
|
% XXX FieldType is wrong for --high-level-data: should this be _ArgType?
|
|
FieldType = mlds_generic_type,
|
|
MaybePtag = yes(ptag(0u8)),
|
|
Field = ml_field(MaybePtag, PointerRval, PointerType, FieldId, FieldType),
|
|
Stmt = ml_stmt_atomic(assign(Field, ArgRval), Context).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ml_backend.ml_accurate_gc.
|
|
%---------------------------------------------------------------------------%
|