From 07f57e1ffe9432d3b19d25ae31ed9b473bc80f6f Mon Sep 17 00:00:00 2001 From: Martin Berends Date: Mon, 25 Oct 2010 15:49:27 +0100 Subject: [PATCH] [java/runtime] catch up to dotnet in throw and catch handlers --- java/runtime/Makefile | 18 +++- java/runtime/Rakudo/Init.java | 10 +- .../KnowHOW/KnowHOWBootstrapper.java | 61 +++++++++--- .../Rakudo/Metamodel/RakudoObject.java | 6 +- .../Representations/RakudoCodeRef.java | 18 ++-- .../runtime/Rakudo/Metamodel/SharedTable.java | 95 ++++++++++--------- .../LeaveStackUnwinderException.java | 2 +- java/runtime/Rakudo/Runtime/Ops.java | 2 +- 8 files changed, 135 insertions(+), 77 deletions(-) diff --git a/java/runtime/Makefile b/java/runtime/Makefile index 950280f..d40c574 100644 --- a/java/runtime/Makefile +++ b/java/runtime/Makefile @@ -9,11 +9,13 @@ # SerializationContext # | | # +------------------------> RakudoObject | -# | | | | | -# | Parameter Lexpad | | -# | | | | | -# | Signature | Representation | -# | | | | | | | +# | | | | | | +# | Parameter | Lexpad | | +# | | | | | | +# | | Handler | | | +# | | | | | | +# | Signature | | Representation | +# | | | | | | | | # | +--+----------------> RakudoCodeRef | | | # | | | | | | | # 1 2 3 ExecutionDomain Context | | | @@ -63,6 +65,7 @@ ALL_BUILD_TARGETS = \ OTHER_DEPENDENT_TARGETS = \ $(CLASSES)Rakudo/Runtime/CaptureHelper.class \ + $(CLASSES)Rakudo/Runtime/Exceptions/Handler.class \ $(CLASSES)Rakudo/Runtime/Exceptions/LeaveStackUnwinderException.class \ $(CLASSES)Rakudo/Runtime/Lexpad.class \ $(CLASSES)Rakudo/Runtime/Parameter.class \ @@ -123,6 +126,7 @@ $(CLASSES)Rakudo/Metamodel/RakudoObject.class: Rakudo/Metamodel/RakudoObject.jav Rakudo/Metamodel/Representations/RakudoCodeRef.java \ Rakudo/Metamodel/REPRRegistry.java \ Rakudo/Runtime/Context.java \ + Rakudo/Runtime/Exceptions/Handler.java \ Rakudo/Runtime/Exceptions/LeaveStackUnwinderException.java \ Rakudo/Runtime/MultiDispatch/LexicalCandidateFinder.java \ Rakudo/Runtime/MultiDispatch/MultiDispatcher.java \ @@ -143,6 +147,7 @@ $(CLASSES)Rakudo/Metamodel/RakudoObject.class: Rakudo/Metamodel/RakudoObject.jav Rakudo/Metamodel/Representations/RakudoCodeRef.java \ Rakudo/Metamodel/REPRRegistry.java \ Rakudo/Runtime/Context.java \ + Rakudo/Runtime/Exceptions/Handler.java \ Rakudo/Runtime/Exceptions/LeaveStackUnwinderException.java \ Rakudo/Runtime/MultiDispatch/LexicalCandidateFinder.java \ Rakudo/Runtime/MultiDispatch/MultiDispatcher.java \ @@ -348,6 +353,9 @@ Rakudo/Runtime/CodeObjectUtility.java: ../../dotnet/runtime/Runtime/CodeObjectUt Rakudo/Runtime/Context.java: ../../dotnet/runtime/Runtime/Context.cs @echo "todo: Rakudo/Runtime/Context.java is older than ../../dotnet/runtime/Runtime/Context.cs" +Rakudo/Runtime/Exceptions/Handler.java: ../../dotnet/runtime/Runtime/Exceptions/Handler.cs + @echo "todo: Rakudo/Runtime/Exceptions/Handler.java is older than ../../dotnet/runtime/Runtime/Exceptions/Handler.cs" + Rakudo/Runtime/Exceptions/LeaveStackUnwinderException.java: ../../dotnet/runtime/Runtime/Exceptions/LeaveStackUnwinderException.cs @echo "todo: Rakudo/Runtime/Exceptions/LeaveStackUnwinderException.java is older than ../../dotnet/runtime/Runtime/Exceptions/LeaveStackUnwinderException.cs" diff --git a/java/runtime/Rakudo/Init.java b/java/runtime/Rakudo/Init.java index b4ffcd9..ae4cdc9 100644 --- a/java/runtime/Rakudo/Init.java +++ b/java/runtime/Rakudo/Init.java @@ -40,6 +40,7 @@ public static ThreadContext Initialize(String settingName) // Bootstrap the meta-model. RegisterRepresentations(); RakudoObject knowHOW = KnowHOWBootstrapper.Bootstrap(); + RakudoObject knowHOWAttribute = KnowHOWBootstrapper.SetupKnowHOWAttribute(knowHOW); // Either load a named setting or use the fake bootstrapping one. Context settingContext = @@ -61,6 +62,7 @@ public static ThreadContext Initialize(String settingName) threadContext.DefaultNumBoxType = settingContext.LexPad.GetByName("NQPNum"); threadContext.DefaultStrBoxType = settingContext.LexPad.GetByName("NQPStr"); threadContext.DefaultListType = settingContext.LexPad.GetByName("NQPList"); + return threadContext; } @@ -96,7 +98,7 @@ private static Context BootstrapSetting(RakudoObject KnowHOW) System.err.println( "calling new Context from Init" ); Context settingContext = new Context(); settingContext.LexPad = new Lexpad(new String[] - { "KnowHOW", "capture", "NQPInt", "NQPNum", "NQPStr", "NQPList", "LLCode", "list" }); + { "KnowHOW", "capture", "NQPInt", "NQPNum", "NQPStr", "NQPList", "NQPCode", "list" }); RakudoCodeRef.IFunc_Body funcBody = new RakudoCodeRef.IFunc_Body() { // create an anonymous class public RakudoObject Invoke(ThreadContext tc, RakudoObject self, RakudoObject capture) { @@ -128,7 +130,7 @@ public RakudoObject Invoke(ThreadContext tc, RakudoObject self, RakudoObject cap /// /// /// - public static Context LoadSetting(String settingName, RakudoObject knowHOW) + public static Context LoadSetting(String settingName, RakudoObject knowHOW, RakudoObject knowHOWAttribute) { // Load the assembly. System.err.println("Init.LoadSetting begin loading " + settingName ); @@ -192,9 +194,10 @@ public static Context LoadSetting(String settingName, RakudoObject knowHOW) // Fudge a few more things in. // XXX Should be able to toss all of these but KnowHOW. settingContext.LexPad.Extend(new String[] - { "KnowHOW", "print", "say", "capture", "LLCode" }); + { "KnowHOW", "KnowHOWAttribute", "print", "say", "capture", "LLCode" }); settingContext.LexPad.SetByName("KnowHOW", knowHOW); + settingContext.LexPad.SetByName("KnowHOWAttribute", knowHOWAttribute); RakudoCodeRef.IFunc_Body funcPrint = new RakudoCodeRef.IFunc_Body() { // create an anonymous class @@ -222,7 +225,6 @@ public RakudoObject Invoke(ThreadContext tc, RakudoObject self, RakudoObject cap }; settingContext.LexPad.SetByName("say", CodeObjectUtility.WrapNativeMethod(funcSay)); settingContext.LexPad.SetByName("capture", REPRRegistry.get_REPR_by_name("P6capture").type_object_for(null,null)); - settingContext.LexPad.SetByName("LLCode", REPRRegistry.get_REPR_by_name("RakudoCodeRef").type_object_for(null, knowHOW.getSTable().REPR.instance_of(null, knowHOW))); return settingContext; } diff --git a/java/runtime/Rakudo/Metamodel/KnowHOW/KnowHOWBootstrapper.java b/java/runtime/Rakudo/Metamodel/KnowHOW/KnowHOWBootstrapper.java index 51a3679..ec6e753 100644 --- a/java/runtime/Rakudo/Metamodel/KnowHOW/KnowHOWBootstrapper.java +++ b/java/runtime/Rakudo/Metamodel/KnowHOW/KnowHOWBootstrapper.java @@ -23,8 +23,7 @@ /// for implementing the various other bits of the object model. /// Works in conjunction with KnowHOWREPR. /// -public class KnowHOWBootstrapper -// public static class KnowHOWBootstrapper // the C# version +public class KnowHOWBootstrapper // public static in the C# version { /// /// Bootstraps the KnowHOW. This is were things "bottom out" in the @@ -117,9 +116,7 @@ public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject return HOW.Methods.get(Ops.unbox_str(tc, Positionals[1])); else { // throw new NoSuchMethodException("No such method " + Ops.unbox_str(tc, Positionals[1])); - System.err.println("No such method " + Ops.unbox_str(tc, Positionals[1])); - System.exit(1); - return null; + throw new UnsupportedOperationException("No such method " + Ops.unbox_str(tc, Positionals[1])); } } }; @@ -141,6 +138,9 @@ public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject { // create an anonymous class public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject capture) { + // Safe to just return a P6list instance that points at + // the same thing we hold internally, since a list is + // immutable. KnowHOWREPR.KnowHOWInstance HOW = (KnowHOWREPR.KnowHOWInstance)CaptureHelper.GetPositional(capture, 0); RakudoObject Result = tc.DefaultListType.getSTable().REPR.instance_of(tc, tc.DefaultListType); ((P6list.Instance)Result).Storage = HOW.Attributes; @@ -181,11 +181,11 @@ public RakudoObject Invoke(ThreadContext tc, RakudoObject ignored, RakudoObject KnowHOWHOW.Methods.put(key, KnowHOWMeths.get(key)); // We need to clone the STable. - SharedTable STableCopy = new SharedTable(); - STableCopy.HOW = KnowHOWHOW; - STableCopy.WHAT = KnowHOW.getSTable().WHAT; - STableCopy.REPR = KnowHOW.getSTable().REPR; - KnowHOWHOW.setSTable(STableCopy); + SharedTable sTableCopy = new SharedTable(); + sTableCopy.HOW = KnowHOWHOW; + sTableCopy.WHAT = KnowHOW.getSTable().WHAT; + sTableCopy.REPR = KnowHOW.getSTable().REPR; + KnowHOWHOW.setSTable(sTableCopy); // And put a fake FindMethod in there that just looks in the // dictionary. @@ -197,10 +197,7 @@ public RakudoObject FindMethod(ThreadContext tc, RakudoObject obj, String name, if (MTable.containsKey(name)) return MTable.get(name); else { - // throw new InvalidOperationException("No such method " + Name); - System.err.println("No such method " + name); - System.exit(1); - return null; + throw new UnsupportedOperationException("No such method " + name); } } }; @@ -212,5 +209,41 @@ public RakudoObject FindMethod(ThreadContext tc, RakudoObject obj, String name, // And we should be done. return KnowHOW; } + + /// + /// Sets up the KnowHOWAttribute object/class, which actually is a + /// KnowHOW. + /// + /// + public static RakudoObject SetupKnowHOWAttribute(RakudoObject knowHOW) + { + // Create a new HOW instance. + KnowHOWREPR.KnowHOWInstance HOW = (KnowHOWREPR.KnowHOWInstance)knowHOW.getSTable().REPR.instance_of(null, knowHOW); + + // We base the attribute on P6str, since we just want to store an + // attribute name for now. + RakudoObject knowHOWAttribute = REPRRegistry.get_REPR_by_name("P6str").type_object_for(null, HOW); + + // Add methods new and Str. + RakudoCodeRef.IFunc_Body meth_new = new RakudoCodeRef.IFunc_Body() { // the C# version uses a lambda + public RakudoObject Invoke(ThreadContext tc, RakudoObject obj, RakudoObject capture) + { + RakudoObject WHAT = CaptureHelper.GetPositional(capture, 0).getSTable().WHAT; + String name = Ops.unbox_str(tc, CaptureHelper.GetNamed(capture, "name")); + return Ops.box_str(tc, name, WHAT); + } + }; + HOW.Methods.put("new", CodeObjectUtility.WrapNativeMethod(meth_new)); + RakudoCodeRef.IFunc_Body meth_name = new RakudoCodeRef.IFunc_Body() { // the C# version uses a lambda + public RakudoObject Invoke(ThreadContext tc, RakudoObject obj, RakudoObject capture) + { + RakudoObject self = CaptureHelper.GetPositional(capture, 0); + return Ops.box_str(tc, Ops.unbox_str(tc, self), tc.DefaultStrBoxType); + } + }; + HOW.Methods.put("name", CodeObjectUtility.WrapNativeMethod(meth_name)); + + return knowHOWAttribute; + } } diff --git a/java/runtime/Rakudo/Metamodel/RakudoObject.java b/java/runtime/Rakudo/Metamodel/RakudoObject.java index fcfcc15..4aaafce 100644 --- a/java/runtime/Rakudo/Metamodel/RakudoObject.java +++ b/java/runtime/Rakudo/Metamodel/RakudoObject.java @@ -13,9 +13,9 @@ public abstract class RakudoObject /// Every object must have a way to refer to the shared table, /// which contains the commonalities this object has. /// - private SharedTable STable; - public SharedTable getSTable() { return STable; } - public void setSTable( SharedTable st ) { STable = st; } + private SharedTable sTable; + public SharedTable getSTable() { return sTable; } + public void setSTable( SharedTable st ) { sTable = st; } // SharedTable STable { get; set; } // the C# version /// diff --git a/java/runtime/Rakudo/Metamodel/Representations/RakudoCodeRef.java b/java/runtime/Rakudo/Metamodel/Representations/RakudoCodeRef.java index 0fa66d1..d96abc4 100644 --- a/java/runtime/Rakudo/Metamodel/Representations/RakudoCodeRef.java +++ b/java/runtime/Rakudo/Metamodel/Representations/RakudoCodeRef.java @@ -1,7 +1,9 @@ package Rakudo.Metamodel.Representations; import java.util.HashMap; + import Rakudo.Runtime.Context; +import Rakudo.Runtime.Exceptions.Handler; import Rakudo.Runtime.ThreadContext; import Rakudo.Runtime.Lexpad; import Rakudo.Runtime.Parameter; @@ -23,8 +25,8 @@ public final class RakudoCodeRef implements Representation // implement it, as the Java equivalent of a C# lambda expression. // Used in for example: CodeObjectUtility public interface IFunc_Body { - public RakudoObject Invoke(ThreadContext tc, RakudoObject ro1, RakudoObject ro2); - } + public RakudoObject Invoke(ThreadContext tc, RakudoObject meth, RakudoObject capt); + } // C# has public Func; // TODO: why 4 parameters and not 3? /// /// This is how the boxed form of a P6str looks. @@ -35,7 +37,6 @@ public final class Instance extends RakudoObject /// The code body - the thing that actually runs instructions. /// public RakudoCodeRef.IFunc_Body Body; // IFunc_Body is defined above Instance - // public Func Body; /// /// The static lexpad. @@ -57,6 +58,11 @@ public final class Instance extends RakudoObject /// public Context CurrentContext; + /// + /// Exception handlers this block has, if any. + /// + public Handler[] Handlers; + /// /// Constructor. /// @@ -81,10 +87,10 @@ public RakudoObject type_object_for(ThreadContext tc, RakudoObject MetaPackage) // Also twiddle the S-Table's Invoke to invoke the contained // function. - sTable.Invoke = new IFunc_Body() { // create an anonymous class - public RakudoObject Invoke( ThreadContext TC, RakudoObject Obj, RakudoObject Cap ) + sTable.Invoke = new IFunc_Body() { // the C# version has a lambda + public RakudoObject Invoke( ThreadContext tci, RakudoObject meth, RakudoObject capt ) { - return ((RakudoCodeRef.Instance)Obj).Body.Invoke(TC, Obj, Cap); + return ((RakudoCodeRef.Instance)meth).Body.Invoke(tci, meth, capt); } }; return sTable.WHAT; diff --git a/java/runtime/Rakudo/Metamodel/SharedTable.java b/java/runtime/Rakudo/Metamodel/SharedTable.java index 85e31b8..4875964 100644 --- a/java/runtime/Rakudo/Metamodel/SharedTable.java +++ b/java/runtime/Rakudo/Metamodel/SharedTable.java @@ -1,5 +1,4 @@ package Rakudo.Metamodel; - import Rakudo.Metamodel.IFindMethod; import Rakudo.Metamodel.RakudoObject; import Rakudo.Metamodel.Representation; @@ -14,47 +13,8 @@ /// a given "type". Type in this context refers to a given combination /// of meta-object and representation. /// -public class SharedTable -// public sealed class SharedTable // the C# version +public final class SharedTable // public sealed in the C# version { - /// - /// This finds a method with the given name or using a hint. - /// - public IFindMethod FindMethod = - new IFindMethod() { // anonymous class instead of lambda-expression - public RakudoObject FindMethod(ThreadContext tc, RakudoObject obj, String name, int hint) - { - // See if we can find it by hint. - if (hint != Hints.NO_HINT && obj.getSTable().VTable != null && hint < obj.getSTable().VTable.length) - { - // Yes, just grab it from the v-table. - return obj.getSTable().VTable[hint]; - } - else - { - // Find the find_method method. - RakudoObject HOW = obj.getSTable().HOW; - RakudoObject meth = HOW.getSTable().FindMethod.FindMethod(tc, HOW, "find_method", Hints.NO_HINT); - - // Call it. - RakudoObject cap = CaptureHelper.FormWith(new RakudoObject[] { HOW, Ops.box_str(tc, name, tc.DefaultStrBoxType) }); - return meth.getSTable().Invoke.Invoke(tc, meth, cap); - } - } - }; - - /// - /// The default invoke looks up a postcircumfix:<( )> and runs that. - /// XXX Cache the hint where we can. - /// - public RakudoCodeRef.IFunc_Body Invoke = new RakudoCodeRef.IFunc_Body() { // create an anonymous class - public RakudoObject Invoke( ThreadContext TC, RakudoObject Obj, RakudoObject Cap ) - { - RakudoObject invokable = Obj.getSTable().FindMethod.FindMethod(TC, Obj, "postcircumfix:<( )>", Hints.NO_HINT); - return invokable.getSTable().Invoke.Invoke(TC, Obj, Cap); - } - }; - /// /// The representation object that manages object layout. /// @@ -72,6 +32,55 @@ public RakudoObject Invoke( ThreadContext TC, RakudoObject Obj, RakudoObject Cap /// public RakudoObject WHAT; + /// + /// This finds a method with the given name or using a hint. + /// + public IFindMethod FindMethod = new IFindMethod() { // this anonymous class is a lambda in the C# version + public RakudoObject FindMethod(ThreadContext tc, RakudoObject obj, String name, int hint) + { + // See if we can find it by hint. + if (hint != Hints.NO_HINT && obj.getSTable().VTable != null && hint < obj.getSTable().VTable.length) + { + // Yes, just grab it from the v-table. + return obj.getSTable().VTable[hint]; + } + else + { + // Find the find_method method. + RakudoObject HOW = obj.getSTable().HOW; + RakudoObject meth = CachedFindMethod; + if (meth == null) + obj.getSTable().CachedFindMethod = meth = HOW.getSTable().FindMethod.FindMethod( + tc, HOW, "find_method", Hints.NO_HINT); + + // Call it. + RakudoObject capt = CaptureHelper.FormWith(new RakudoObject[] { HOW, Ops.box_str(tc, name, tc.DefaultStrBoxType) }); + return meth.getSTable().Invoke.Invoke(tc, meth, capt); + } + } + }; + /// + /// We keep a cache of the find_method method. + /// + private RakudoObject CachedFindMethod; // internal in the C# version + + /// + /// The default invoke looks up a postcircumfix:<( )> and runs that. + /// XXX Cache the hint where we can. + /// + public RakudoCodeRef.IFunc_Body Invoke = new RakudoCodeRef.IFunc_Body() { // this anonymous class is a lambda in the C# version + public RakudoObject Invoke( ThreadContext tc, RakudoObject meth, RakudoObject capt ) + { + SharedTable sTable = meth.getSTable(); + RakudoObject invokable = (sTable.CachedInvoke != null) ? sTable.CachedInvoke : (sTable.CachedInvoke = meth.getSTable().FindMethod.FindMethod(tc, meth, "postcircumfix:<( )>", Hints.NO_HINT)); + return invokable.getSTable().Invoke.Invoke(tc, meth, capt); + } + }; + /// + /// We keep a cache of the postcircumfix:<( )> method. + /// + private RakudoObject CachedInvoke; // internal in the C# version + /// /// The serialization context of this STable, if any. /// @@ -99,8 +108,7 @@ public long TypeCacheID () { id = TypeCacheIDSource; } return id; - } - // public long TypeCacheID = Interlocked.Increment(ref TypeIDSource); // the C# version + } // public long TypeCacheID = Interlocked.Increment(ref TypeIDSource); // the C# version /// /// Source of type IDs. The lowest one is 4. This is to make the lower @@ -108,5 +116,6 @@ public long TypeCacheID () { /// multi dispatch cache, which is the primary user of these IDs. /// private static long TypeCacheIDSource = 4; + } diff --git a/java/runtime/Rakudo/Runtime/Exceptions/LeaveStackUnwinderException.java b/java/runtime/Rakudo/Runtime/Exceptions/LeaveStackUnwinderException.java index 6d81945..5514d5b 100644 --- a/java/runtime/Rakudo/Runtime/Exceptions/LeaveStackUnwinderException.java +++ b/java/runtime/Rakudo/Runtime/Exceptions/LeaveStackUnwinderException.java @@ -7,7 +7,7 @@ /// This exception is thrown to actually unwind the (dotnet) stack after /// we run an exception handler. /// -public class LeaveStackUnwinderException extends Exception +public class LeaveStackUnwinderException extends RuntimeException // not Exception, see http://www.javapractices.com/topic/TopicAction.do?Id=129 { /// /// The block we're looking for. diff --git a/java/runtime/Rakudo/Runtime/Ops.java b/java/runtime/Rakudo/Runtime/Ops.java index 7b1fad3..ad7190a 100644 --- a/java/runtime/Rakudo/Runtime/Ops.java +++ b/java/runtime/Rakudo/Runtime/Ops.java @@ -687,7 +687,7 @@ public static RakudoObject llmapping_elems(ThreadContext tc, RakudoObject lowlev /// /// public static RakudoObject leave_block(ThreadContext tc, RakudoObject block, RakudoObject returnValue) - throws LeaveStackUnwinderException +// throws LeaveStackUnwinderException { throw new LeaveStackUnwinderException((RakudoCodeRef.Instance)block, returnValue); }