changeset 13556:44288fe54352

Ruby: fix some ?break? semantics.
author Chris Seaton <chris.seaton@oracle.com>
date Wed, 08 Jan 2014 17:42:10 +0000
parents f70c894ae874
children b63357fbe40c
files graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java
diffstat 10 files changed, 172 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java	Wed Jan 08 17:42:10 2014 +0000
@@ -13,6 +13,7 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
 import com.oracle.truffle.ruby.runtime.*;
 import com.oracle.truffle.ruby.runtime.control.*;
 
@@ -28,7 +29,11 @@
 
     @Override
     public Object execute(VirtualFrame frame) {
-        throw new BreakException(child.execute(frame));
+        if (child instanceof NilNode) {
+            throw BreakException.NIL;
+        } else {
+            throw new BreakException(child.execute(frame));
+        }
     }
 
 }
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java	Wed Jan 08 17:42:10 2014 +0000
@@ -13,19 +13,27 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
 import com.oracle.truffle.ruby.runtime.*;
 import com.oracle.truffle.ruby.runtime.control.*;
 
 @NodeInfo(shortName = "next")
 public class NextNode extends RubyNode {
 
-    public NextNode(RubyContext context, SourceSection sourceSection) {
+    @Child private RubyNode child;
+
+    public NextNode(RubyContext context, SourceSection sourceSection, RubyNode child) {
         super(context, sourceSection);
+
+        this.child = adoptChild(child);
     }
 
     @Override
     public Object execute(VirtualFrame frame) {
-        throw new NextException();
+        if (child instanceof NilNode) {
+            throw NextException.NIL;
+        } else {
+            throw new NextException(child.execute(frame));
+        }
     }
-
 }
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java	Wed Jan 08 17:42:10 2014 +0000
@@ -16,6 +16,7 @@
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.ruby.runtime.*;
 import com.oracle.truffle.ruby.runtime.control.*;
 import com.oracle.truffle.ruby.runtime.core.*;
@@ -457,6 +458,10 @@
     @CoreMethod(names = "each", needsBlock = true, maxArgs = 0)
     public abstract static class EachNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public EachNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -466,12 +471,21 @@
         }
 
         @Specialization
-        public NilPlaceholder each(VirtualFrame frame, RubyArray array, RubyProc block) {
-            for (int n = 0; n < array.size(); n++) {
-                try {
-                    yield(frame, block, array.get(n));
-                } catch (BreakException e) {
-                    break;
+        public Object each(VirtualFrame frame, RubyArray array, RubyProc block) {
+            outer: for (int n = 0; n < array.size(); n++) {
+                while (true) {
+                    try {
+                        yield(frame, block, array.get(n));
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
                 }
             }
 
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java	Wed Jan 08 17:42:10 2014 +0000
@@ -14,7 +14,9 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
 import com.oracle.truffle.ruby.runtime.core.*;
 import com.oracle.truffle.ruby.runtime.core.array.*;
 
@@ -602,6 +604,10 @@
     @CoreMethod(names = "times", needsBlock = true, maxArgs = 0)
     public abstract static class TimesNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public TimesNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -611,9 +617,22 @@
         }
 
         @Specialization
-        public BigInteger times(VirtualFrame frame, BigInteger n, RubyProc block) {
-            for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) {
-                yield(frame, block, i);
+        public Object times(VirtualFrame frame, BigInteger n, RubyProc block) {
+            outer: for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) {
+                while (true) {
+                    try {
+                        yield(frame, block, i);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return n;
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java	Wed Jan 08 17:42:10 2014 +0000
@@ -14,7 +14,9 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
 import com.oracle.truffle.ruby.runtime.core.*;
 import com.oracle.truffle.ruby.runtime.core.array.*;
 
@@ -755,6 +757,10 @@
     @CoreMethod(names = "times", needsBlock = true, maxArgs = 0)
     public abstract static class TimesNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public TimesNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -764,9 +770,22 @@
         }
 
         @Specialization
-        public int times(VirtualFrame frame, int n, RubyProc block) {
-            for (int i = 0; i < n; i++) {
-                yield(frame, block, i);
+        public Object times(VirtualFrame frame, int n, RubyProc block) {
+            outer: for (int i = 0; i < n; i++) {
+                while (true) {
+                    try {
+                        yield(frame, block, i);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return n;
@@ -831,6 +850,10 @@
     @CoreMethod(names = "upto", needsBlock = true, minArgs = 1, maxArgs = 1)
     public abstract static class UpToNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public UpToNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -840,9 +863,22 @@
         }
 
         @Specialization
-        public NilPlaceholder upto(VirtualFrame frame, int from, int to, RubyProc block) {
-            for (int i = from; i <= to; i++) {
-                yield(frame, block, i);
+        public Object upto(VirtualFrame frame, int from, int to, RubyProc block) {
+            outer: for (int i = from; i <= to; i++) {
+                while (true) {
+                    try {
+                        yield(frame, block, i);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return NilPlaceholder.INSTANCE;
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java	Wed Jan 08 17:42:10 2014 +0000
@@ -12,8 +12,10 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.ruby.nodes.call.*;
 import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
 import com.oracle.truffle.ruby.runtime.core.*;
 import com.oracle.truffle.ruby.runtime.core.array.*;
 import com.oracle.truffle.ruby.runtime.core.range.*;
@@ -50,6 +52,10 @@
     @CoreMethod(names = "each", needsBlock = true, maxArgs = 0)
     public abstract static class EachNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public EachNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -59,9 +65,22 @@
         }
 
         @Specialization
-        public FixnumRange each(VirtualFrame frame, FixnumRange range, RubyProc block) {
-            for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) {
-                yield(frame, block, n);
+        public Object each(VirtualFrame frame, FixnumRange range, RubyProc block) {
+            outer: for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) {
+                while (true) {
+                    try {
+                        yield(frame, block, n);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return range;
@@ -182,6 +201,10 @@
     @CoreMethod(names = "step", needsBlock = true, minArgs = 1, maxArgs = 1)
     public abstract static class StepNode extends YieldingCoreMethodNode {
 
+        private final BranchProfile breakProfile = new BranchProfile();
+        private final BranchProfile nextProfile = new BranchProfile();
+        private final BranchProfile redoProfile = new BranchProfile();
+
         public StepNode(RubyContext context, SourceSection sourceSection) {
             super(context, sourceSection);
         }
@@ -191,9 +214,22 @@
         }
 
         @Specialization
-        public FixnumRange step(VirtualFrame frame, FixnumRange range, int step, RubyProc block) {
-            for (int n = range.getBegin(); n < range.getExclusiveEnd(); n += step) {
-                yield(frame, block, n);
+        public Object step(VirtualFrame frame, FixnumRange range, int step, RubyProc block) {
+            outer: for (int n = range.getBegin(); n < range.getExclusiveEnd(); n += step) {
+                while (true) {
+                    try {
+                        yield(frame, block, n);
+                        continue outer;
+                    } catch (BreakException e) {
+                        breakProfile.enter();
+                        return e.getResult();
+                    } catch (NextException e) {
+                        nextProfile.enter();
+                        continue outer;
+                    } catch (RedoException e) {
+                        redoProfile.enter();
+                    }
+                }
             }
 
             return range;
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java	Wed Jan 08 17:42:10 2014 +0000
@@ -36,8 +36,7 @@
             return body.execute(frame);
         } catch (NextException e) {
             nextProfile.enter();
-            return NilPlaceholder.INSTANCE;
+            return e.getResult();
         }
     }
-
 }
--- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java	Wed Jan 08 17:42:10 2014 +0000
@@ -1484,7 +1484,17 @@
 
     @Override
     public Object visitNextNode(org.jrubyparser.ast.NextNode node) {
-        return new NextNode(context, translate(node.getPosition()));
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode resultNode;
+
+        if (node.getValueNode() == null) {
+            resultNode = new NilNode(context, sourceSection);
+        } else {
+            resultNode = (RubyNode) node.getValueNode().accept(this);
+        }
+
+        return new NextNode(context, sourceSection, resultNode);
     }
 
     @Override
--- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java	Wed Jan 08 17:42:10 2014 +0000
@@ -17,6 +17,8 @@
  */
 public final class BreakException extends ControlFlowException {
 
+    public static final BreakException NIL = new BreakException(NilPlaceholder.INSTANCE);
+
     private final Object result;
 
     public BreakException(Object result) {
--- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java	Wed Jan 08 17:10:18 2014 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java	Wed Jan 08 17:42:10 2014 +0000
@@ -10,12 +10,27 @@
 package com.oracle.truffle.ruby.runtime.control;
 
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
 
 /**
  * Controls moving to the next iteration in a control structure or method.
  */
 public final class NextException extends ControlFlowException {
 
+    public static final NextException NIL = new NextException(NilPlaceholder.INSTANCE);
+
+    private final Object result;
+
+    public NextException(Object result) {
+        assert RubyContext.shouldObjectBeVisible(result);
+
+        this.result = result;
+    }
+
+    public Object getResult() {
+        return result;
+    }
+
     private static final long serialVersionUID = -302759969186731457L;
 
 }