From 6be2fe20ee8f0ac45bdfa4b8ed5cbd12ae406fcb Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Fri, 26 Jun 2009 01:12:00 +0000 Subject: [PATCH] The Java backend was sometimes generating code like this to initialise RTTI Branches: main The Java backend was sometimes generating code like this to initialise RTTI data structures: foo_type_info.init(..., /* cast */ new TypeInfo_Struct(bar_type_ctor_info), ...); bar_type_ctor_info.init(...); where `bar_type_ctor_info' is actually a type_info. The problem is that the fields of the non-initialised `bar_type_ctor_info' would be copied into the new TypeInfo_Struct object. The "cast" is of course also unnecessary as the bar is already a TypeInfo_Struct. This patch attempts to fix the problem in two ways: 1. Don't allocate a new TypeInfo_Struct object to emulate the "cast" unless the value is actually a TypeCtorInfo_Struct, avoiding the problem of copying uninitialised fields. Currently this is implemented by a runtime check because the MLDS `cast' operation doesn't record the original type of the value being cast. 2. Instead of relying on mlds_to_rtti.m to return a list of RTTI data structures where sub-structures appear before the structures that reference them, explicitly perform a topological sort. This should be more robust. Unrelated change: use pre-allocated PseudoTypeInfo instances for common variable numbers (1 through 5). compiler/rtti_to_mlds.m: Add a function to order a list of RTTI definitions as above. Use cons instead of list.append in some places now that we can. compiler/mlds_to_java.m: Call the function to order RTTI definitions before outputing the initialisations. Call TypeInfo_Struct.maybe_new instead of allocating new TypeInfo_Structs. Generate code that uses pre-allocated PseudoTypeInfo instances. java/runtime/TypeInfo_Struct.java: Add a `maybe_new' method for "casting" TypeCtorInfo_Structs to TypeInfos or returning the argument unchanged. Delete a copy constructor; now unused. Add some assertions. java/runtime/PseudoTypeInfo.java: Add static instances of PseudoTypeInfo. tests/hard_coded/Mmakefile: tests/hard_coded/java_rtti_bug.exp: tests/hard_coded/java_rtti_bug.m: Add test case. --- compiler/mlds_to_java.m | 44 ++++++- compiler/rtti_to_mlds.m | 198 ++++++++++++++++++++++++----- java/runtime/PseudoTypeInfo.java | 12 +- java/runtime/TypeInfo_Struct.java | 56 ++++++-- tests/hard_coded/Mmakefile | 1 + tests/hard_coded/java_rtti_bug.exp | 1 + tests/hard_coded/java_rtti_bug.m | 33 +++++ 7 files changed, 296 insertions(+), 49 deletions(-) create mode 100644 tests/hard_coded/java_rtti_bug.exp create mode 100644 tests/hard_coded/java_rtti_bug.m diff --git a/compiler/mlds_to_java.m b/compiler/mlds_to_java.m index 0c7a995ce..5a220b586 100644 --- a/compiler/mlds_to_java.m +++ b/compiler/mlds_to_java.m @@ -98,6 +98,7 @@ :- import_module ml_backend.ml_code_util. % for ml_gen_local_var_decl_flags. :- import_module ml_backend.ml_type_gen. % for ml_gen_type_name :- import_module ml_backend.ml_util. +:- import_module ml_backend.rtti_to_mlds. :- import_module parse_tree.builtin_lib_types. :- import_module parse_tree.file_names. % for mercury_std_library_name. :- import_module parse_tree.java_names. @@ -1752,15 +1753,27 @@ output_rtti_assignments(Indent, ModuleInfo, ModuleName, Defns, !IO) :- Defns = [] ; Defns = [_ | _], + OrderedDefns = order_mlds_rtti_defns(Defns), indent_line(Indent, !IO), io.write_string("static {\n", !IO), list.foldl( - output_rtti_defn_assignments(Indent + 1, ModuleInfo, ModuleName), - Defns, !IO), + output_rtti_defns_assignments(Indent + 1, ModuleInfo, ModuleName), + OrderedDefns, !IO), indent_line(Indent, !IO), io.write_string("}\n", !IO) ). +:- pred output_rtti_defns_assignments(indent::in, module_info::in, + mlds_module_name::in, list(mlds_defn)::in, io::di, io::uo) is det. + +output_rtti_defns_assignments(Indent, ModuleInfo, ModuleName, Defns, !IO) :- + % Separate cliques. + indent_line(Indent, !IO), + io.write_string("//\n", !IO), + list.foldl( + output_rtti_defn_assignments(Indent, ModuleInfo, ModuleName), + Defns, !IO). + :- pred output_rtti_defn_assignments(indent::in, module_info::in, mlds_module_name::in, mlds_defn::in, io::di, io::uo) is det. @@ -3414,19 +3427,29 @@ output_unop(ModuleInfo, Unop, Expr, ModuleName, !IO) :- % Similarly for conversions from TypeCtorInfo to TypeInfo. ( Type = mlds_pseudo_type_info_type, - Expr = ml_const(mlconst_int(_)) + Expr = ml_const(mlconst_int(N)) -> maybe_output_comment("cast", !IO), - io.write_string("new jmercury.runtime.PseudoTypeInfo(", !IO), - output_rval(ModuleInfo, Expr, ModuleName, !IO), - io.write_string(")", !IO) + ( have_preallocated_pseudo_type_var(N) -> + io.write_string("jmercury.runtime.PseudoTypeInfo.K", !IO), + io.write_int(N, !IO) + ; + io.write_string("new jmercury.runtime.PseudoTypeInfo(", !IO), + output_rval(ModuleInfo, Expr, ModuleName, !IO), + io.write_string(")", !IO) + ) ; ( Type = mercury_type(_, ctor_cat_system(cat_system_type_info), _) ; Type = mlds_type_info_type ) -> + % XXX We really should be able to tell if we are casting a + % TypeCtorInfo or a TypeInfo. Julien says that's probably going to + % be rather difficult as the compiler doesn't keep track of where + % type_ctor_infos are acting as type_infos properly. maybe_output_comment("cast", !IO), - io.write_string("new jmercury.runtime.TypeInfo_Struct(", !IO), + io.write_string("jmercury.runtime.TypeInfo_Struct.maybe_new(", + !IO), output_rval(ModuleInfo, Expr, ModuleName, !IO), io.write_string(")", !IO) ; @@ -3443,6 +3466,13 @@ output_unop(ModuleInfo, Unop, Expr, ModuleName, !IO) :- output_std_unop(ModuleInfo, StdUnop, Expr, ModuleName, !IO) ). +:- pred have_preallocated_pseudo_type_var(int::in) is semidet. + +have_preallocated_pseudo_type_var(N) :- + % Corresponds to static members in class PseudoTypeInfo. + N >= 1, + N =< 5. + :- pred output_cast_rval(module_info::in, mlds_type::in, mlds_rval::in, mlds_module_name::in, io::di, io::uo) is det. diff --git a/compiler/rtti_to_mlds.m b/compiler/rtti_to_mlds.m index 3a933a202..4e65beffe 100644 --- a/compiler/rtti_to_mlds.m +++ b/compiler/rtti_to_mlds.m @@ -14,26 +14,6 @@ % The RTTI data structures are used for static data that is used % for handling RTTI, polymorphism, and typeclasses. % -% XXX There are problems with these definitions for the Java back-end. -% Under the current system, the definitions are output as static variables -% with static initializers, ordered so that subdefinitions always appear before -% the definition which uses them. This is neccessary because in Java, static -% initializers are performed at runtime in textual order, and if a definition -% relies on another static variable for its constructor but said variable has -% not been initialized, then it is treated as `null' by the JVM with no -% warning. -% The problem with this approach is that it won't work for cyclic definitions. -% eg: -% :- type foo ---> f(bar) ; g. -% :- type bar ---> f2(foo) ; g2 -% At some point this should be changed so that initialization is performed by 2 -% phases: first allocate all of the objects, then fill in the fields. -% -% XXX In the absence of this fix, there are still several places in the code -% below which use list.append. If possible these lists should instead be -% manipulated through some use of prepending and/or list.reverse instead, so -% that the algorithm stays O(N). -% %-----------------------------------------------------------------------------% :- module ml_backend.rtti_to_mlds. @@ -51,6 +31,15 @@ % :- func rtti_data_list_to_mlds(module_info, list(rtti_data)) = list(mlds_defn). + % Given a list of MLDS RTTI data definitions (only), return the definitions + % such that if X appears in the initialiser for Y then X appears earlier in + % the list than Y. + % + % This function returns a list of cliques so that problems with ordering + % within cliques, if any, may be easier to discover. + % +:- func order_mlds_rtti_defns(list(mlds_defn)) = list(list(mlds_defn)). + %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% @@ -72,11 +61,14 @@ :- import_module assoc_list. :- import_module bool. :- import_module counter. +:- import_module digraph. :- import_module int. :- import_module list. :- import_module map. :- import_module maybe. :- import_module pair. +:- import_module set. +:- import_module svmap. :- import_module term. :- import_module univ. @@ -117,7 +109,7 @@ rtti_data_to_mlds(ModuleInfo, RttiData) = MLDS_Defns :- Initializer, ExtraDefns), rtti_entity_name_and_init_to_defn(Name, RttiId, Initializer, MLDS_Defn), - MLDS_Defns = ExtraDefns ++ [MLDS_Defn] + MLDS_Defns = [MLDS_Defn | ExtraDefns] ). :- pred rtti_name_and_init_to_defn(rtti_type_ctor::in, ctor_rtti_name::in, @@ -339,7 +331,7 @@ gen_type_class_decl_defn(TCDecl, RttiId, ModuleInfo, Init, SubDefns) :- SuperArrayInit = gen_init_array( gen_init_cast_rtti_id(ElementType, ModuleName), SuperRttiIds), rtti_id_and_init_to_defn(SuperArrayRttiId, SuperArrayInit, SuperDefn), - SuperDefns = SuperConstrDefns ++ [SuperDefn], + SuperDefns = [SuperDefn | SuperConstrDefns], SupersInit = gen_init_null_pointer( mlds_rtti_type(item_type(MethodIdsRttiId))) ), @@ -538,7 +530,7 @@ gen_functors_layout_info(ModuleInfo, RttiTypeCtor, TypeCtorDetails, type_ctor_enum_name_ordered_table), NumberMapInit = gen_init_rtti_name(ModuleName, RttiTypeCtor, type_ctor_functor_number_map), - Defns = EnumFunctorDescs ++ [ByValueDefn, ByNameDefn, NumberMapDefn] + Defns = [ByValueDefn, ByNameDefn, NumberMapDefn | EnumFunctorDescs] ; TypeCtorDetails = tcd_foreign_enum(ForeignEnumLang, _, ForeignEnumFunctors, ForeignEnumByOrdinal, ForeignEnumByName, @@ -558,8 +550,8 @@ gen_functors_layout_info(ModuleInfo, RttiTypeCtor, TypeCtorDetails, type_ctor_foreign_enum_name_ordered_table), NumberMapInit = gen_init_rtti_name(ModuleName, RttiTypeCtor, type_ctor_functor_number_map), - Defns = ForeignEnumFunctorDescs ++ - [ByOrdinalDefn, ByNameDefn, NumberMapDefn] + Defns = [ByOrdinalDefn, ByNameDefn, NumberMapDefn | + ForeignEnumFunctorDescs] ; TypeCtorDetails = tcd_du(_, DuFunctors, DuByPtag, DuByName, FunctorNumberMap), @@ -673,7 +665,7 @@ gen_notag_functor_desc(ModuleInfo, RttiTypeCtor, NotagFunctorDesc) gen_init_maybe(ml_string_type, gen_init_string, MaybeArgName) ]), rtti_id_and_init_to_defn(RttiId, Init, MLDS_Defn), - MLDS_Defns = SubDefns ++ [MLDS_Defn]. + MLDS_Defns = [MLDS_Defn | SubDefns]. :- func gen_du_functor_desc(module_info, rtti_type_ctor, du_functor) = list(mlds_defn). @@ -758,7 +750,7 @@ gen_du_functor_desc(ModuleInfo, RttiTypeCtor, DuFunctor) = MLDS_Defns :- ExistInfoInit ]), rtti_id_and_init_to_defn(RttiId, Init, MLDS_Defn), - MLDS_Defns = SubDefns ++ [MLDS_Defn]. + MLDS_Defns = [MLDS_Defn | SubDefns]. :- func gen_res_addr_functor_desc(module_info, rtti_type_ctor, reserved_functor) = mlds_defn. @@ -835,7 +827,7 @@ gen_tc_constraint(ModuleInfo, MakeRttiId, Constraint, RttiId, !Counter, PTIInits ]), rtti_id_and_init_to_defn(RttiId, Init, ConstrDefn), - !:Defns = !.Defns ++ PTIDefns ++ [ConstrDefn]. + !:Defns = !.Defns ++ [ConstrDefn | PTIDefns]. :- pred make_exist_tc_constr_id(rtti_type_ctor::in, int::in, int::in, int::in, rtti_id::out) is det. @@ -875,7 +867,7 @@ gen_exist_info(ModuleInfo, RttiTypeCtor, Ordinal, ExistInfo) = MLDS_Defns :- gen_init_cast_rtti_id(ElementType, ModuleName), TCConstrIds), rtti_name_and_init_to_defn(RttiTypeCtor, TCConstrArrayRttiName, TCConstrArrayInit, TCConstrArrayDefn), - ConstrDefns = TCConstrDefns ++ [TCConstrArrayDefn] + ConstrDefns = [TCConstrArrayDefn | TCConstrDefns] ), Init = init_struct(mlds_rtti_type(item_type(RttiId)), [ gen_init_int(Plain), @@ -913,7 +905,7 @@ gen_field_types(ModuleInfo, RttiTypeCtor, Ordinal, Types) = MLDS_Defns :- gen_pseudo_type_info_array(ModuleInfo, TypeRttiDatas, Init, SubDefns), RttiName = type_ctor_field_types(Ordinal), rtti_name_and_init_to_defn(RttiTypeCtor, RttiName, Init, MLDS_Defn), - MLDS_Defns = SubDefns ++ [MLDS_Defn]. + MLDS_Defns = [MLDS_Defn | SubDefns]. %-----------------------------------------------------------------------------% @@ -1009,7 +1001,7 @@ gen_du_ptag_ordered_table(ModuleInfo, RttiTypeCtor, PtagMap) = MLDS_Defns :- RttiName = type_ctor_du_ptag_ordered_table, Init = init_array(PtagInitPrefix ++ PtagInits), rtti_name_and_init_to_defn(RttiTypeCtor, RttiName, Init, MLDS_Defn), - MLDS_Defns = SubDefns ++ [MLDS_Defn]. + MLDS_Defns = [MLDS_Defn | SubDefns]. :- func gen_du_ptag_ordered_table_body(module_name, rtti_type_ctor, assoc_list(int, sectag_table), int) = list(mlds_initializer). @@ -1095,7 +1087,7 @@ gen_maybe_res_value_ordered_table(ModuleInfo, RttiTypeCtor, ResFunctors, type_ctor_du_ptag_ordered_table) ]), rtti_id_and_init_to_defn(RttiId, Init, MLDS_Defn), - MLDS_Defns = SubDefns ++ [MLDS_Defn]. + MLDS_Defns = [MLDS_Defn | SubDefns]. :- func gen_res_addr_functor_table(module_name, rtti_type_ctor, list(reserved_functor)) = mlds_defn. @@ -1565,6 +1557,148 @@ gen_init_sectag_locn(Locn) = gen_init_builtin_const(Name) :- gen_init_type_ctor_rep(TypeCtorData) = gen_init_builtin_const(Name) :- rtti.type_ctor_rep_to_string(TypeCtorData, Name). +%-----------------------------------------------------------------------------% +% +% Ordering RTTI definitions +% + +order_mlds_rtti_defns(Defns) = OrdDefns :- + some [!Graph] ( + digraph.init(!:Graph), + list.foldl2(add_rtti_defn_nodes, Defns, !Graph, map.init, NameMap), + list.foldl(add_rtti_defn_arcs, Defns, !Graph), + digraph.atsort(!.Graph, RevOrdSets) + ), + list.reverse(RevOrdSets, OrdSets), + list.map(set.to_sorted_list, OrdSets, OrdLists), + list.map(list.filter_map(map.search(NameMap)), OrdLists, OrdDefns). + +:- pred add_rtti_defn_nodes(mlds_defn::in, + digraph(mlds_data_name)::in, digraph(mlds_data_name)::out, + map(mlds_data_name, mlds_defn)::in, map(mlds_data_name, mlds_defn)::out) + is det. + +add_rtti_defn_nodes(Defn, !Graph, !NameMap) :- + Name = Defn ^ mlds_entity_name, + ( + Name = entity_data(DataName), + digraph.add_vertex(DataName, _, !Graph), + svmap.det_insert(DataName, Defn, !NameMap) + ; + ( Name = entity_type(_, _) + ; Name = entity_function(_, _, _, _) + ; Name = entity_export(_) + ), + unexpected(this_file, "add_rtti_defn_nodes: expected entity_data") + ). + +:- pred add_rtti_defn_arcs(mlds_defn::in, + digraph(mlds_data_name)::in, digraph(mlds_data_name)::out) is det. + +add_rtti_defn_arcs(Defn, !Graph) :- + Defn = mlds_defn(EntityName, _, _, EntityDefn), + ( + EntityName = entity_data(DefnDataName), + EntityDefn = mlds_data(Type, Initializer, _GCStatement), + Type = mlds_rtti_type(_) + -> + add_rtti_defn_arcs_initializer(DefnDataName, Initializer, !Graph) + ; + unexpected(this_file, "add_rtti_defn_arcs: expected rtti entity_data") + ). + +:- pred add_rtti_defn_arcs_initializer(mlds_data_name::in, mlds_initializer::in, + digraph(mlds_data_name)::in, digraph(mlds_data_name)::out) is det. + +add_rtti_defn_arcs_initializer(DefnDataName, Initializer, !Graph) :- + ( + Initializer = init_obj(Rval), + add_rtti_defn_arcs_rval(DefnDataName, Rval, !Graph) + ; + ( Initializer = init_struct(_, Initializers) + ; Initializer = init_array(Initializers) + ), + list.foldl(add_rtti_defn_arcs_initializer(DefnDataName), Initializers, + !Graph) + ; + Initializer = no_initializer + ). + +:- pred add_rtti_defn_arcs_rval(mlds_data_name::in, mlds_rval::in, + digraph(mlds_data_name)::in, digraph(mlds_data_name)::out) is det. + +add_rtti_defn_arcs_rval(DefnDataName, Rval, !Graph) :- + ( + Rval = ml_lval(Lval), + add_rtti_defn_arcs_lval(DefnDataName, Lval, !Graph) + ; + Rval = ml_mkword(_Tag, RvalA), + add_rtti_defn_arcs_rval(DefnDataName, RvalA, !Graph) + ; + Rval = ml_const(Const), + add_rtti_defn_arcs_const(DefnDataName, Const, !Graph) + ; + Rval = ml_unop(_, RvalA), + add_rtti_defn_arcs_rval(DefnDataName, RvalA, !Graph) + ; + Rval = ml_binop(_, RvalA, RvalB), + add_rtti_defn_arcs_rval(DefnDataName, RvalA, !Graph), + add_rtti_defn_arcs_rval(DefnDataName, RvalB, !Graph) + ; + Rval = ml_mem_addr(Lval), + add_rtti_defn_arcs_lval(DefnDataName, Lval, !Graph) + ; + Rval = ml_self(_) + ). + +:- pred add_rtti_defn_arcs_lval(mlds_data_name::in, mlds_lval::in, + digraph(mlds_data_name)::in, digraph(mlds_data_name)::out) is det. + +add_rtti_defn_arcs_lval(DefnDataName, Lval, !Graph) :- + ( + Lval = ml_field(_, Rval, _, _, _), + add_rtti_defn_arcs_rval(DefnDataName, Rval, !Graph) + ; + Lval = ml_mem_ref(Rval, _Type), + add_rtti_defn_arcs_rval(DefnDataName, Rval, !Graph) + ; + Lval = ml_global_var_ref(env_var_ref(_)) + ; + Lval = ml_var(_, _) + ). + +:- pred add_rtti_defn_arcs_const(mlds_data_name::in, mlds_rval_const::in, + digraph(mlds_data_name)::in, digraph(mlds_data_name)::out) is det. + +add_rtti_defn_arcs_const(DefnDataName, Const, !Graph) :- + ( + Const = mlconst_data_addr(data_addr(_, DataName)), + ( + DataName = mlds_rtti(_), + digraph.add_vertices_and_edge(DefnDataName, DataName, !Graph) + ; + ( DataName = mlds_data_var(_) + ; DataName = mlds_common(_) + ; DataName = mlds_module_layout + ; DataName = mlds_proc_layout(_) + ; DataName = mlds_internal_layout(_, _) + ; DataName = mlds_tabling_ref(_, _) + ) + ) + ; + ( Const = mlconst_true + ; Const = mlconst_false + ; Const = mlconst_int(_) + ; Const = mlconst_foreign(_, _, _) + ; Const = mlconst_float(_) + ; Const = mlconst_string(_) + ; Const = mlconst_multi_string(_) + ; Const = mlconst_named_const(_) + ; Const = mlconst_code_addr(_) + ; Const = mlconst_null(_) + ) + ). + %-----------------------------------------------------------------------------% :- func this_file = string. diff --git a/java/runtime/PseudoTypeInfo.java b/java/runtime/PseudoTypeInfo.java index 89b807a67..318f36039 100644 --- a/java/runtime/PseudoTypeInfo.java +++ b/java/runtime/PseudoTypeInfo.java @@ -1,5 +1,5 @@ // -// Copyright (C) 2001-2004 The University of Melbourne. +// Copyright (C) 2001-2004, 2009 The University of Melbourne. // This file may only be copied under the terms of the GNU Library General // Public License - see the file COPYING.LIB in the Mercury distribution. // @@ -26,6 +26,14 @@ public class PseudoTypeInfo { public PseudoTypeInfo(int n) { variable_number = n; } protected PseudoTypeInfo() { variable_number = -1; } + // Adding or removing members requires corresponding changes in + // mlds_to_java.m. + public static final PseudoTypeInfo K1 = new PseudoTypeInfo(1); + public static final PseudoTypeInfo K2 = new PseudoTypeInfo(2); + public static final PseudoTypeInfo K3 = new PseudoTypeInfo(3); + public static final PseudoTypeInfo K4 = new PseudoTypeInfo(4); + public static final PseudoTypeInfo K5 = new PseudoTypeInfo(5); + // XXX This should be renamed `equals' public boolean unify(PseudoTypeInfo ti) { if (this.getClass() == TypeInfo_Struct.class && @@ -36,3 +44,5 @@ public class PseudoTypeInfo { return variable_number == ti.variable_number; } } + +// vim: set ts=8 sts=8 sw=8 noet: diff --git a/java/runtime/TypeInfo_Struct.java b/java/runtime/TypeInfo_Struct.java index 107d59e8f..992db10be 100644 --- a/java/runtime/TypeInfo_Struct.java +++ b/java/runtime/TypeInfo_Struct.java @@ -18,22 +18,36 @@ public class TypeInfo_Struct extends PseudoTypeInfo { public TypeInfo_Struct(TypeCtorInfo_Struct tc) { type_ctor = tc; + sanity_check(); } - // copy constructor - // XXX Rather than invoking this constructor, and allocating a new - // type_info object on the heap, we should generate code which - // just copies the pointer, - public TypeInfo_Struct(TypeInfo_Struct ti) + public static TypeInfo_Struct maybe_new(final Object obj) { - type_ctor = ti.type_ctor; - args = ti.args; + // In at least one place in the standard library we make up a + // TypeInfo out of thin air to satisfy the compiler. + if (obj == null) { + return null; + } + if (obj instanceof TypeCtorInfo_Struct) { + return new TypeInfo_Struct((TypeCtorInfo_Struct) obj); + } + if (obj instanceof TypeInfo_Struct) { + return (TypeInfo_Struct) obj; + } + throw new java.lang.Error( + "expected TypeInfo_Struct or TypeCtorInfo_Struct"); } public void init(TypeCtorInfo_Struct tc, PseudoTypeInfo[] as) { - type_ctor = tc; - args = as; + type_ctor = tc; + args = as; + + // We may be in the middle of initialising a cyclic data + // structure, so unfortunately, we can't actually sanity check + // the arguments here. + assert tc != null; + // sanity_check(); } public TypeInfo_Struct copy() @@ -43,6 +57,7 @@ public class TypeInfo_Struct extends PseudoTypeInfo { if (args != null) { ti.args = args.clone(); } + ti.sanity_check(); return ti; } @@ -119,4 +134,27 @@ public class TypeInfo_Struct extends PseudoTypeInfo { } return true; } + + private void sanity_check() { + assert type_ctor != null; + + if (args == null) { + return; + } + for (PseudoTypeInfo pti : args) { + if (pti instanceof TypeInfo_Struct) { + TypeInfo_Struct ti = (TypeInfo_Struct) pti; + assert ti.type_ctor != null; + assert ti.variable_number == -1; + } else if (pti instanceof TypeCtorInfo_Struct) { + TypeCtorInfo_Struct tc = + (TypeCtorInfo_Struct) pti; + assert tc.variable_number == -1; + } else { + assert pti.variable_number != -1; + } + } + } } + +// vim: set ts=8 sw=8 sts=8 noet: diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile index ab64a7de7..6271558e2 100644 --- a/tests/hard_coded/Mmakefile +++ b/tests/hard_coded/Mmakefile @@ -139,6 +139,7 @@ ORDINARY_PROGS= \ intermod_pragma_clause \ intermod_type_qual \ intermod_unused_args \ + java_rtti_bug \ join_list \ lco_no_inline \ list_series_int \ diff --git a/tests/hard_coded/java_rtti_bug.exp b/tests/hard_coded/java_rtti_bug.exp new file mode 100644 index 000000000..c9be995c1 --- /dev/null +++ b/tests/hard_coded/java_rtti_bug.exp @@ -0,0 +1 @@ +foo(bar(baz(1))) diff --git a/tests/hard_coded/java_rtti_bug.m b/tests/hard_coded/java_rtti_bug.m new file mode 100644 index 000000000..09fde50fa --- /dev/null +++ b/tests/hard_coded/java_rtti_bug.m @@ -0,0 +1,33 @@ +% Regression test. +% The Java backend was generating code that didn't initialise an type_ctor_info +% before another RTTI structure referenced it. This resulted in a null +% pointer exception when this program is executed. + +:- module java_rtti_bug. +:- interface. + +:- import_module io. + +:- pred main(io::di, io::uo) is det. + +%-----------------------------------------------------------------------------% +%-----------------------------------------------------------------------------% + +:- implementation. + +main(!IO) :- + X = foo(bar(baz(1))), + io.write(X, !IO), + io.nl(!IO). + +:- type foo + ---> foo(bar(baz(int))). + +:- type bar(T) + ---> bar(T). + +:- type baz(T) + ---> baz(T). + +%-----------------------------------------------------------------------------% +% vim: ft=mercury ts=8 sts=4 sw=4 et