[m-rev.] for review: implement det exceptions on the .NET backend.

Tyson Dowd trd at cs.mu.OZ.AU
Mon Aug 27 21:39:10 AEST 2001


On 24-Aug-2001, Peter Ross <peter.ross at miscrit.be> wrote:
> On Thu, Aug 23, 2001 at 06:42:03PM +0200, Tyson Dowd wrote:
> > Hi,
> > 
> > 
> > ===================================================================
> > 
> > 
> > Estimated hours taken: 16
> > Branches: main
> > 
> > Implement exceptions in the .NET backend.
> > (sorry, model_det exceptions only at the moment).
> > 
> > compiler/mlds_to_il.m:
> > 	Wrap two exception handlers around the Mercury code -- one that
> > 	prints out any uncaught user exceptions using
> > 	ML_report_uncaught_exception, and one that catches any system
> > 	exceptions and prints them using the system exception printing
> > 	mechanism.
> > 
> I think it would be nice to make clearer that a user exception is an
> exception that the Mercury runtime system understands and a system
> exception is any other exception.

Ok done.

> > library/exception.m:
> > 	Implement exceptions in C#.
> > 	try and catch call try_impl and catch_impl, which by default
> > 	call builtin_trd and builtin_catch, but we provide a
> > 	foreign_proc definition that implements them in C# on the .NET
> > 	backend.
> > 	We also implement ML_call_goal in Mercury, renaming the 
> > 	hand-coded versions appropriately.
> > 
> > library/math.m:
> > 	Throw mercury.runtime.SystemException for domain errors.
> > 
> Why?

Good question -- I think I should really throw a domain_error(string)
error.

Further investiation reveals that the math library doesn't throw
exceptions!  It prints Software Error and calls exit(1);

Probably this is because if you were to generate an exception you
couldn't mark the predicates as will_not_call_mercury, and thus you
would pay a performance penalty on certain backends (cough-llds-cough).

But on .NET I think we will instead throw a domain_error exception.

See the relative diff below.

> 
> > runtime/mercury_mcpp.cpp:
> > 	Fix the implementation of mercury.runtime.Exception -- now we
> > 	store the Mercury exception so you can retrieve it later.
> > 
> > 	Create a new class for Mercury runtime system exceptions, which
> > 	are generated by SORRY and fatal_error.  We can't expect to
> > 	print these exceptions using ML_report_uncaught_exception (at
> > 	the moment ML_report_uncaught_exception generates such
> > 	exceptions!) so we print them as normal .NET exceptions instead.
> > 
> > 
> > Index: compiler/mlds_to_il.m
> > ===================================================================
> > RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_il.m,v
> > retrieving revision 1.77
> > diff -u -r1.77 mlds_to_il.m
> > --- compiler/mlds_to_il.m	23 Aug 2001 09:28:03 -0000	1.77
> > +++ compiler/mlds_to_il.m	23 Aug 2001 16:37:50 -0000
> > @@ -990,7 +990,10 @@
> >  		il_info_add_init_instructions(runtime_initialization_instrs),
> >  		^ has_main := yes,
> >  
> > -		il_info_get_next_block_id(TryBlockId),
> > +		il_info_get_next_block_id(InnerTryBlockId),
> > +		il_info_get_next_block_id(OuterTryBlockId),
> > +		il_info_get_next_block_id(InnerCatchBlockId),
> > +		il_info_get_next_block_id(OuterCatchBlockId),
> >  		il_info_make_next_label(DoneLabel),
> >  
> >  			% Replace all the returns with leave instructions;
> > @@ -1006,43 +1009,123 @@
> >  				I
> >  			)
> >  		)},
> > +
> > +		{ UnivMercuryType = term__functor(term__atom("univ"), [], 
> > +			context("", 0)) },
> > +		{ UnivMLDSType = mercury_type(UnivMercuryType, user_type) },
> > +		{ UnivType = mlds_type_to_ilds_type(DataRep, UnivMLDSType) },
> > +
> >  		{ RenameNode = (func(N) = list__map(RenameRets, N)) },
> >  
> > -		{ ExceptionClassName = structured_name(assembly("mscorlib"),
> > +		{ MercuryExceptionClassName = structured_name(
> > +				assembly("mercury"),
> > +				["mercury", "runtime", "Exception"], []) },
> > +
> You should add a il_mercury_library_assembly_name function, and use that
> instead.

I have now used the existing mercury_runtime_name function here.

> > +__gc public class SystemException : public System::Exception
> > +{
> > +public:
> > +	SystemException(MR_String Msg) : System::Exception(Msg)
> > +	{	
> > +		// XXX this should set the exception message
> > +	}
> > +};
> 
> What happens now if you call SORRY or fatal_error,
> do you still get the message?  If not I think you should fix this.

The comment is wrong, this works fine.


Here is the relative diff, I will commit this shortly.

diff -u compiler/mlds_to_il.m compiler/mlds_to_il.m
--- compiler/mlds_to_il.m
+++ compiler/mlds_to_il.m
@@ -1022,10 +1022,9 @@
 
 		{ RenameNode = (func(N) = list__map(RenameRets, N)) },
 
-		{ MercuryExceptionClassName = structured_name(
-				assembly("mercury"),
-				["mercury", "runtime", "Exception"], []) },
-
+		{ MercuryExceptionClassName = 
+			mercury_runtime_name(["Exception"]) },
+		
 		{ ExceptionClassName = structured_name(il_system_assembly_name,
 				["System", "Exception"], []) },
 
@@ -1038,9 +1037,7 @@
 				id("Write")) },
 
 		{ UncaughtExceptionName = class_member_name(
-				structured_name(assembly("mercury"),
-					["mercury", "exception",
-						"mercury_code"], []),
+			mercury_library_wrapper_class_name(["exception"]),
 				id("ML_report_uncaught_exception")) },
 
 		{ WriteString = methoddef(call_conv(no, default),
@@ -1092,8 +1089,8 @@
 			% button on this window is a bit difficult
 			% remotely.
 			%
-			% Inside this exception handler, we catch any user
-			% exceptions and pass them 
+			% Inside this exception handler, we catch any 
+			% exceptions and print them.
 			%
 			% We nest the Mercury exception handler so that any
 			% exceptions thrown in ML_report_uncaught_exception
@@ -3783,10 +3780,18 @@
 
 %-----------------------------------------------------------------------------
 
-	% qualifiy a name with "[mercury]mercury."
+	% qualify a name with "[mercury]mercury."
 :- func mercury_library_name(ilds__namespace_qual_name) = ilds__class_name.
 mercury_library_name(Name) = 
 	structured_name(assembly("mercury"), ["mercury" | Name], []).
+
+	% qualify a name with "[mercury]mercury." and add the wrapper class
+	% name on the end.
+:- func mercury_library_wrapper_class_name(ilds__namespace_qual_name) = 
+		ilds__class_name.
+mercury_library_wrapper_class_name(Name) = 
+	structured_name(assembly("mercury"),
+		["mercury" | Name] ++ [wrapper_class_name], []).
 
 %-----------------------------------------------------------------------------
 
diff -u library/math.m library/math.m
--- library/math.m
+++ library/math.m
@@ -198,11 +198,21 @@
 :- func math__tanh(float) = float.
 :- mode math__tanh(in) = out is det.
 
+	% A domain error exception, indicates that the inputs to a function
+	% were outside the domain of the function.  The string indicates
+	% where the error occured.
+	%
+	% NOTE: not all backends will throw an exception in such an event, 
+	% they may abort instead.  It is also possible to switch domain
+	% checking off.
+	
+:- type domain_error ---> domain_error(string).
+
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
 :- implementation.
-:- import_module float.
+:- import_module float, exception.
 
 % These operations are mostly implemented using the C interface.
 
@@ -223,7 +233,9 @@
 	#define	ML_FLOAT_PI		3.1415926535897932384
 	#define	ML_FLOAT_LN2		0.69314718055994530941
 
+/*
 	void ML_math_domain_error(const char *where);
+*/
 
 "). % end pragma foreign_decl
 
@@ -233,6 +245,8 @@
 	// For pi and e we use the constants defined in System.Math.
 
 	public static double ML_FLOAT_LN2 = 0.69314718055994530941;
+	
+
 ").
 
 :- pragma foreign_code("C", "
@@ -259,18 +273,12 @@
 
 "). % end pragma foreign_code
 
-:- pragma foreign_code("C#", "
 
-/*
-** Handle domain errors.
-*/
-static void
-ML_math_domain_error(string where)
-{
-	throw new mercury.runtime.SystemException(where);
-}
+:- pred throw_math_domain_error(string::in) is erroneous.
 
-"). % end pragma foreign_code
+throw_math_domain_error(S) :- throw(domain_error(S)).
+
+:- pragma export(throw_math_domain_error(in), "ML_throw_math_domain_error").
 
 %
 % Mathematical constants from math.m
@@ -366,11 +374,12 @@
 	SquareRoot = sqrt(X);
 ").
 :- pragma foreign_proc("C#", math__sqrt(X::in) = (SquareRoot::out),
-		[will_not_call_mercury, thread_safe], "
+		[thread_safe], "
 #if ML_OMIT_MATH_DOMAIN_CHECKS
 #else
 	if (X < 0.0) {
-		ML_math_domain_error(""math__sqrt"");
+		mercury.math.mercury_code.ML_throw_math_domain_error(
+			""math__sqrt"");
 	}
 #endif
 	SquareRoot = System.Math.Sqrt(X);
@@ -448,16 +457,18 @@
 ").
 
 :- pragma foreign_proc("C#", math__pow(X::in, Y::in) = (Res::out),
-		[will_not_call_mercury, thread_safe], "
+		[thread_safe], "
 #if ML_OMIT_MATH_DOMAIN_CHECKS
 	Res = System.Math.Pow(X, Y);
 #else
 	if (X < 0.0) {
-		ML_math_domain_error(""math__pow"");
+		mercury.math.mercury_code.ML_throw_math_domain_error(
+			""math__pow"");
 	}
 	if (X == 0.0) {
 		if (Y <= 0.0) {
-			ML_math_domain_error(""math__pow"");
+			mercury.math.mercury_code.ML_throw_math_domain_error(
+				""math__pow"");
 		}
 		Res = 0.0;
 	} else {
@@ -497,11 +508,12 @@
 	Log = log(X);
 ").
 :- pragma foreign_proc("C#", math__ln(X::in) = (Log::out),
-		[will_not_call_mercury, thread_safe], "
+		[thread_safe], "
 #if ML_OMIT_MATH_DOMAIN_CHECKS
 #else 
 	if (X <= 0.0) {
-		ML_math_domain_error(""math__ln"");
+		mercury.math.mercury_code.ML_throw_math_domain_error(
+			""math__ln"");
 	}
 #endif
 	Log = System.Math.Log(X);
@@ -524,11 +536,12 @@
 	Log10 = log10(X);
 ").
 :- pragma foreign_proc("C#", math__log10(X::in) = (Log10::out),
-		[will_not_call_mercury, thread_safe], "
+		[thread_safe], "
 #if ML_OMIT_MATH_DOMAIN_CHECKS
 #else
 	if (X <= 0.0) {
-		ML_math_domain_error(""math__log10"");
+		mercury.math.mercury_code.ML_throw_math_domain_error(
+			""math__log10"");
 	}
 #endif
 	Log10 = System.Math.Log10(X);
@@ -551,11 +564,12 @@
 	Log2 = log(X) / ML_FLOAT_LN2;
 ").
 :- pragma foreign_proc("C#", math__log2(X::in) = (Log2::out),
-		[will_not_call_mercury, thread_safe], "
+		[thread_safe], "
 #if ML_OMIT_MATH_DOMAIN_CHECKS
 #else
 	if (X <= 0.0) {
-		ML_math_domain_error(""math__log2"");
+		mercury.math.mercury_code.ML_throw_math_domain_error(
+			""math__log2"");
 	}
 #endif
 	Log2 = System.Math.Log(X) / ML_FLOAT_LN2;
@@ -583,14 +597,16 @@
 	Log = log(X)/log(B);
 ").
 :- pragma foreign_proc("C#", math__log(B::in, X::in) = (Log::out),
-		[will_not_call_mercury, thread_safe], "
+		[thread_safe], "
 #if ML_OMIT_MATH_DOMAIN_CHECKS
 #else 
 	if (X <= 0.0 || B <= 0.0) {
-		ML_math_domain_error(""math__log"");
+		mercury.math.mercury_code.ML_throw_math_domain_error(
+			""math__log"");
 	}
 	if (B == 1.0) {
-		ML_math_domain_error(""math__log"");
+		mercury.math.mercury_code.ML_throw_math_domain_error(
+			""math__log"");
 	}
 #endif
 	Log = System.Math.Log(X,B);
@@ -651,11 +667,12 @@
 	ASin = asin(X);
 ").
 :- pragma foreign_proc("C#", math__asin(X::in) = (ASin::out),
-		[will_not_call_mercury, thread_safe], "
+		[thread_safe], "
 #if ML_OMIT_MATH_DOMAIN_CHECKS
 #else
 	if (X < -1.0 || X > 1.0) {
-		ML_math_domain_error(""math__asin"");
+		mercury.math.mercury_code.ML_throw_math_domain_error(
+			""math__asin"");
 	}
 #endif
 	ASin = System.Math.Asin(X);
@@ -678,11 +695,12 @@
 	ACos = acos(X);
 ").
 :- pragma foreign_proc("C#", math__acos(X::in) = (ACos::out),
-		[will_not_call_mercury, thread_safe], "
+		[thread_safe], "
 #if ML_OMIT_MATH_DOMAIN_CHECKS
 #else
 	if (X < -1.0 || X > 1.0) {
-		ML_math_domain_error(""math__acos"");
+		mercury.math.mercury_code.ML_throw_math_domain_error(
+			""math__acos"");
 	}
 #endif
 	ACos = System.Math.Acos(X);
diff -u runtime/mercury_mcpp.cpp runtime/mercury_mcpp.cpp
--- runtime/mercury_mcpp.cpp
+++ runtime/mercury_mcpp.cpp
@@ -43,7 +43,8 @@
 public:
 	SystemException(MR_String Msg) : System::Exception(Msg)
 	{	
-		// XXX this should set the exception message
+		// the parent constructor sets the error message that
+		// will be printed.
 	}
 };
 

--------------------------------------------------------------------------
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