[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