[m-rev.] for review: arrays and the debugger

Zoltan Somogyi zs at cs.mu.OZ.AU
Thu Jun 21 19:03:50 AEST 2001


On 19-Jun-2001, Mark Brown <dougl at cs.mu.OZ.AU> wrote:
> > +** this task. The reason for having those specialized variants is that
> > +** executing the full task can be extremely time consuming, especially when
> > +** large arrays are involved. (Simply allocating and filling in an array of
> > +** a million typeinfos can cause a system to start paging.) Therefore we
> > try to
> > +** make sure that in every circumstance we perform the minimum work
> > possible.
> 
> It would be better if you mentioned the circumstances in question (that is,
> mention each of the callers of these functions).

Which combinations of features actually needed and what the functions
implementing them are concerns for std_util.m, not this file. They are already
documented in std_util.m, and this file contains a pointer to that
documentation, so mentioning those callers would not be much help but would
incur a double maintenance burden.

However, I acted on your other suggestions. Here is the relative diff.
I intend to commit it after a final bootcheck.

Zoltan.

--- /home/zs/mer/ws41/runtime/mercury_ml_expand_body.h	Tue Jun 12 22:16:44 2001
+++ runtime/mercury_ml_expand_body.h	Thu Jun 21 18:47:13 2001
@@ -8,10 +8,10 @@
 ** mercury_ml_expand_body.h
 **
 ** This file is included several times in library/std_util.m. Each inclusion
-** defines a function that the body of several variants of the old ML_expand
-** function, which, given a data word and its type_info, returned its functor,
-** arity, argument vector and a type_info vector describing its arguments.
-** One variants still does all that. The others perform different subsets of
+** defines the body of one of several variants of the old ML_expand function,
+** which, given a data word and its type_info, returned its functor, arity,
+** argument vector and a type_info vector describing its arguments.
+** One variant still does all that. The others perform different subsets of
 ** this task. The reason for having those specialized variants is that
 ** executing the full task can be extremely time consuming, especially when
 ** large arrays are involved. (Simply allocating and filling in an array of
--- /home/zs/mer/ws41/library/std_util.m	Tue Jun 12 17:02:39 2001
+++ library/std_util.m	Thu Jun 21 18:54:48 2001
@@ -495,11 +495,12 @@
 
 %-----------------------------------------------------------------------------%
 
-	% functor, argument and deconstruct take any type (including univ),
-	% and return representation information for that type.
+	% functor, argument and deconstruct and their variants take any type
+	% (including univ), and return representation information for that type.
+	%
+	% The string representation of the functor that these predicates
+	% return is:
 	%
-	% The string representation of the functor that `functor' and
-	% `deconstruct' return is:
 	% 	- for user defined types, the functor that is given
 	% 	  in the type definition. For lists, this
 	% 	  means the functors ./2 and []/0 are used, even if
@@ -510,11 +511,22 @@
 	%	  base 10 number, positive floating point numbers have
 	%	  no sign.
 	%	- for strings, the string, inside double quotation marks
-	%	- for characters, the character inside single
-	%	  quotation marks
-	%	- for predicates and functions, the string
-	%	  <<predicate>>
+	%	- for characters, the character inside single quotation marks
+	%	- for predicates and functions, the string <<predicate>>
 	%	- for tuples, the string {}
+	%	- for arrays, the string <<array>>
+	%
+	% The arity that these predicates return is:
+	%
+	% 	- for user defined types, the arity of the functor.
+	%	- for integers, zero.
+	%	- for floats, zero.
+	%	- for strings, zero.
+	%	- for characters, zero.
+	%	- for predicates and functions, zero; we do not return the
+	%	  number of arguments expected by the predicate or function.
+	%	- for tuples, the number of elements in the tuple.
+	%	- for arrays, the number of elements in the array.
 
 	% functor(Data, Functor, Arity)
 	%
@@ -564,12 +576,22 @@
 	% representation, i.e. one for which there is a user-defined
 	% equality predicate.)
 	%
+	% The cost of calling deconstruct depends greatly on how many arguments
+	% Data has. If Data is an array, then each element of the array is
+	% considered one of its arguments. Therefore calling deconstruct
+	% on large arrays can take a very large amount of memory and a very
+	% long time. If you call deconstruct in a situation in which you may
+	% pass it a large array, you should probably use limited_deconstruct
+	% instead.
+	%
 :- pred deconstruct(T::in, string::out, int::out, list(univ)::out) is det.
 
 	% limited_deconstruct(Data, MaxArity, Functor, Arity, Arguments)
 	%
 	% limited_deconstruct works like deconstruct, but if the arity of T is
-	% greater than MaxArity, limited_deconstruct fails.
+	% greater than MaxArity, limited_deconstruct fails. This is useful in
+	% avoiding bad performance in cases where Data may be a large array.
+	%
 :- pred limited_deconstruct(T::in, int::in, string::out,
 	int::out, list(univ)::out) is semidet.
 
@@ -2890,8 +2912,71 @@
 extern  bool    ML_named_arg_num(MR_TypeInfo type_info, MR_Word *term_ptr,
                     const char *arg_name, int *arg_num_ptr);
 
+/*
+** The following macros factor out the common parts of the various
+** deconstruction predicates.
+*/
+
+    /*
+    ** Check for attempts to deconstruct a non-canonical type.
+    ** Such deconstructions must be cc_multi, which is why we treat
+    ** violations of this as runtime errors in det deconstruction
+    ** predicates.
+    ** (There ought to be cc_multi versions of those predicates.)
+    */
+#define ML_abort_if_type_is_noncanonical(ei, predname)              \
+    do {                                                            \
+        if ((ei).non_canonical_type) {                              \
+            MR_fatal_error(""called "" predname "" for a type ""    \
+                ""with a user-defined equality predicate"");        \
+        }                                                           \
+    } while (0)
+
 #endif
 
+#define ML_deconstruct_get_functor(ei, functor_field, var)          \
+    do {                                                            \
+        MR_make_aligned_string(MR_LVALUE_CAST(MR_ConstString, var), \
+            (ei).functor_field);                                    \
+    } while (0)
+
+#define ML_deconstruct_get_arity(ei, var)                           \
+    do {                                                            \
+        var = (ei).arity;                                           \
+    } while (0)
+
+#define ML_deconstruct_get_arg_list(ei, args_field, var)            \
+    do {                                                            \
+        int     i;                                                  \
+                                                                    \
+        var = MR_list_empty_msg(MR_PROC_LABEL);                     \
+        i = (ei).arity;                                             \
+                                                                    \
+        while (--i >= 0) {                                          \
+            MR_Word arg;                                            \
+                                                                    \
+                /* Create an argument on the heap */                \
+            MR_new_univ_on_hp(arg,                                  \
+                (ei).args_field.arg_type_infos[i],                  \
+                (ei).args_field.arg_values[i +                      \
+                    (ei).args_field.num_extra_args]);               \
+                                                                    \
+                /* Join the argument to the front of the list */    \
+            var = MR_list_cons_msg(arg, var, MR_PROC_LABEL);        \
+        }                                                           \
+    } while (0)
+
+    /*
+    ** Free any arg_type_infos allocated by the ML_expand variant.
+    ** Should be called after we have used them for the last time.
+    */
+#define ML_deconstruct_free_allocated_arg_type_infos(ei, args_field)\
+    do {                                                            \
+        if ((ei).args_field.can_free_arg_type_infos) {              \
+            MR_GC_free((ei).args_field.arg_type_infos);             \
+        }                                                           \
+    } while (0)
+
 ").
 
 :- pragma foreign_code("C", "
@@ -2960,19 +3045,7 @@
     ML_Expand_Chosen_Arg_Only_Info	expand_info;
 
     ML_expand_chosen_arg_only(type_info, term_ptr, arg_index, &expand_info);
-
-        /*
-        ** Check for attempts to deconstruct a non-canonical type:
-        ** such deconstructions must be cc_multi, and since
-        ** arg/2 is det, we must treat violations of this
-        ** as runtime errors.
-        ** (There ought to be a cc_multi version of arg/2
-        ** that allows this.)
-        */
-    if (expand_info.non_canonical_type) {
-        MR_fatal_error(""called argument/2 for a type with a ""
-            ""user-defined equality predicate"");
-    }
+    ML_abort_if_type_is_noncanonical(expand_info, ""argument/2"");
 
         /* Check range */
     if (expand_info.chosen_index_exists) {
@@ -3109,24 +3182,9 @@
     ML_expand_functor_only(type_info, &Term, &expand_info);
     MR_restore_transient_registers();
 
-        /*
-        ** Check for attempts to deconstruct a non-canonical type:
-        ** such deconstructions must be cc_multi, and since
-        ** functor/2 is det, we must treat violations of this
-        ** as runtime errors.
-        ** (There ought to be a cc_multi version of functor/2
-        ** that allows this.)
-        */
-    if (expand_info.non_canonical_type) {
-        MR_fatal_error(""called functor/2 for a type with a ""
-            ""user-defined equality predicate"");
-    }
-
-        /* Copy functor onto the heap */
-    MR_make_aligned_string(MR_LVALUE_CAST(MR_ConstString, Functor),
-        expand_info.functor_only);
-
-    Arity = expand_info.arity;
+    ML_abort_if_type_is_noncanonical(expand_info, ""functor/3"");
+    ML_deconstruct_get_functor(expand_info, functor_only, Functor);
+    ML_deconstruct_get_arity(expand_info, Arity);
 }").
 
 /*
@@ -3243,9 +3301,6 @@
 {
     ML_Expand_Functor_Args_Info	expand_info;
     MR_TypeInfo         		type_info;
-    MR_Word             		Argument;
-    MR_Word             		tmp;
-    int                 		i;
 
     type_info = (MR_TypeInfo) TypeInfo_for_T;
 
@@ -3253,49 +3308,11 @@
     ML_expand_functor_args(type_info, &Term, &expand_info);
     MR_restore_transient_registers();
 
-        /*
-        ** Check for attempts to deconstruct a non-canonical type:
-        ** such deconstructions must be cc_multi, and since
-        ** deconstruct/4 is det, we must treat violations of this
-        ** as runtime errors.
-        ** (There ought to be a cc_multi version of deconstruct/4
-        ** that allows this.)
-        */
-    if (expand_info.non_canonical_type) {
-        MR_fatal_error(""called deconstruct/4 for a type with a ""
-            ""user-defined equality predicate"");
-    }
-
-        /* Get functor */
-    MR_make_aligned_string(MR_LVALUE_CAST(MR_ConstString, Functor),
-        expand_info.functor);
-
-        /* Get arity */
-    Arity = expand_info.arity;
-
-        /* Build argument list */
-    Arguments = MR_list_empty_msg(MR_PROC_LABEL);
-    i = expand_info.arity;
-
-    while (--i >= 0) {
-
-            /* Create an argument on the heap */
-        MR_new_univ_on_hp(Argument,
-            expand_info.args.arg_type_infos[i],
-            expand_info.args.arg_values[i + expand_info.args.num_extra_args]);
-
-            /* Join the argument to the front of the list */
-        Arguments = MR_list_cons_msg(Argument, Arguments, MR_PROC_LABEL);
-    }
-
-    /*
-    ** Free the allocated arg_type_infos, since we just copied
-    ** all its arguments onto the heap.
-    */
-
-    if (expand_info.args.can_free_arg_type_infos) {
-        MR_GC_free(expand_info.args.arg_type_infos);
-    }
+    ML_abort_if_type_is_noncanonical(expand_info, ""deconstruct/4"");
+    ML_deconstruct_get_functor(expand_info, functor, Functor);
+    ML_deconstruct_get_arity(expand_info, Arity);
+    ML_deconstruct_get_arg_list(expand_info, args, Arguments);
+    ML_deconstruct_free_allocated_arg_type_infos(expand_info, args);
 }").
 
 :- pragma foreign_proc("C", 
@@ -3304,9 +3321,6 @@
 {
     ML_Expand_Functor_Args_Limit_Info	expand_info;
     MR_TypeInfo         				type_info;
-    MR_Word             				Argument;
-    MR_Word             				tmp;
-    int                 				i;
 
     type_info = (MR_TypeInfo) TypeInfo_for_T;
 
@@ -3314,72 +3328,35 @@
     ML_expand_functor_args_limit(type_info, &Term, MaxArity, &expand_info);
     MR_restore_transient_registers();
 
-        /*
-        ** Check for attempts to deconstruct a non-canonical type:
-        ** such deconstructions must be cc_multi, and since
-        ** deconstruct/4 is det, we must treat violations of this
-        ** as runtime errors.
-        ** (There ought to be a cc_multi version of deconstruct/4
-        ** that allows this.)
-        */
-    if (expand_info.non_canonical_type) {
-        MR_fatal_error(""called deconstruct/4 for a type with a ""
-            ""user-defined equality predicate"");
-    }
+    ML_abort_if_type_is_noncanonical(expand_info, ""limited_deconstruct/5"");
 
 	if (expand_info.limit_reached) {
 		SUCCESS_INDICATOR = FALSE;
 	} else {
 		SUCCESS_INDICATOR = TRUE;
 
-			/* Get functor */
-		MR_make_aligned_string(MR_LVALUE_CAST(MR_ConstString, Functor),
-			expand_info.functor);
-
-			/* Get arity */
-		Arity = expand_info.arity;
-
-			/* Build argument list */
-		Arguments = MR_list_empty_msg(MR_PROC_LABEL);
-		i = expand_info.arity;
-
-		while (--i >= 0) {
-
-				/* Create an argument on the heap */
-			MR_new_univ_on_hp(Argument,
-				expand_info.args.arg_type_infos[i],
-				expand_info.args.arg_values[i + expand_info.args.num_extra_args]);
-
-				/* Join the argument to the front of the list */
-			Arguments = MR_list_cons_msg(Argument, Arguments, MR_PROC_LABEL);
-		}
-
-		/*
-		** Free the allocated arg_type_infos, since we just copied
-		** all its arguments onto the heap.
-		*/
-
-		if (expand_info.args.can_free_arg_type_infos) {
-			MR_GC_free(expand_info.args.arg_type_infos);
-		}
+        ML_deconstruct_get_functor(expand_info, functor, Functor);
+        ML_deconstruct_get_arity(expand_info, Arity);
+        ML_deconstruct_get_arg_list(expand_info, args, Arguments);
+        ML_deconstruct_free_allocated_arg_type_infos(expand_info, args);
 	}
 }").
 
 :- pragma foreign_proc("MC++", 
 	deconstruct(_Term::in, _Functor::out, _Arity::out,
-        _Arguments::out), will_not_call_mercury, "
+	_Arguments::out),
+	[will_not_call_mercury], "
 {
 	mercury::runtime::Errors::SORRY(""foreign code for this function"");
-}
-").
+}").
 
 :- pragma foreign_proc("MC++", 
-	limited_deconstruct(_Term::in, _MaxArity::in, _Functor::out, _Arity::out,
-        _Arguments::out), will_not_call_mercury, "
+	limited_deconstruct(_Term::in, _MaxArity::in, _Functor::out,
+	_Arity::out, _Arguments::out),
+	[will_not_call_mercury], "
 {
 	mercury::runtime::Errors::SORRY(""foreign code for this function"");
-}
-").
+}").
 
 get_functor_info(Univ, FunctorInfo) :-
     ( univ_to_type(Univ, Int) ->
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list