# HG changeset patch # User Christian Humer # Date 1426012106 -3600 # Node ID e8d2f3f95dcdab0021c5d3eac5c1fa1cb544a854 # Parent d03352ba2efb66da57267109820f21a1ec605f7c Truffle-DSL: implemented duplication check for specializations with @Cached to avoid duplicates for multithreaded AST execution. diff -r d03352ba2efb -r e8d2f3f95dcd graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MergeSpecializationsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MergeSpecializationsTest.java Tue Mar 10 13:47:46 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MergeSpecializationsTest.java Tue Mar 10 19:28:26 2015 +0100 @@ -40,7 +40,7 @@ public class MergeSpecializationsTest { - private static final int THREADS = 8; + private static final int THREADS = 50; @NodeChild @SuppressWarnings("unused") @@ -92,19 +92,16 @@ multithreadedMerge(TestNodeFactory.getInstance(), new Executions(1.0, 1L << 32, 1), 3, 2, 1); } - @Ignore @Test public void testMultithreadedMergeCachedInOrder() { multithreadedMerge(TestCachedNodeFactory.getInstance(), new Executions(1, 1L << 32, 1.0), 1, 2, 3); } - @Ignore @Test public void testMultithreadedMergeCachedTwoEntries() { multithreadedMerge(TestCachedNodeFactory.getInstance(), new Executions(1, 2, 1.0), 1, 1, 3); } - @Ignore @Test public void testMultithreadedMergeCachedThreeEntries() { multithreadedMerge(TestCachedNodeFactory.getInstance(), new Executions(1, 2, 3), 1, 1, 1); diff -r d03352ba2efb -r e8d2f3f95dcd graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/RewriteEvent.java --- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/RewriteEvent.java Tue Mar 10 13:47:46 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.dsl.internal; - -import com.oracle.truffle.api.nodes.*; - -/** - * Lazy rewrite event that implements {@link CharSequence} to be provided as message in - * {@link Node#replace(Node, CharSequence)}. - */ -abstract class RewriteEvent implements CharSequence { - - private final Node source; - private final String reason; - private String message; - - private RewriteEvent(Node source, String reason) { - this.source = source; - this.reason = reason; - } - - public int length() { - return getMessage().length(); - } - - public char charAt(int index) { - return getMessage().charAt(index); - } - - public CharSequence subSequence(int start, int end) { - return getMessage().subSequence(start, end); - } - - @Override - public String toString() { - return getMessage(); - } - - private String getMessage() { - if (message == null) { - message = createMessage(); - } - return message; - } - - private String createMessage() { - StringBuilder builder = new StringBuilder(); - builder.append(source); - builder.append(" "); - builder.append(reason); - Object[] values = getValues(); - if (values.length > 0) { - builder.append(" with parameters ("); - String sep = ""; - for (Object value : values) { - builder.append(sep); - if (value == null) { - builder.append("null"); - } else { - builder.append(value).append(" (").append(value.getClass().getSimpleName()).append(")"); - } - - sep = ", "; - } - builder.append(")"); - } - return builder.toString(); - } - - public abstract Object[] getValues(); - - static final class RewriteEvent0 extends RewriteEvent { - - private static final Object[] EMPTY = new Object[0]; - - public RewriteEvent0(Node source, String reason) { - super(source, reason); - } - - @Override - public Object[] getValues() { - return EMPTY; - } - - } - - static final class RewriteEvent1 extends RewriteEvent { - - private final Object o1; - - public RewriteEvent1(Node source, String reason, Object o1) { - super(source, reason); - this.o1 = o1; - } - - @Override - public Object[] getValues() { - return new Object[]{o1}; - } - - } - - static final class RewriteEvent2 extends RewriteEvent { - - private final Object o1; - private final Object o2; - - public RewriteEvent2(Node source, String reason, Object o1, Object o2) { - super(source, reason); - this.o1 = o1; - this.o2 = o2; - } - - @Override - public Object[] getValues() { - return new Object[]{o1, o2}; - } - - } - - static final class RewriteEvent3 extends RewriteEvent { - - private final Object o1; - private final Object o2; - private final Object o3; - - public RewriteEvent3(Node source, String reason, Object o1, Object o2, Object o3) { - super(source, reason); - this.o1 = o1; - this.o2 = o2; - this.o3 = o3; - } - - @Override - public Object[] getValues() { - return new Object[]{o1, o2, o3}; - } - - } - - static final class RewriteEvent4 extends RewriteEvent { - - private final Object o1; - private final Object o2; - private final Object o3; - private final Object o4; - - public RewriteEvent4(Node source, String reason, Object o1, Object o2, Object o3, Object o4) { - super(source, reason); - this.o1 = o1; - this.o2 = o2; - this.o3 = o3; - this.o4 = o4; - } - - @Override - public Object[] getValues() { - return new Object[]{o1, o2, o3, o4}; - } - - } - - static final class RewriteEventN extends RewriteEvent { - - private final Object[] args; - - public RewriteEventN(Node source, String reason, Object... args) { - super(source, reason); - this.args = args; - } - - @Override - public Object[] getValues() { - return args; - } - - } -} diff -r d03352ba2efb -r e8d2f3f95dcd graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SlowPathEvent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SlowPathEvent.java Tue Mar 10 19:28:26 2015 +0100 @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.internal; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Lazy rewrite event that implements {@link CharSequence} to be provided as message in + * {@link Node#replace(Node, CharSequence)}. + */ +abstract class SlowPathEvent implements CharSequence { + + protected final SpecializationNode source; + protected final String reason; + protected final Frame frame; + private String message; + + SlowPathEvent(SpecializationNode source, String reason, Frame frame) { + this.source = source; + this.reason = reason; + this.frame = frame; + } + + public int length() { + return getMessage().length(); + } + + public char charAt(int index) { + return getMessage().charAt(index); + } + + public CharSequence subSequence(int start, int end) { + return getMessage().subSequence(start, end); + } + + @Override + public String toString() { + return getMessage(); + } + + private String getMessage() { + if (message == null) { + message = createMessage(); + } + return message; + } + + private String createMessage() { + StringBuilder builder = new StringBuilder(); + builder.append(source); + builder.append(" "); + builder.append(reason); + Object[] values = getValues(); + if (values.length > 0) { + builder.append(" with parameters ("); + String sep = ""; + for (Object value : values) { + builder.append(sep); + if (value == null) { + builder.append("null"); + } else { + builder.append(value).append(" (").append(value.getClass().getSimpleName()).append(")"); + } + + sep = ", "; + } + builder.append(")"); + } + return builder.toString(); + } + + public abstract Object[] getValues(); + + static class SlowPathEvent0 extends SlowPathEvent { + + private static final Object[] EMPTY = new Object[0]; + + public SlowPathEvent0(SpecializationNode source, String reason, Frame frame) { + super(source, reason, frame); + } + + @Override + public final Object[] getValues() { + return EMPTY; + } + + } + + static class SlowPathEvent1 extends SlowPathEvent { + + protected final Object o1; + + public SlowPathEvent1(SpecializationNode source, String reason, Frame frame, Object o1) { + super(source, reason, frame); + this.o1 = o1; + } + + @Override + public final Object[] getValues() { + return new Object[]{o1}; + } + + } + + static class SlowPathEvent2 extends SlowPathEvent { + + protected final Object o1; + protected final Object o2; + + public SlowPathEvent2(SpecializationNode source, String reason, Frame frame, Object o1, Object o2) { + super(source, reason, frame); + this.o1 = o1; + this.o2 = o2; + } + + @Override + public final Object[] getValues() { + return new Object[]{o1, o2}; + } + + } + + static class SlowPathEvent3 extends SlowPathEvent { + + protected final Object o1; + protected final Object o2; + protected final Object o3; + + public SlowPathEvent3(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, Object o3) { + super(source, reason, frame); + this.o1 = o1; + this.o2 = o2; + this.o3 = o3; + } + + @Override + public final Object[] getValues() { + return new Object[]{o1, o2, o3}; + } + + } + + static class SlowPathEvent4 extends SlowPathEvent { + + protected final Object o1; + protected final Object o2; + protected final Object o3; + protected final Object o4; + + public SlowPathEvent4(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, Object o3, Object o4) { + super(source, reason, frame); + this.o1 = o1; + this.o2 = o2; + this.o3 = o3; + this.o4 = o4; + } + + @Override + public final Object[] getValues() { + return new Object[]{o1, o2, o3, o4}; + } + + } + + static class SlowPathEvent5 extends SlowPathEvent { + + protected final Object o1; + protected final Object o2; + protected final Object o3; + protected final Object o4; + protected final Object o5; + + public SlowPathEvent5(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { + super(source, reason, frame); + this.o1 = o1; + this.o2 = o2; + this.o3 = o3; + this.o4 = o4; + this.o5 = o5; + } + + @Override + public final Object[] getValues() { + return new Object[]{o1, o2, o3, o4, o5}; + } + + } + + static class SlowPathEventN extends SlowPathEvent { + + protected final Object[] args; + + public SlowPathEventN(SpecializationNode source, String reason, Frame frame, Object... args) { + super(source, reason, frame); + this.args = args; + } + + @Override + public final Object[] getValues() { + return args; + } + + } +} diff -r d03352ba2efb -r e8d2f3f95dcd graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java --- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java Tue Mar 10 13:47:46 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java Tue Mar 10 19:28:26 2015 +0100 @@ -30,12 +30,13 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent0; -import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent1; -import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent2; -import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent3; -import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent4; -import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEventN; +import com.oracle.truffle.api.dsl.internal.SlowPathEvent.SlowPathEvent0; +import com.oracle.truffle.api.dsl.internal.SlowPathEvent.SlowPathEvent1; +import com.oracle.truffle.api.dsl.internal.SlowPathEvent.SlowPathEvent2; +import com.oracle.truffle.api.dsl.internal.SlowPathEvent.SlowPathEvent3; +import com.oracle.truffle.api.dsl.internal.SlowPathEvent.SlowPathEvent4; +import com.oracle.truffle.api.dsl.internal.SlowPathEvent.SlowPathEvent5; +import com.oracle.truffle.api.dsl.internal.SlowPathEvent.SlowPathEventN; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.NodeUtil.NodeClass; @@ -44,13 +45,13 @@ /** * Internal implementation dependent base class for generated specialized nodes. */ +@NodeInfo(cost = NodeCost.NONE) @SuppressWarnings("unused") -@NodeInfo(cost = NodeCost.NONE) public abstract class SpecializationNode extends Node { @Child protected SpecializationNode next; - private final int index; + final int index; public SpecializationNode() { this(-1); @@ -92,10 +93,9 @@ } } - protected final SpecializationNode polymorphicMerge(SpecializationNode newNode) { - SpecializationNode merged = next.merge(newNode); - if (merged == newNode && !isSame(newNode) && count() <= 2) { - return removeSame(new RewriteEvent0(findRoot(), "merged polymorphic to monomorphic")); + protected final SpecializationNode polymorphicMerge(SpecializationNode newNode, SpecializationNode merged) { + if (merged == newNode && count() <= 2) { + return removeSame(new SlowPathEvent0(this, "merged polymorphic to monomorphic", null)); } return merged; } @@ -114,15 +114,85 @@ protected abstract Node[] getSuppliedChildren(); - protected SpecializationNode merge(SpecializationNode newNode) { - if (this.isSame(newNode)) { + protected SpecializationNode merge(SpecializationNode newNode, Frame frame) { + if (isIdentical(newNode, frame)) { + return this; + } + return next != null ? next.merge(newNode, frame) : newNode; + } + + protected SpecializationNode merge(SpecializationNode newNode, Frame frame, Object o1) { + if (isIdentical(newNode, frame, o1)) { + return this; + } + return next != null ? next.merge(newNode, frame, o1) : newNode; + } + + protected SpecializationNode merge(SpecializationNode newNode, Frame frame, Object o1, Object o2) { + if (isIdentical(newNode, frame, o1, o2)) { + return this; + } + return next != null ? next.merge(newNode, frame, o1, o2) : newNode; + } + + protected SpecializationNode merge(SpecializationNode newNode, Frame frame, Object o1, Object o2, Object o3) { + if (isIdentical(newNode, frame, o1, o2, o3)) { + return this; + } + return next != null ? next.merge(newNode, frame, o1, o2, o3) : newNode; + } + + protected SpecializationNode merge(SpecializationNode newNode, Frame frame, Object o1, Object o2, Object o3, Object o4) { + if (isIdentical(newNode, frame, o1, o2, o3, o4)) { + return this; + } + return next != null ? next.merge(newNode, frame, o1, o2, o3, o4) : newNode; + } + + protected SpecializationNode merge(SpecializationNode newNode, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { + if (isIdentical(newNode, frame, o1, o2, o3, o4, o5)) { return this; } - return next != null ? next.merge(newNode) : newNode; + return next != null ? next.merge(newNode, frame, o1, o2, o3, o4, o5) : newNode; + } + + protected SpecializationNode merge(SpecializationNode newNode, Frame frame, Object... args) { + if (isIdentical(newNode, frame, args)) { + return this; + } + return next != null ? next.merge(newNode, frame, args) : newNode; + } + + protected boolean isSame(SpecializationNode other) { + return getClass() == other.getClass(); + } + + protected boolean isIdentical(SpecializationNode newNode, Frame frame) { + return isSame(newNode); } - protected SpecializationNode mergeNoSame(SpecializationNode newNode) { - return next != null ? next.merge(newNode) : newNode; + protected boolean isIdentical(SpecializationNode newNode, Frame frame, Object o1) { + return isSame(newNode); + } + + protected boolean isIdentical(SpecializationNode newNode, Frame frame, Object o1, Object o2) { + return isSame(newNode); + } + + protected boolean isIdentical(SpecializationNode newNode, Frame frame, Object o1, Object o2, Object o3) { + return isSame(newNode); + } + + protected boolean isIdentical(SpecializationNode newNode, Frame frame, Object o1, Object o2, Object o3, Object o4) { + return isSame(newNode); + } + + protected boolean isIdentical(SpecializationNode newNode, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { + return isSame(newNode); + } + + protected boolean isIdentical(SpecializationNode newNode, Frame frame, Object... args) { + return isSame(newNode); } protected final int countSame(SpecializationNode node) { @@ -150,10 +220,6 @@ return index; } - protected boolean isSame(SpecializationNode other) { - return getClass() == other.getClass(); - } - private int count() { return next != null ? next.count() + 1 : 1; } @@ -226,8 +292,12 @@ return findStart().getParent(); } - private SpecializationNode removeSameImpl(SpecializationNode toRemove, CharSequence reason) { - SpecializationNode start = findStart(); + private SpecializedNode findSpecializedNode() { + return (SpecializedNode) findEnd().findStart().getParent(); + } + + private static SpecializationNode removeSameImpl(SpecializationNode toRemove, CharSequence reason) { + SpecializationNode start = toRemove.findStart(); SpecializationNode current = start; while (current != null) { if (current.isSame(toRemove)) { @@ -238,7 +308,7 @@ } current = current.next; } - return findEnd().findStart(); + return toRemove.findEnd().findStart(); } public Object acceptAndExecute(Frame frame) { @@ -314,7 +384,7 @@ if (nextSpecialization == null) { return unsupported(frame); } - return insertSpecialization(nextSpecialization, new RewriteEvent0(findRoot(), "inserted new specialization")).acceptAndExecute(frame); + return atomic(new InsertionEvent0(this, "insert new specialization", frame, nextSpecialization)).acceptAndExecute(frame); } protected final Object uninitialized(Frame frame, Object o1) { @@ -326,7 +396,7 @@ if (nextSpecialization == null) { return unsupported(frame, o1); } - return insertSpecialization(nextSpecialization, new RewriteEvent1(findRoot(), "inserted new specialization", o1)).acceptAndExecute(frame, o1); + return atomic(new InsertionEvent1(this, "insert new specialization", frame, o1, nextSpecialization)).acceptAndExecute(frame, o1); } protected final Object uninitialized(Frame frame, Object o1, Object o2) { @@ -338,7 +408,7 @@ if (nextSpecialization == null) { return unsupported(frame, o1, o2); } - return insertSpecialization(nextSpecialization, new RewriteEvent2(findRoot(), "inserted new specialization", o1, o2)).acceptAndExecute(frame, o1, o2); + return atomic(new InsertionEvent2(this, "insert new specialization", frame, o1, o2, nextSpecialization)).acceptAndExecute(frame, o1, o2); } protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3) { @@ -350,7 +420,7 @@ if (nextSpecialization == null) { return unsupported(frame, o1, o2, o3); } - return insertSpecialization(nextSpecialization, new RewriteEvent3(findRoot(), "inserted new specialization", o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3); + return atomic(new InsertionEvent3(this, "insert new specialization", frame, o1, o2, o3, nextSpecialization)).acceptAndExecute(frame, o1, o2, o3); } protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3, Object o4) { @@ -362,7 +432,7 @@ if (nextSpecialization == null) { return unsupported(frame, o1, o2, o3, o4); } - return insertSpecialization(nextSpecialization, new RewriteEvent4(findRoot(), "inserts new specialization", o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4); + return atomic(new InsertionEvent4(this, "insert new specialization", frame, o1, o2, o3, o4, nextSpecialization)).acceptAndExecute(frame, o1, o2, o3, o4); } protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { @@ -374,7 +444,7 @@ if (nextSpecialization == null) { unsupported(frame, o1, o2, o3, o4, o5); } - return insertSpecialization(nextSpecialization, new RewriteEventN(findRoot(), "inserts new specialization", o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5); + return atomic(new InsertionEvent5(this, "insert new specialization", frame, o1, o2, o3, o4, o5, nextSpecialization)).acceptAndExecute(frame, o1, o2, o3, o4, o5); } protected final Object uninitialized(Frame frame, Object... args) { @@ -386,39 +456,35 @@ if (nextSpecialization == null) { unsupported(frame, args); } - return insertSpecialization(nextSpecialization, new RewriteEventN(findRoot(), "inserts new specialization", args)).acceptAndExecute(frame, args); - } - - private boolean needsPolymorphic() { - return findStart().count() == 2; + return atomic(new InsertionEventN(this, "insert new specialization", frame, args, nextSpecialization)).acceptAndExecute(frame, args); } protected final Object remove(String reason, Frame frame) { - return removeSame(new RewriteEvent0(findRoot(), reason)).acceptAndExecute(frame); + return atomic(new RemoveEvent0(this, reason, frame)).acceptAndExecute(frame); } protected final Object remove(String reason, Frame frame, Object o1) { - return removeSame(new RewriteEvent1(findRoot(), reason, o1)).acceptAndExecute(frame, o1); + return atomic(new RemoveEvent1(this, reason, frame, o1)).acceptAndExecute(frame, o1); } protected final Object remove(String reason, Frame frame, Object o1, Object o2) { - return removeSame(new RewriteEvent2(findRoot(), reason, o1, o2)).acceptAndExecute(frame, o1, o2); + return atomic(new RemoveEvent2(this, reason, frame, o1, o2)).acceptAndExecute(frame, o1, o2); } protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3) { - return removeSame(new RewriteEvent3(findRoot(), reason, o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3); + return atomic(new RemoveEvent3(this, reason, frame, o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3); } protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3, Object o4) { - return removeSame(new RewriteEvent4(findRoot(), reason, o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4); + return atomic(new RemoveEvent4(this, reason, frame, o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4); } protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { - return removeSame(new RewriteEventN(findRoot(), reason, o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5); + return atomic(new RemoveEvent5(this, reason, frame, o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5); } protected final Object remove(String reason, Frame frame, Object... args) { - return removeSame(new RewriteEventN(findRoot(), reason, args)).acceptAndExecute(frame, args); + return atomic(new RemoveEventN(this, reason, frame, args)).acceptAndExecute(frame, args); } protected Object unsupported(Frame frame) { @@ -449,49 +515,24 @@ throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), args); } - private SpecializationNode insertSpecialization(final SpecializationNode generated, final CharSequence message) { - return atomic(new Callable() { - public SpecializationNode call() { - return insert(generated, message); - } - }); - } - - private SpecializationNode insert(final SpecializationNode generated, CharSequence message) { - SpecializationNode start = findStart(); - if (start == this) { - // fast path for first insert - return insertBefore(this, generated, message); - } else { - return slowSortedInsert(start, generated, message); - } - } - - private static SpecializationNode slowSortedInsert(SpecializationNode start, final SpecializationNode generated, final CharSequence message) { - final SpecializationNode merged = start.merge(generated); + static SpecializationNode insertSorted(SpecializationNode start, final SpecializationNode generated, final CharSequence message, final SpecializationNode merged) { if (merged == generated) { // new node if (start.count() == 2) { - insertBefore(start, start.createPolymorphic(), "insert polymorphic"); + insertAt(start, start.createPolymorphic(), "insert polymorphic"); } - SpecializationNode insertBefore = findInsertBeforeNode(generated.index, start); - return insertBefore(insertBefore, generated, message); + SpecializationNode current = start; + while (current != null && current.index < generated.index) { + current = current.next; + } + return insertAt(current, generated, message); } else { // existing node - merged.replace(merged, new RewriteEvent0(merged.findRoot(), "merged specialization")); return start; } } - private static SpecializationNode findInsertBeforeNode(int generatedIndex, SpecializationNode start) { - SpecializationNode current = start; - while (current != null && current.index < generatedIndex) { - current = current.next; - } - return current; - } - - private static SpecializationNode insertBefore(SpecializationNode node, SpecializationNode insertBefore, CharSequence message) { + static SpecializationNode insertAt(SpecializationNode node, SpecializationNode insertBefore, CharSequence message) { insertBefore.next = node; return node.replace(insertBefore, message); } @@ -545,7 +586,6 @@ b.append(")"); } - // utilities for generated code protected static void check(Assumption assumption) throws InvalidAssumptionException { if (assumption != null) { assumption.check(); @@ -580,4 +620,226 @@ return true; } + private static final class InsertionEvent0 extends SlowPathEvent0 implements Callable { + + private final SpecializationNode next; + + public InsertionEvent0(SpecializationNode source, String reason, Frame frame, SpecializationNode next) { + super(source, reason, frame); + this.next = next; + } + + public SpecializationNode call() throws Exception { + SpecializationNode start = source.findStart(); + if (start.index == Integer.MAX_VALUE) { + return insertAt(start, next, this); + } else { + return insertSorted(start, next, this, start.merge(next, frame)); + } + } + + } + + private static final class InsertionEvent1 extends SlowPathEvent1 implements Callable { + + private final SpecializationNode next; + + public InsertionEvent1(SpecializationNode source, String reason, Frame frame, Object o1, SpecializationNode next) { + super(source, reason, frame, o1); + this.next = next; + } + + public SpecializationNode call() throws Exception { + SpecializationNode start = source.findStart(); + if (start.index == Integer.MAX_VALUE) { + return insertAt(start, next, this); + } else { + return insertSorted(start, next, this, start.merge(next, frame, o1)); + } + } + + } + + private static final class InsertionEvent2 extends SlowPathEvent2 implements Callable { + + private final SpecializationNode next; + + public InsertionEvent2(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, SpecializationNode next) { + super(source, reason, frame, o1, o2); + this.next = next; + } + + public SpecializationNode call() throws Exception { + SpecializationNode start = source.findStart(); + if (start.index == Integer.MAX_VALUE) { + return insertAt(start, next, this); + } else { + return insertSorted(start, next, this, start.merge(next, frame, o1, o2)); + } + } + + } + + private static final class InsertionEvent3 extends SlowPathEvent3 implements Callable { + + private final SpecializationNode next; + + public InsertionEvent3(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, Object o3, SpecializationNode next) { + super(source, reason, frame, o1, o2, o3); + this.next = next; + } + + public SpecializationNode call() throws Exception { + SpecializationNode start = source.findStart(); + if (start.index == Integer.MAX_VALUE) { + return insertAt(start, next, this); + } else { + return insertSorted(start, next, this, start.merge(next, frame, o1, o2, o3)); + } + } + + } + + private static final class InsertionEvent4 extends SlowPathEvent4 implements Callable { + + private final SpecializationNode next; + + public InsertionEvent4(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, Object o3, Object o4, SpecializationNode next) { + super(source, reason, frame, o1, o2, o3, o4); + this.next = next; + } + + public SpecializationNode call() throws Exception { + SpecializationNode start = source.findStart(); + if (start.index == Integer.MAX_VALUE) { + return insertAt(start, next, this); + } else { + return insertSorted(start, next, this, start.merge(next, frame, o1, o2, o3, o4)); + } + } + + } + + private static final class InsertionEvent5 extends SlowPathEvent5 implements Callable { + + private final SpecializationNode next; + + public InsertionEvent5(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5, SpecializationNode next) { + super(source, reason, frame, o1, o2, o3, o4, o5); + this.next = next; + } + + public SpecializationNode call() throws Exception { + SpecializationNode start = source.findStart(); + if (start.index == Integer.MAX_VALUE) { + return insertAt(start, next, this); + } else { + return insertSorted(start, next, this, start.merge(next, frame, o1, o2, o3, o4, o5)); + } + } + + } + + private static final class InsertionEventN extends SlowPathEventN implements Callable { + + private final SpecializationNode next; + + public InsertionEventN(SpecializationNode source, String reason, Frame frame, Object[] args, SpecializationNode next) { + super(source, reason, frame, args); + this.next = next; + } + + public SpecializationNode call() throws Exception { + SpecializationNode start = source.findStart(); + if (start.index == Integer.MAX_VALUE) { + return insertAt(start, next, this); + } else { + return insertSorted(start, next, this, start.merge(next, frame, args)); + } + } + } + + private static final class RemoveEvent0 extends SlowPathEvent0 implements Callable { + + public RemoveEvent0(SpecializationNode source, String reason, Frame frame) { + super(source, reason, frame); + } + + public SpecializationNode call() throws Exception { + return removeSameImpl(source, this); + } + + } + + private static final class RemoveEvent1 extends SlowPathEvent1 implements Callable { + + public RemoveEvent1(SpecializationNode source, String reason, Frame frame, Object o1) { + super(source, reason, frame, o1); + } + + public SpecializationNode call() throws Exception { + return removeSameImpl(source, this); + } + + } + + private static final class RemoveEvent2 extends SlowPathEvent2 implements Callable { + + public RemoveEvent2(SpecializationNode source, String reason, Frame frame, Object o1, Object o2) { + super(source, reason, frame, o1, o2); + } + + public SpecializationNode call() throws Exception { + return removeSameImpl(source, this); + } + + } + + private static final class RemoveEvent3 extends SlowPathEvent3 implements Callable { + + public RemoveEvent3(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, Object o3) { + super(source, reason, frame, o1, o2, o3); + } + + public SpecializationNode call() throws Exception { + return removeSameImpl(source, this); + } + + } + + private static final class RemoveEvent4 extends SlowPathEvent4 implements Callable { + + public RemoveEvent4(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, Object o3, Object o4) { + super(source, reason, frame, o1, o2, o3, o4); + } + + public SpecializationNode call() throws Exception { + return removeSameImpl(source, this); + } + + } + + private static final class RemoveEvent5 extends SlowPathEvent5 implements Callable { + + public RemoveEvent5(SpecializationNode source, String reason, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { + super(source, reason, frame, o1, o2, o3, o4, o5); + } + + public SpecializationNode call() throws Exception { + return removeSameImpl(source, this); + } + + } + + private static final class RemoveEventN extends SlowPathEventN implements Callable { + + public RemoveEventN(SpecializationNode source, String reason, Frame frame, Object[] args) { + super(source, reason, frame, args); + } + + public SpecializationNode call() throws Exception { + return removeSameImpl(source, this); + } + } + } diff -r d03352ba2efb -r e8d2f3f95dcd graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Tue Mar 10 13:47:46 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Tue Mar 10 19:28:26 2015 +0100 @@ -447,6 +447,7 @@ clazz.addOptional(createSpecializationCreateMethod(specialization, constructor)); clazz.addOptional(createMergeMethod(specialization)); clazz.addOptional(createIsSameMethod(specialization)); + clazz.addOptional(createIsIdenticalMethod(specialization)); TypeData returnType = specialization.getReturnType().getTypeSystemType(); int signatureSize = specialization.getSignatureSize(); @@ -493,6 +494,36 @@ return executable; } + private Element createIsIdenticalMethod(SpecializationData specialization) { + boolean cacheBoundGuard = specialization.hasMultipleInstances(); + if (!cacheBoundGuard) { + return null; + } + + LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold); + currentLocals.loadFastPathState(specialization); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isIdentical"); + method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other")); + currentLocals.addParametersTo(method, FRAME_VALUE); + method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + final CodeTreeBuilder builder = method.createBuilder(); + + SpecializationGroup group = SpecializationGroup.create(specialization); + SpecializationBody executionFactory = new SpecializationBody(true, false) { + @Override + public CodeTree createBody(SpecializationData s, LocalContext values) { + return builder.create().returnTrue().build(); + } + }; + + builder.startIf().string("isSame(other)").end().startBlock(); + builder.tree(createGuardAndCast(group, typeSystem.getGenericTypeData(), currentLocals, executionFactory)); + builder.end(); + builder.returnFalse(); + return method; + } + private CodeExecutableElement createIsSameMethod(SpecializationData specialization) { if (!specialization.isSpecialized() || !options.implicitCastOptimization().isDuplicateTail()) { return null; @@ -532,18 +563,29 @@ } private Element createMergeMethod(SpecializationData specialization) { - boolean cacheBoundGuard = specialization.hasMultipleInstances(); - if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic() && !cacheBoundGuard) { + if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) { return null; } TypeMirror specializationNodeType = getType(SpecializationNode.class); + LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold); + CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge"); executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode")); + currentLocals.addParametersTo(executable, FRAME_VALUE); executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); CodeTreeBuilder builder = executable.createBuilder(); if (specialization.isPolymorphic()) { - builder.statement("return polymorphicMerge(newNode)"); + builder.startReturn(); + builder.startCall("polymorphicMerge"); + builder.string("newNode"); + builder.startCall("super", "merge"); + builder.string("newNode"); + currentLocals.addReferencesTo(builder, FRAME_VALUE); + builder.end(); + builder.end(); + builder.end(); + } else { boolean elseIf = false; for (SpecializationData containedSpecialization : specialization.getExcludedBy()) { @@ -554,11 +596,12 @@ builder.statement("removeSame(\"Contained by " + containedSpecialization.createReferenceName() + "\")"); builder.end(); } - if (cacheBoundGuard) { - builder.statement("return super.mergeNoSame(newNode)"); - } else { - builder.statement("return super.merge(newNode)"); - } + builder.startReturn(); + builder.startCall("super", "merge"); + builder.string("newNode"); + currentLocals.addReferencesTo(builder, FRAME_VALUE); + builder.end(); + builder.end(); } return executable; @@ -638,18 +681,15 @@ CodeTreeBuilder builder = method.createBuilder(); SpecializationGroup group = createSpecializationGroups(); - CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationExecution() { - public CodeTree createExecute(SpecializationData specialization, LocalContext values) { + CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationBody(false, false) { + @Override + public CodeTree createBody(SpecializationData specialization, LocalContext values) { CodeTypeElement generatedType = specializationClasses.get(specialization); if (generatedType == null) { throw new AssertionError("No generated type for " + specialization); } return createSlowPathExecute(specialization, values); } - - public boolean isFastPath() { - return false; - } }); builder.tree(execution); @@ -1525,14 +1565,11 @@ } else { final TypeData finalType = type; SpecializationGroup group = SpecializationGroup.create(specialization); - SpecializationExecution executionFactory = new SpecializationExecution() { - public CodeTree createExecute(SpecializationData s, LocalContext values) { + SpecializationBody executionFactory = new SpecializationBody(true, true) { + @Override + public CodeTree createBody(SpecializationData s, LocalContext values) { return createFastPathExecute(builder, finalType, s, values); } - - public boolean isFastPath() { - return true; - } }; builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory)); if (hasFallthrough(group, type, originalValues, true, null) || group.getSpecialization().isFallback()) { @@ -1621,11 +1658,11 @@ return builder.build(); } - private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationExecution execution) { + private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationBody execution) { CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); Set castGuards; - if (execution.isFastPath()) { + if (execution.needsCastedValues()) { castGuards = null; // cast all } else { castGuards = new HashSet<>(); @@ -1679,7 +1716,7 @@ builder.tree(createGuardAndCast(child, forType, currentValues.copy(), execution)); } if (specialization != null) { - builder.tree(execution.createExecute(specialization, currentValues)); + builder.tree(execution.createBody(specialization, currentValues)); } } builder.end(ifCount); @@ -2207,7 +2244,7 @@ } private CodeTree[] createTypeCheckAndLocals(SpecializationData specialization, List typeGuards, Set castGuards, LocalContext currentValues, - SpecializationExecution specializationExecution) { + SpecializationBody specializationExecution) { CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder(); CodeTreeBuilder localsBuilder = CodeTreeBuilder.createBuilder(); for (TypeGuard typeGuard : typeGuards) { @@ -2635,11 +2672,25 @@ } - private interface SpecializationExecution { - - boolean isFastPath(); - - CodeTree createExecute(SpecializationData specialization, LocalContext currentValues); + private abstract class SpecializationBody { + + private final boolean fastPath; + private final boolean needsCastedValues; + + public SpecializationBody(boolean fastPath, boolean needsCastedValues) { + this.fastPath = fastPath; + this.needsCastedValues = needsCastedValues; + } + + public final boolean isFastPath() { + return fastPath; + } + + public final boolean needsCastedValues() { + return needsCastedValues; + } + + public abstract CodeTree createBody(SpecializationData specialization, LocalContext currentValues); }