mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-19 07:45:09 +00:00
Extend the layout scheme to handle typeinfos inside typeclass infos,
Estimated hours taken: 16
Extend the layout scheme to handle typeinfos inside typeclass infos,
and thus enable the debugger (and later native gc) to work with programs
that use type classes and existential types.
compiler/llds.m:
Change the data structure that holds information about the locations
of the typeinfo variables of the tvars active at call return sites
from set(pair(tvar, lval)) to map(tvar, set(layout_locn)).
The change from set to map avoids the possibility of inadvertently
duplicating the info for a give type variable.
The change to explicitly keep a set of locations in which the typeinfo
var may be found allows us to use set intersection on those sets if
(a) the program point may be reached via more than one path, and
(b) not all paths have the same sets. Both of these can happen in
programs that use type classes.
The change from lval to layout_locn (which encodes either an lval,
or an lval representing a typeclass info and an (indirect) offset
inside that typeclass info) is necessary support programs with
type classes.
compiler/continuation_info.m:
Change the data structure that holds information about the locations
of the typeinfo variables of the tvars active at a particular program
point the same way and for the same reasons as in llds.m.
Take set intersections of typeinfo var locations whenever we find
multiple live variable info records for the same label.
compiler/call_gen.m:
Delay the construction of the return live variable information
until the code generator state has been updated to reflect where
things will be on return, instead of trying to cobble up this
info into the code generator state that reflects the point just
before the call. Apart from being cleaner, this is necessary
to avoid compiler aborts for programs that use existential types.
The old compiler could not find the typeinfos of any existentially
quantified type vars, since they do not exist before the call.
compiler/code_info.m:
Rewrite and generalize the code for generating live value information.
compiler/trace.m:
Remove the specialized code for generating live value information;
call code_info instead.
compiler/stack_layout.m:
Pick one of several possible locations for a typeinfo var.
Generate the new indirect layout location descriptions.
Reduce the number of tag bits used to describe different kinds of
lvals, to leave more room for the indirect information.
compiler/*.m:
Conform to the above data structure changes.
compiler/hlds_pred.m:
Clarify the documentation of type_info_locn.
runtime/mercury_stack_layout.h:
Update the section that deals with MR_Live_Lval to take
indirect typeinfo locations into account.
runtime/mercury_layout_util.c:
Handle indirect typeinfo locations when interpreting layout structures.
runtime/mercury_layout_util.c:
trace/mercury_trace_internal.c:
Ignore variables whose names start with TypeClassInfo.
runtime/mercury_accurate_gc.c:
runtime/mercury_agc_debug.c:
Add markers to remind Tyson to handle indirect typeinfo locations.
tests/debugger/implied_instance.{m,inp,exp}:
tests/debugger/multi_paramster.{m,inp,exp}:
tests/debugger/existential_type_classes.{m,inp,exp}:
Copies of the tests in tests/hard_coded/typeclasses, modified to
avoid or delay I/O, so that the calls to I/O preds that may or may
not be traced to do not affect the output.
tests/debugger/Mmakefile:
Add the new test cases.
Remove references to the *_lib variants of the old test cases.
They are not necessary if I/O is delayed until after the last
reported trace event.
tests/hard_coded/typeclasses/Mmakefile:
Remove --trace deep from existential_type_classes, since that
aspect of the test case is now covered in the debugger directory.
This commit is contained in:
@@ -287,7 +287,7 @@ stack_layout__construct_proc_layout(EntryLabel, Detism, StackSlots,
|
||||
;
|
||||
SuccipLval = stackvar(Location)
|
||||
},
|
||||
{ stack_layout__represent_lval(SuccipLval, SuccipRval) },
|
||||
{ stack_layout__represent_locn(direct(SuccipLval), SuccipRval) },
|
||||
{ StackSlotsRval = const(int_const(StackSlots)) },
|
||||
{ CodeAddrRval = const(code_addr_const(label(EntryLabel))) },
|
||||
|
||||
@@ -429,32 +429,32 @@ stack_layout__construct_internal_rvals(Internal, RvalList) -->
|
||||
{
|
||||
Port = no,
|
||||
set__init(PortLiveVarSet),
|
||||
set__init(PortTypeVarSet)
|
||||
map__init(PortTypeVarMap)
|
||||
;
|
||||
Port = yes(layout_label_info(PortLiveVarSet, PortTypeVarSet))
|
||||
Port = yes(layout_label_info(PortLiveVarSet, PortTypeVarMap))
|
||||
},
|
||||
stack_layout__get_agc_stack_layout(AgcStackLayout),
|
||||
{
|
||||
Return = no,
|
||||
set__init(ReturnLiveVarSet),
|
||||
set__init(ReturnTypeVarSet)
|
||||
map__init(ReturnTypeVarMap)
|
||||
;
|
||||
Return = yes(layout_label_info(ReturnLiveVarSet0,
|
||||
ReturnTypeVarSet0)),
|
||||
ReturnTypeVarMap0)),
|
||||
( AgcStackLayout = yes ->
|
||||
ReturnLiveVarSet = ReturnLiveVarSet0,
|
||||
ReturnTypeVarSet0 = ReturnTypeVarSet
|
||||
ReturnTypeVarMap = ReturnTypeVarMap0
|
||||
;
|
||||
% This set of variables must be for uplevel printing
|
||||
% in execution tracing, so we are interested only
|
||||
% in (a) variables, not temporaries, (b) only named
|
||||
% variables, and (c) only those on the stack, not
|
||||
% the return valies.
|
||||
% the return values.
|
||||
set__to_sorted_list(ReturnLiveVarSet0,
|
||||
ReturnLiveVarList0),
|
||||
stack_layout__select_trace_return(
|
||||
ReturnLiveVarList0, ReturnTypeVarSet0,
|
||||
ReturnLiveVarList, ReturnTypeVarSet),
|
||||
ReturnLiveVarList0, ReturnTypeVarMap0,
|
||||
ReturnLiveVarList, ReturnTypeVarMap),
|
||||
set__list_to_set(ReturnLiveVarList, ReturnLiveVarSet)
|
||||
)
|
||||
},
|
||||
@@ -468,19 +468,21 @@ stack_layout__construct_internal_rvals(Internal, RvalList) -->
|
||||
% which may not be true.)
|
||||
{ RvalList = [yes(const(int_const(-1)))] }
|
||||
;
|
||||
% XXX ignore differences in insts inside var_infos
|
||||
{ set__union(PortLiveVarSet, ReturnLiveVarSet, LiveVarSet) },
|
||||
{ set__union(PortTypeVarSet, ReturnTypeVarSet, TypeVarSet) },
|
||||
stack_layout__construct_livelval_rvals(LiveVarSet, TypeVarSet,
|
||||
RvalList)
|
||||
{ map__union(set__intersect, PortTypeVarMap, ReturnTypeVarMap,
|
||||
TypeVarMap) },
|
||||
stack_layout__construct_livelval_rvals(LiveVarSet,
|
||||
TypeVarMap, RvalList)
|
||||
).
|
||||
|
||||
%---------------------------------------------------------------------------%
|
||||
|
||||
:- pred stack_layout__construct_livelval_rvals(set(var_info)::in,
|
||||
set(pair(tvar, lval))::in, list(maybe(rval))::out,
|
||||
map(tvar, set(layout_locn))::in, list(maybe(rval))::out,
|
||||
stack_layout_info::in, stack_layout_info::out) is det.
|
||||
|
||||
stack_layout__construct_livelval_rvals(LiveLvalSet, TVarLocnSet, RvalList) -->
|
||||
stack_layout__construct_livelval_rvals(LiveLvalSet, TVarLocnMap, RvalList) -->
|
||||
{ set__to_sorted_list(LiveLvalSet, LiveLvals) },
|
||||
{ list__length(LiveLvals, Length) },
|
||||
{ VarLengthRval = const(int_const(Length)) },
|
||||
@@ -489,7 +491,7 @@ stack_layout__construct_livelval_rvals(LiveLvalSet, TVarLocnSet, RvalList) -->
|
||||
stack_layout__construct_liveval_pairs(SortedLiveLvals,
|
||||
LiveValRval, NamesRval),
|
||||
|
||||
{ set__to_sorted_list(TVarLocnSet, TVarLocns) },
|
||||
{ map__to_assoc_list(TVarLocnMap, TVarLocns) },
|
||||
( { TVarLocns = [] } ->
|
||||
{ TypeParamRval = const(int_const(0)) }
|
||||
;
|
||||
@@ -518,14 +520,15 @@ stack_layout__construct_livelval_rvals(LiveLvalSet, TVarLocnSet, RvalList) -->
|
||||
% the selected var_infos.
|
||||
|
||||
:- pred stack_layout__select_trace_return(
|
||||
list(var_info)::in, set(pair(tvar, lval))::in,
|
||||
list(var_info)::out, set(pair(tvar, lval))::out) is det.
|
||||
list(var_info)::in, map(tvar, set(layout_locn))::in,
|
||||
list(var_info)::out, map(tvar, set(layout_locn))::out) is det.
|
||||
|
||||
stack_layout__select_trace_return(Infos, TVars, TraceReturnInfos, TVars) :-
|
||||
IsNamedReturnVar = lambda([LvalInfo::in] is semidet, (
|
||||
LvalInfo = var_info(Lval, LvalType),
|
||||
IsNamedReturnVar = lambda([LocnInfo::in] is semidet, (
|
||||
LocnInfo = var_info(Locn, LvalType),
|
||||
LvalType = var(_, Name, _, _),
|
||||
Name \= "",
|
||||
( Locn = direct(Lval) ; Locn = indirect(Lval, _)),
|
||||
( Lval = stackvar(_) ; Lval = framevar(_) )
|
||||
)),
|
||||
list__filter(IsNamedReturnVar, Infos, TraceReturnInfos).
|
||||
@@ -584,16 +587,22 @@ stack_layout__get_name_from_live_value_type(LiveType, Name) :-
|
||||
% slot to fill is given by the second argument.
|
||||
|
||||
:- pred stack_layout__construct_type_param_locn_vector(
|
||||
assoc_list(tvar, lval)::in, int::in, list(maybe(rval))::out,
|
||||
assoc_list(tvar, set(layout_locn))::in,
|
||||
int::in, list(maybe(rval))::out,
|
||||
stack_layout_info::in, stack_layout_info::out) is det.
|
||||
|
||||
stack_layout__construct_type_param_locn_vector([], _, []) --> [].
|
||||
stack_layout__construct_type_param_locn_vector([TVar - Locn | TVarLocns],
|
||||
stack_layout__construct_type_param_locn_vector([TVar - Locns | TVarLocns],
|
||||
CurSlot, Vector) -->
|
||||
{ term__var_to_int(TVar, TVarNum) },
|
||||
{ NextSlot is CurSlot + 1 },
|
||||
( { TVarNum = CurSlot } ->
|
||||
{ stack_layout__represent_lval(Locn, Rval) },
|
||||
{ set__remove_least(Locns, LeastLocn, _) ->
|
||||
Locn = LeastLocn
|
||||
;
|
||||
error("tvar has empty set of locations")
|
||||
},
|
||||
{ stack_layout__represent_locn(Locn, Rval) },
|
||||
stack_layout__construct_type_param_locn_vector(TVarLocns,
|
||||
NextSlot, VectorTail),
|
||||
{ Vector = [yes(Rval) | VectorTail] }
|
||||
@@ -607,7 +616,7 @@ stack_layout__construct_type_param_locn_vector([TVar - Locn | TVarLocns],
|
||||
{ error("unsorted tvars in construct_type_param_locn_vector") }
|
||||
).
|
||||
|
||||
% Construct a vector of (lval, live_value_type) pairs,
|
||||
% Construct a vector of (locn, live_value_type) pairs,
|
||||
% and a corresponding vector of variable names.
|
||||
|
||||
:- pred stack_layout__construct_liveval_pairs(list(var_info)::in,
|
||||
@@ -627,15 +636,15 @@ stack_layout__construct_liveval_pairs(LiveLvals, LocnVector, NameVector) -->
|
||||
{ NameVector = create(0, Names, no, CNum2,
|
||||
"stack_layout_name_vector") }.
|
||||
|
||||
% Construct a pair of (lval, live_value_type) representations.
|
||||
% Construct a pair of (locn, live_value_type) representations.
|
||||
|
||||
:- pred stack_layout__construct_liveval_pair(var_info::in,
|
||||
list(maybe(rval))::out, stack_layout_info::in, stack_layout_info::out)
|
||||
is det.
|
||||
|
||||
stack_layout__construct_liveval_pair(var_info(Lval, LiveValueType),
|
||||
stack_layout__construct_liveval_pair(var_info(Locn, LiveValueType),
|
||||
MaybeRvals) -->
|
||||
{ stack_layout__represent_lval(Lval, Rval0) },
|
||||
{ stack_layout__represent_locn(Locn, Rval0) },
|
||||
stack_layout__represent_live_value_type(LiveValueType, Rval1),
|
||||
{ MaybeRvals = [yes(Rval0), yes(Rval1)] }.
|
||||
|
||||
@@ -707,31 +716,60 @@ stack_layout__represent_live_value_type(var(_, _, Type, _Inst), Rval) -->
|
||||
{ Rval = create(0, [yes(Rval0), yes(Rval1)], no, CNum2,
|
||||
"stack_layout_pair") }.
|
||||
|
||||
% Construct a representation of a variable location.
|
||||
%
|
||||
% Most of the time, a layout specifies a location as an lval.
|
||||
% However, a type_info variable may be hidden inside a typeclass_info,
|
||||
% In this case, accessing the type_info requires indirection.
|
||||
% The address of the typeclass_info is given as an lval, and
|
||||
% the location of the typeinfo within the typeclass_info as an index;
|
||||
% private_builtin:type_info_from_typeclass_info interprets the index.
|
||||
%
|
||||
% This one level of indirection is sufficient, since type_infos
|
||||
% cannot be nested inside typeclass_infos any deeper than this.
|
||||
% A more general representation that would allow more indirection
|
||||
% would be much harder to fit into one machine word.
|
||||
|
||||
:- pred stack_layout__represent_locn(layout_locn, rval).
|
||||
:- mode stack_layout__represent_locn(in, out) is det.
|
||||
|
||||
stack_layout__represent_locn(direct(Lval), Rval) :-
|
||||
stack_layout__represent_lval(Lval, Word),
|
||||
Rval = const(int_const(Word)).
|
||||
stack_layout__represent_locn(indirect(Lval, Offset), Rval) :-
|
||||
stack_layout__represent_lval(Lval, BaseWord),
|
||||
stack_layout__offset_bits(OffsetBits),
|
||||
require((1 << OffsetBits) > Offset,
|
||||
"stack_layout__represent_locn: offset too large to be represented"),
|
||||
BaseAndOffset is (BaseWord << OffsetBits) + Offset,
|
||||
stack_layout__make_tagged_word(lval_indirect, BaseAndOffset, Word),
|
||||
Rval = const(int_const(Word)).
|
||||
|
||||
% Construct a representation of an lval.
|
||||
|
||||
:- pred stack_layout__represent_lval(lval, rval).
|
||||
:- pred stack_layout__represent_lval(lval, int).
|
||||
:- mode stack_layout__represent_lval(in, out) is det.
|
||||
|
||||
stack_layout__represent_lval(reg(r, Num), Rval) :-
|
||||
stack_layout__make_tagged_rval(0, Num, Rval).
|
||||
stack_layout__represent_lval(reg(f, Num), Rval) :-
|
||||
stack_layout__make_tagged_rval(1, Num, Rval).
|
||||
stack_layout__represent_lval(reg(r, Num), Word) :-
|
||||
stack_layout__make_tagged_word(lval_r_reg, Num, Word).
|
||||
stack_layout__represent_lval(reg(f, Num), Word) :-
|
||||
stack_layout__make_tagged_word(lval_f_reg, Num, Word).
|
||||
|
||||
stack_layout__represent_lval(stackvar(Num), Rval) :-
|
||||
stack_layout__make_tagged_rval(2, Num, Rval).
|
||||
stack_layout__represent_lval(framevar(Num), Rval) :-
|
||||
stack_layout__make_tagged_rval(3, Num, Rval).
|
||||
stack_layout__represent_lval(stackvar(Num), Word) :-
|
||||
stack_layout__make_tagged_word(lval_stackvar, Num, Word).
|
||||
stack_layout__represent_lval(framevar(Num), Word) :-
|
||||
stack_layout__make_tagged_word(lval_framevar, Num, Word).
|
||||
|
||||
stack_layout__represent_lval(succip, Rval) :-
|
||||
stack_layout__make_tagged_rval(4, 0, Rval).
|
||||
stack_layout__represent_lval(maxfr, Rval) :-
|
||||
stack_layout__make_tagged_rval(5, 0, Rval).
|
||||
stack_layout__represent_lval(curfr, Rval) :-
|
||||
stack_layout__make_tagged_rval(6, 0, Rval).
|
||||
stack_layout__represent_lval(hp, Rval) :-
|
||||
stack_layout__make_tagged_rval(7, 0, Rval).
|
||||
stack_layout__represent_lval(sp, Rval) :-
|
||||
stack_layout__make_tagged_rval(8, 0, Rval).
|
||||
stack_layout__represent_lval(succip, Word) :-
|
||||
stack_layout__make_tagged_word(lval_succip, 0, Word).
|
||||
stack_layout__represent_lval(maxfr, Word) :-
|
||||
stack_layout__make_tagged_word(lval_maxfr, 0, Word).
|
||||
stack_layout__represent_lval(curfr, Word) :-
|
||||
stack_layout__make_tagged_word(lval_curfr, 0, Word).
|
||||
stack_layout__represent_lval(hp, Word) :-
|
||||
stack_layout__make_tagged_word(lval_hp, 0, Word).
|
||||
stack_layout__represent_lval(sp, Word) :-
|
||||
stack_layout__make_tagged_word(lval_sp, 0, Word).
|
||||
|
||||
stack_layout__represent_lval(temp(_, _), _) :-
|
||||
error("stack_layout: continuation live value stored in temp register").
|
||||
@@ -761,21 +799,51 @@ stack_layout__represent_lval(lvar(_), _) :-
|
||||
% This allows us to use more than the usual 2 or 3 bits, but
|
||||
% we have to use low tags and cannot tag pointers this way.
|
||||
|
||||
:- pred stack_layout__make_tagged_rval(int::in, int::in, rval::out) is det.
|
||||
:- pred stack_layout__make_tagged_word(locn_type::in, int::in, int::out) is det.
|
||||
|
||||
stack_layout__make_tagged_rval(Tag, Value, Rval) :-
|
||||
stack_layout__make_tagged_word(Tag, Value, TaggedValue),
|
||||
Rval = const(int_const(TaggedValue)).
|
||||
stack_layout__make_tagged_word(Locn, Value, TaggedValue) :-
|
||||
stack_layout__locn_type_code(Locn, Tag),
|
||||
stack_layout__tag_bits(TagBits),
|
||||
TaggedValue is (Value << TagBits) + Tag.
|
||||
|
||||
:- pred stack_layout__make_tagged_word(int::in, int::in, int::out) is det.
|
||||
:- type locn_type
|
||||
---> lval_r_reg
|
||||
; lval_f_reg
|
||||
; lval_stackvar
|
||||
; lval_framevar
|
||||
; lval_succip
|
||||
; lval_maxfr
|
||||
; lval_curfr
|
||||
; lval_hp
|
||||
; lval_sp
|
||||
; lval_indirect.
|
||||
|
||||
stack_layout__make_tagged_word(Tag, Value, TaggedValue) :-
|
||||
stack_layout__tag_bits(Bits),
|
||||
TaggedValue = (Value << Bits) + Tag.
|
||||
:- pred stack_layout__locn_type_code(locn_type::in, int::out) is det.
|
||||
|
||||
stack_layout__locn_type_code(lval_r_reg, 0).
|
||||
stack_layout__locn_type_code(lval_f_reg, 1).
|
||||
stack_layout__locn_type_code(lval_stackvar, 2).
|
||||
stack_layout__locn_type_code(lval_framevar, 3).
|
||||
stack_layout__locn_type_code(lval_succip, 4).
|
||||
stack_layout__locn_type_code(lval_maxfr, 5).
|
||||
stack_layout__locn_type_code(lval_curfr, 6).
|
||||
stack_layout__locn_type_code(lval_hp, 7).
|
||||
stack_layout__locn_type_code(lval_sp, 8).
|
||||
stack_layout__locn_type_code(lval_indirect, 9).
|
||||
|
||||
:- pred stack_layout__tag_bits(int::out) is det.
|
||||
|
||||
stack_layout__tag_bits(8).
|
||||
% This number of tag bits must be able to encode all values of
|
||||
% stack_layout__locn_type_code.
|
||||
|
||||
stack_layout__tag_bits(4).
|
||||
|
||||
% This number of tag bits must be able to encode the largest offset
|
||||
% of a type_info within a typeclass_info.
|
||||
|
||||
:- pred stack_layout__offset_bits(int::out) is det.
|
||||
|
||||
stack_layout__offset_bits(6).
|
||||
|
||||
%---------------------------------------------------------------------------%
|
||||
|
||||
|
||||
Reference in New Issue
Block a user