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:
Zoltan Somogyi
1998-10-23 00:42:02 +00:00
parent 6b9583eb74
commit beaa554171
17 changed files with 705 additions and 185 deletions

View File

@@ -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).
%---------------------------------------------------------------------------%