You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2011/04/14 00:23:20 UTC

svn commit: r1091947 - in /tapestry/tapestry5/trunk: plastic/src/main/java/org/apache/tapestry5/internal/plastic/ plastic/src/main/java/org/apache/tapestry5/plastic/ tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ tapestry-ioc/src/m...

Author: hlship
Date: Wed Apr 13 22:23:19 2011
New Revision: 1091947

URL: http://svn.apache.org/viewvc?rev=1091947&view=rev
Log:
TAP5-853: Redesign the portion of the Plastic API for generating conditional statements

Added:
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/Condition.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ConditionCallback.java
Modified:
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java?rev=1091947&r1=1091946&r2=1091947&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java Wed Apr 13 22:23:19 2011
@@ -15,11 +15,15 @@
 package org.apache.tapestry5.internal.plastic;
 
 import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.tapestry5.internal.plastic.asm.Label;
 import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.Type;
+import org.apache.tapestry5.plastic.Condition;
+import org.apache.tapestry5.plastic.ConditionCallback;
 import org.apache.tapestry5.plastic.InstructionBuilder;
 import org.apache.tapestry5.plastic.InstructionBuilderCallback;
 import org.apache.tapestry5.plastic.MethodDescription;
@@ -35,6 +39,19 @@ public class InstructionBuilderImpl exte
     private static final int[] DUPE_OPCODES = new int[]
     { DUP, DUP_X1, DUP_X2 };
 
+    /** Maps from condition to opcode to jump to the false code block. */
+    private static final Map<Condition, Integer> conditionToOpcode = new HashMap<Condition, Integer>();
+
+    static
+    {
+        Map<Condition, Integer> m = conditionToOpcode;
+
+        m.put(Condition.NULL, IFNONNULL);
+        m.put(Condition.NON_NULL, IFNULL);
+        m.put(Condition.ZERO, IFNE);
+        m.put(Condition.NON_ZERO, IFEQ);
+    }
+
     protected final InstructionBuilderState state;
 
     protected final MethodVisitor v;
@@ -598,6 +615,53 @@ public class InstructionBuilderImpl exte
         v.visitLabel(endIfLabel);
     }
 
+    public InstructionBuilder conditional(Condition condition, final InstructionBuilderCallback ifTrue)
+    {
+        check();
+
+        return conditional(condition, new ConditionCallback()
+        {
+            public void ifTrue(InstructionBuilder builder)
+            {
+                ifTrue.doBuild(builder);
+            }
+
+            public void ifFalse(InstructionBuilder builder)
+            {
+            }
+        });
+    }
+
+    public InstructionBuilder conditional(Condition condition, ConditionCallback callback)
+    {
+        check();
+
+        Label ifFalseLabel = new Label();
+        Label endIfLabel = new Label();
+
+        v.visitJumpInsn(conditionToOpcode.get(condition), ifFalseLabel);
+
+        InstructionBuilderImpl trueBuilder = new InstructionBuilderImpl(state);
+
+        callback.ifTrue(trueBuilder);
+
+        trueBuilder.lock();
+
+        v.visitJumpInsn(GOTO, endIfLabel);
+
+        v.visitLabel(ifFalseLabel);
+
+        InstructionBuilderImpl falseBuilder = new InstructionBuilderImpl(state);
+
+        callback.ifFalse(falseBuilder);
+
+        falseBuilder.lock();
+
+        v.visitLabel(endIfLabel);
+
+        return this;
+    }
+
     void doCallback(InstructionBuilderCallback callback)
     {
         check();

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java?rev=1091947&r1=1091946&r2=1091947&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java Wed Apr 13 22:23:19 2011
@@ -42,6 +42,8 @@ import org.apache.tapestry5.internal.pla
 import org.apache.tapestry5.plastic.AnnotationAccess;
 import org.apache.tapestry5.plastic.ClassInstantiator;
 import org.apache.tapestry5.plastic.ComputedValue;
+import org.apache.tapestry5.plastic.Condition;
+import org.apache.tapestry5.plastic.ConditionCallback;
 import org.apache.tapestry5.plastic.FieldConduit;
 import org.apache.tapestry5.plastic.FieldHandle;
 import org.apache.tapestry5.plastic.InstanceContext;
@@ -1309,7 +1311,7 @@ public class PlasticClassImpl extends Lo
                     {
                         builder.invoke(MethodInvocation.class, boolean.class, "didThrowCheckedException");
 
-                        builder.ifZero(null, new InstructionBuilderCallback()
+                        builder.conditional(Condition.NON_ZERO, new InstructionBuilderCallback()
                         {
                             public void doBuild(InstructionBuilder builder)
                             {

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/Condition.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/Condition.java?rev=1091947&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/Condition.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/Condition.java Wed Apr 13 22:23:19 2011
@@ -0,0 +1,23 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.plastic;
+
+/**
+ * Condition used with {@link InstructionBuilder#conditional(Condition, ConditionCallback)}.
+ */
+public enum Condition
+{
+    NULL, NON_NULL, ZERO, NON_ZERO;
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ConditionCallback.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ConditionCallback.java?rev=1091947&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ConditionCallback.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ConditionCallback.java Wed Apr 13 22:23:19 2011
@@ -0,0 +1,27 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.plastic;
+
+/**
+ * Used with {@link InstructionBuilder#conditional(Condition, ConditionCallback)}.
+ */
+public interface ConditionCallback
+{
+    /** Generates code for when the condition is true. */
+    void ifTrue(InstructionBuilder builder);
+
+    /** Generates code for when the condition is false. */
+    void ifFalse(InstructionBuilder builder);
+}

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java?rev=1091947&r1=1091946&r2=1091947&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java Wed Apr 13 22:23:19 2011
@@ -386,26 +386,32 @@ public interface InstructionBuilder
     InstructionBuilder loadVariable(String name);
 
     /**
-     * Checks if the top value on the stack is zero and invokes the code from one of the two callbacks.
+     * Executes conditional code based on a {@link Condition}. The testing opcodes all pop
+     * the value off the stack, so this is usually preceded by {@link #dupe(int) dupe(0)}.
      * 
-     * @param ifTrue
-     *            callback to generate code for the case where the top value on the stack is zero (may be null)
-     * @param ifFalse
-     *            callback to generate code for the case where the top value on the stack is non-zero
-     *            (may be null)
+     * @param condition
+     *            defines true and false cases
+     * @param callback
+     *            provides code for true and false blocks
+     * @return this builder
      */
-    @Opcodes("IFEQ, GOTO")
-    InstructionBuilder ifZero(InstructionBuilderCallback ifTrue, InstructionBuilderCallback ifFalse);
+    @Opcodes("IFEQ, etc., GOTO")
+    InstructionBuilder conditional(Condition condition, ConditionCallback callback);
 
     /**
-     * Checks if the top value on the stack is null and invokes the code from one of the two callbacks.
+     * Simplified version of {@link #conditional(Condition, ConditionCallback)} that
+     * simply executes the callback code when the condition is true and does nothing
+     * if the condition is false (the more general case).
+     * <p>
+     * The testing opcodes all pop the value off the stack, so this is usually preceded by {@link #dupe(int) dupe(0)}.
      * 
+     * @param condition
+     *            to evaluate
      * @param ifTrue
-     *            callback to generate code for the case where the top value on the stack is null (may be null)
-     * @param ifFalse
-     *            callback to generate code for the case where the top value on the stack is not null
-     *            (may be null)
+     *            generates code for when condition is true
+     * @return
      */
-    @Opcodes("IFNULL, GOTO")
-    InstructionBuilder ifNull(InstructionBuilderCallback ifTrue, InstructionBuilderCallback ifFalse);
+    @Opcodes("IFEQ, etc., GOTO")
+    InstructionBuilder conditional(Condition condition, InstructionBuilderCallback ifTrue);
+
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java?rev=1091947&r1=1091946&r2=1091947&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java Wed Apr 13 22:23:19 2011
@@ -67,6 +67,8 @@ import org.apache.tapestry5.ioc.services
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.BodyBuilder;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.Condition;
+import org.apache.tapestry5.plastic.ConditionCallback;
 import org.apache.tapestry5.plastic.InstructionBuilder;
 import org.apache.tapestry5.plastic.InstructionBuilderCallback;
 import org.apache.tapestry5.plastic.MethodDescription;
@@ -413,14 +415,14 @@ public class PropertyConduitSourceImpl i
                 public void doBuild(InstructionBuilder builder)
                 {
                     builder.loadArgument(0).dupe(0);
-                    builder.ifNull(new InstructionBuilderCallback()
+                    builder.conditional(Condition.NULL, new InstructionBuilderCallback()
                     {
                         public void doBuild(InstructionBuilder builder)
                         {
                             builder.throwException(NullPointerException.class,
                                     String.format("Root object of property expression '%s' is null.", expression));
                         }
-                    }, null);
+                    });
 
                     builder.checkcast(rootType).returnResult();
                 }
@@ -797,7 +799,18 @@ public class PropertyConduitSourceImpl i
         {
             builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
 
-            builder.dupe(0).ifNull(RETURN_RESULT, null);
+            returnResultIfNull(builder);
+        }
+
+        public void returnResultIfNull(InstructionBuilder builder)
+        {
+            builder.dupe(0).conditional(Condition.NULL, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.returnResult();
+                }
+            });
         }
 
         private Class buildSubexpression(InstructionBuilder builder, Class activeType, Tree node)
@@ -878,7 +891,7 @@ public class PropertyConduitSourceImpl i
         {
             builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
 
-            builder.dupe(0).ifNull(RETURN_RESULT, null);
+            returnResultIfNull(builder);
         }
 
         private void createNotOpGetter(Tree node, String rootName)
@@ -1503,7 +1516,7 @@ public class PropertyConduitSourceImpl i
                         createPlasticMethodInvocation(builder, term, method, info);
                     }
 
-                    builder.dupe(0).ifNull(new InstructionBuilderCallback()
+                    builder.dupe(0).conditional(Condition.NULL, new InstructionBuilderCallback()
                     {
                         public void doBuild(InstructionBuilder builder)
                         {
@@ -1527,7 +1540,7 @@ public class PropertyConduitSourceImpl i
                                     builder.returnDefaultValue();
                             }
                         }
-                    }, null);
+                    });
 
                     if (info.isCastRequired())
                     {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java?rev=1091947&r1=1091946&r2=1091947&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java Wed Apr 13 22:23:19 2011
@@ -23,6 +23,8 @@ import org.apache.tapestry5.ioc.services
 import org.apache.tapestry5.ioc.services.PropertyAdapter;
 import org.apache.tapestry5.ioc.services.PropertyShadowBuilder;
 import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.Condition;
+import org.apache.tapestry5.plastic.ConditionCallback;
 import org.apache.tapestry5.plastic.InstructionBuilder;
 import org.apache.tapestry5.plastic.InstructionBuilderCallback;
 import org.apache.tapestry5.plastic.MethodDescription;
@@ -84,9 +86,7 @@ public class PropertyShadowBuilderImpl i
 
                         // Now add the null check.
 
-                        builder.dupe(0);
-
-                        builder.ifNull(new InstructionBuilderCallback()
+                        builder.dupe(0).conditional(Condition.NULL, new InstructionBuilderCallback()
                         {
                             public void doBuild(InstructionBuilder builder)
                             {
@@ -96,7 +96,7 @@ public class PropertyShadowBuilderImpl i
                                                 "Unable to delegate method invocation to property '%s' of %s, because the property is null.",
                                                 propertyName, source));
                             }
-                        }, null);
+                        });
 
                         builder.returnResult();
                     }