# HG changeset patch # User Doug Simon # Date 1380742829 -7200 # Node ID 673f93db4adc4d8d752a05f83610f25bf4ca30e4 # Parent 51059863da7381d5ed47b2237fa45ee55dc4daf0# Parent ef895852aeb405c4bad9c151e3722cb5643212e7 Merge. diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ArithmeticOperation.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ArithmeticOperation.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ArithmeticOperation.java Wed Oct 02 21:40:29 2013 +0200 @@ -22,9 +22,13 @@ */ package com.oracle.graal.api.code; +import com.oracle.graal.api.meta.*; + /** * An {@code ArithmeticOperation} is an operation that does primitive value arithmetic without side * effect. */ public interface ArithmeticOperation { + + Constant evalConst(Constant... inputs); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Wed Oct 02 21:40:29 2013 +0200 @@ -94,7 +94,7 @@ /** * In this case the read should be scheduled in the first block. */ - public static int testSplitSnippet1(int a) { + public static int testSplit1Snippet(int a) { try { return container.a; } finally { @@ -109,7 +109,7 @@ @Test public void testSplit1() { for (TestMode mode : TestMode.values()) { - SchedulePhase schedule = getFinalSchedule("testSplitSnippet1", mode, MemoryScheduling.OPTIMAL); + SchedulePhase schedule = getFinalSchedule("testSplit1Snippet", mode, MemoryScheduling.OPTIMAL); assertReadWithinStartBlock(schedule, true); assertReadWithinReturnBlock(schedule, false); } @@ -209,6 +209,42 @@ assertReadWithinReturnBlock(schedule, false); } + public String testStringReplaceSnippet(String input) { + return input.replace('a', 'b'); + } + + @Test + public void testStringReplace() { + getFinalSchedule("testStringReplaceSnippet", TestMode.INLINED_WITHOUT_FRAMESTATES, MemoryScheduling.OPTIMAL); + test("testStringReplaceSnippet", "acbaaa"); + } + + /** + * Here the read should float out of the loop. + */ + public static int testLoop5Snippet(int a, int b, MemoryScheduleTest obj) { + int ret = 0; + int bb = b; + for (int i = 0; i < a; i++) { + ret = obj.hash; + if (a > 10) { + bb++; + } else { + bb--; + } + ret = ret / 10; + } + return ret + bb; + } + + @Test + public void testLoop5() { + SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES, MemoryScheduling.OPTIMAL); + assertEquals(7, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + assertReadWithinReturnBlock(schedule, false); + } + /** * Here the read should float to the end (into the same block as the return). */ @@ -312,6 +348,25 @@ } /** + * Here the read should float to the end. + */ + public static int testIfRead5Snippet(int a) { + if (a < 0) { + container.a = 10; + } + return container.a; + } + + @Test + public void testIfRead5() { + SchedulePhase schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES, MemoryScheduling.OPTIMAL); + assertEquals(4, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + assertReadWithinReturnBlock(schedule, true); + assertReadAndWriteInSameBlock(schedule, false); + } + + /** * testing scheduling within a block. */ public static int testBlockScheduleSnippet() { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Oct 02 21:40:29 2013 +0200 @@ -86,7 +86,7 @@ */ @Option(help = "Pattern for method(s) to which intrinsification will not be applied. " + "See MethodFilter class for pattern syntax.") - public static final OptionValue IntrinsificationsDisabled = new OptionValue<>("Object.clone"); + public static final OptionValue IntrinsificationsDisabled = new OptionValue<>(null); // @formatter:on } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Oct 02 21:40:29 2013 +0200 @@ -246,6 +246,16 @@ public final int osThreadOffset = getUninitializedInt(); /** + * The value of JavaThread::graal_counters_offset(). + */ + public final int graalCountersThreadOffset = getUninitializedInt(); + + /** + * The length of the JavaThread::_graal_counters array. + */ + public final int graalCountersSize = getUninitializedInt(); + + /** * The value of OSThread::interrupted_offset(). */ public final int osThreadInterruptedOffset = getUninitializedInt(); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed Oct 02 21:40:29 2013 +0200 @@ -228,4 +228,9 @@ void invalidateInstalledCode(HotSpotInstalledCode hotspotInstalledCode); boolean isTypeLinked(HotSpotResolvedObjectType hotSpotResolvedObjectType); + + /** + * Collects the current values of all Graal benchmark counters, summed up over all threads. + */ + long[] collectCounters(); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed Oct 02 21:40:29 2013 +0200 @@ -190,4 +190,6 @@ * verified entry point of the given native method. */ public static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException; + + public native long[] collectCounters(); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Oct 02 21:40:29 2013 +0200 @@ -47,7 +47,6 @@ import com.oracle.graal.hotspot.phases.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; @@ -79,11 +78,6 @@ } }; - @Option(help = "") - private static final OptionValue GenericDynamicCounters = new OptionValue<>(false); - - @Option(help = "") - private static final OptionValue BenchmarkDynamicCounters = new OptionValue<>(null); //@formatter:on private final HotSpotGraalRuntime graalRuntime; @@ -234,28 +228,8 @@ t.start(); } - if (BenchmarkDynamicCounters.getValue() != null) { - String[] arguments = BenchmarkDynamicCounters.getValue().split(","); - if (arguments.length == 0 || (arguments.length % 3) != 0) { - throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: (err|out),start,end,(err|out),start,end,... (~ matches multiple digits)"); - } - for (int i = 0; i < arguments.length; i += 3) { - if (arguments[i].equals("err")) { - System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, arguments[i + 1], arguments[i + 2]))); - } else if (arguments[i].equals("out")) { - System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, arguments[i + 1], arguments[i + 2]))); - } else { - throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out"); - } - // dacapo: "err, starting =====, PASSED in " - // specjvm2008: "out,Iteration ~ (~s) begins: ,Iteration ~ (~s) ends: " - } - DynamicCounterNode.excludedClassPrefix = "Lcom/oracle/graal/"; - DynamicCounterNode.enabled = true; - } - if (GenericDynamicCounters.getValue()) { - DynamicCounterNode.enabled = true; - } + BenchmarkCounters.initialize(graalRuntime.getCompilerToVM()); + compilerStartTime = System.nanoTime(); } @@ -284,84 +258,6 @@ } } - private final class BenchmarkCountersOutputStream extends CallbackOutputStream { - - private long startTime; - private boolean waitingForEnd; - - private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) { - super(delegate, new String[]{start, end, "\n"}); - } - - @Override - protected void patternFound(int index) { - switch (index) { - case 0: - startTime = System.nanoTime(); - DynamicCounterNode.clear(); - break; - case 1: - waitingForEnd = true; - break; - case 2: - if (waitingForEnd) { - waitingForEnd = false; - DynamicCounterNode.dump(delegate, (System.nanoTime() - startTime) / 1000000000d); - } - break; - } - } - } - - public abstract static class CallbackOutputStream extends OutputStream { - - protected final PrintStream delegate; - private final byte[][] patterns; - private final int[] positions; - - public CallbackOutputStream(PrintStream delegate, String... patterns) { - this.delegate = delegate; - this.positions = new int[patterns.length]; - this.patterns = new byte[patterns.length][]; - for (int i = 0; i < patterns.length; i++) { - this.patterns[i] = patterns[i].getBytes(); - } - } - - protected abstract void patternFound(int index); - - @Override - public void write(int b) throws IOException { - try { - delegate.write(b); - for (int i = 0; i < patterns.length; i++) { - int j = positions[i]; - byte[] cs = patterns[i]; - byte patternChar = cs[j]; - if (patternChar == '~' && Character.isDigit(b)) { - // nothing to do... - } else { - if (patternChar == '~') { - patternChar = cs[++positions[i]]; - } - if (b == patternChar) { - positions[i]++; - } else { - positions[i] = 0; - } - } - if (positions[i] == patterns[i].length) { - positions[i] = 0; - patternFound(i); - } - } - } catch (RuntimeException e) { - e.printStackTrace(delegate); - throw e; - } - } - } - /** * Take action related to entering a new execution phase. * @@ -528,9 +424,7 @@ } SnippetCounter.printGroups(TTY.out().out()); - if (GenericDynamicCounters.getValue()) { - DynamicCounterNode.dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d); - } + BenchmarkCounters.shutdown(graalRuntime.getCompilerToVM(), compilerStartTime); } private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Wed Oct 02 21:40:29 2013 +0200 @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2013, 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. + * + * 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.graal.hotspot.debug; + +import java.io.*; +import java.text.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +import sun.misc.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.HeapAccess.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.debug.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.options.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * This class contains infrastructure to maintain counters based on {@link DynamicCounterNode}s. The + * infrastructure is enabled by specifying either the GenericDynamicCounters or + * BenchmarkDynamicCounters option.
+ * + * The counters are kept in a special area in the native JavaThread object, and the number of + * counters is configured in {@code thread.hpp (GRAAL_COUNTERS_SIZE)}. This file also contains an + * option to exclude compiler threads ({@code GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS}, which + * defaults to true). + * + * The subsystems that use the logging need to have their own options to turn on the counters, and + * insert DynamicCounterNodes when they're enabled. + */ +public class BenchmarkCounters { + + static class Options { + + //@formatter:off + @Option(help = "Turn on the benchmark counters, and displays the results on VM shutdown") + private static final OptionValue GenericDynamicCounters = new OptionValue<>(false); + + @Option(help = "Turn on the benchmark counters, and listen for specific patterns on System.out/System.err:%n" + + "Format: (err|out),start pattern,end pattern (~ matches multiple digits)%n" + + "Examples:%n" + + " dacapo = 'err, starting =====, PASSED in'%n" + + " specjvm2008 = 'out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends:'") + private static final OptionValue BenchmarkDynamicCounters = new OptionValue<>(null); + //@formatter:on + } + + private static final boolean DUMP_STATIC = false; + + public static String excludedClassPrefix = null; + public static boolean enabled = false; + + public static final ConcurrentHashMap indexes = new ConcurrentHashMap<>(); + public static final ArrayList groups = new ArrayList<>(); + public static long[] delta; + public static final ArrayList staticCounters = new ArrayList<>(); + + public static int getIndex(DynamicCounterNode counter) { + if (!enabled) { + throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled"); + } + String name = counter.getName(); + String group = counter.getGroup(); + name = counter.isWithContext() ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name + "#" + group; + Integer index = indexes.get(name); + if (index == null) { + synchronized (BenchmarkCounters.class) { + index = indexes.get(name); + if (index == null) { + index = indexes.size(); + indexes.put(name, index); + groups.add(group); + staticCounters.add(new AtomicLong()); + } + } + } + assert groups.get(index).equals(group) : "mismatching groups: " + groups.get(index) + " vs. " + group; + if (counter.getIncrement().isConstant()) { + staticCounters.get(index).addAndGet(counter.getIncrement().asConstant().asLong()); + } + return index; + } + + public static synchronized void dump(PrintStream out, double seconds, long[] counters) { + if (!staticCounters.isEmpty()) { + out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======"); + for (String group : new TreeSet<>(groups)) { + if (group != null) { + if (DUMP_STATIC) { + dumpCounters(out, seconds, counters, true, group); + } + dumpCounters(out, seconds, counters, false, group); + } + } + out.println("============================"); + + clear(counters); + } + } + + public static synchronized void clear(long[] counters) { + delta = counters; + } + + private static synchronized void dumpCounters(PrintStream out, double seconds, long[] counters, boolean staticCounter, String group) { + TreeMap sorted = new TreeMap<>(); + + long[] array; + if (staticCounter) { + array = new long[indexes.size()]; + for (int i = 0; i < array.length; i++) { + array[i] = staticCounters.get(i).get(); + } + } else { + array = counters.clone(); + for (int i = 0; i < array.length; i++) { + array[i] -= delta[i]; + } + } + long sum = 0; + for (Map.Entry entry : indexes.entrySet()) { + int index = entry.getValue(); + if (groups.get(index).equals(group)) { + sum += array[index]; + sorted.put(array[index] * array.length + index, entry.getKey().substring(0, entry.getKey().length() - group.length() - 1)); + } + } + + if (sum > 0) { + NumberFormat format = NumberFormat.getInstance(Locale.US); + long cutoff = sorted.size() < 10 ? 1 : Math.max(1, sum / 100); + if (staticCounter) { + out.println("=========== " + group + " static counters: "); + for (Map.Entry entry : sorted.entrySet()) { + long counter = entry.getKey() / array.length; + if (counter >= cutoff) { + out.println(format.format(counter) + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); + } + } + out.println(sum + ": total"); + } else { + if (group.startsWith("~")) { + out.println("=========== " + group + " dynamic counters"); + for (Map.Entry entry : sorted.entrySet()) { + long counter = entry.getKey() / array.length; + if (counter >= cutoff) { + out.println(format.format(counter) + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); + } + } + out.println(format.format(sum) + ": total"); + } else { + out.println("=========== " + group + " dynamic counters, time = " + seconds + " s"); + for (Map.Entry entry : sorted.entrySet()) { + long counter = entry.getKey() / array.length; + if (counter >= cutoff) { + out.println(format.format((long) (counter / seconds)) + "/s \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); + } + } + out.println(format.format((long) (sum / seconds)) + "/s: total"); + } + } + } + } + + public abstract static class CallbackOutputStream extends OutputStream { + + protected final PrintStream delegate; + private final byte[][] patterns; + private final int[] positions; + + public CallbackOutputStream(PrintStream delegate, String... patterns) { + this.delegate = delegate; + this.positions = new int[patterns.length]; + this.patterns = new byte[patterns.length][]; + for (int i = 0; i < patterns.length; i++) { + this.patterns[i] = patterns[i].getBytes(); + } + } + + protected abstract void patternFound(int index); + + @Override + public void write(int b) throws IOException { + try { + delegate.write(b); + for (int i = 0; i < patterns.length; i++) { + int j = positions[i]; + byte[] cs = patterns[i]; + byte patternChar = cs[j]; + if (patternChar == '~' && Character.isDigit(b)) { + // nothing to do... + } else { + if (patternChar == '~') { + patternChar = cs[++positions[i]]; + } + if (b == patternChar) { + positions[i]++; + } else { + positions[i] = 0; + } + } + if (positions[i] == patterns[i].length) { + positions[i] = 0; + patternFound(i); + } + } + } catch (RuntimeException e) { + e.printStackTrace(delegate); + throw e; + } + } + } + + public static void initialize(final CompilerToVM compilerToVM) { + final class BenchmarkCountersOutputStream extends CallbackOutputStream { + + private long startTime; + private boolean waitingForEnd; + + private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) { + super(delegate, new String[]{start, end, "\n"}); + } + + @Override + protected void patternFound(int index) { + switch (index) { + case 0: + startTime = System.nanoTime(); + BenchmarkCounters.clear(compilerToVM.collectCounters()); + break; + case 1: + waitingForEnd = true; + break; + case 2: + if (waitingForEnd) { + waitingForEnd = false; + BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters()); + } + break; + } + } + } + + if (Options.BenchmarkDynamicCounters.getValue() != null) { + String[] arguments = Options.BenchmarkDynamicCounters.getValue().split(","); + if (arguments.length == 0 || (arguments.length % 3) != 0) { + throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: (err|out),start,end,(err|out),start,end,... (~ matches multiple digits)"); + } + for (int i = 0; i < arguments.length; i += 3) { + if (arguments[i].equals("err")) { + System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, arguments[i + 1], arguments[i + 2]))); + } else if (arguments[i].equals("out")) { + System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, arguments[i + 1], arguments[i + 2]))); + } else { + throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out"); + } + } + excludedClassPrefix = "Lcom/oracle/graal/"; + enabled = true; + } + if (Options.GenericDynamicCounters.getValue()) { + enabled = true; + } + if (Options.GenericDynamicCounters.getValue() || Options.BenchmarkDynamicCounters.getValue() != null) { + clear(compilerToVM.collectCounters()); + } + } + + public static void shutdown(CompilerToVM compilerToVM, long compilerStartTime) { + if (Options.GenericDynamicCounters.getValue()) { + dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d, compilerToVM.collectCounters()); + } + } + + public static void lower(DynamicCounterNode counter, HotSpotRuntime runtime) { + StructuredGraph graph = counter.graph(); + if (excludedClassPrefix == null || !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) { + HotSpotVMConfig config = runtime.config; + + ReadRegisterNode thread = graph.add(new ReadRegisterNode(runtime.threadRegister(), runtime.getTarget().wordKind, true, false)); + + int index = BenchmarkCounters.getIndex(counter); + if (index >= config.graalCountersSize) { + throw new GraalInternalError("too many counters, reduce number of counters or increase GRAAL_COUNTERS_SIZE (current value: " + config.graalCountersSize + ")"); + } + ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset + Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph); + ReadNode read = graph.add(new ReadNode(thread, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false)); + IntegerAddNode add = graph.unique(new IntegerAddNode(Kind.Long, read, counter.getIncrement())); + WriteNode write = graph.add(new WriteNode(thread, add, location, BarrierType.NONE, false)); + + graph.addBeforeFixed(counter, thread); + graph.addBeforeFixed(counter, read); + graph.addBeforeFixed(counter, write); + } + graph.removeFixed(counter); + } +} diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Wed Oct 02 21:40:29 2013 +0200 @@ -99,7 +99,7 @@ ResolvedJavaMethod initMethod = null; try { Class rjm = ResolvedJavaMethod.class; - makeGraphMethod = runtime.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, SnippetInliningPolicy.class)); + makeGraphMethod = runtime.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, SnippetInliningPolicy.class, boolean.class)); initMethod = runtime.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Oct 02 21:40:29 2013 +0200 @@ -74,6 +74,7 @@ import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; +import com.oracle.graal.hotspot.debug.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.phases.*; import com.oracle.graal.hotspot.replacements.*; @@ -82,6 +83,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; @@ -554,7 +556,7 @@ ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object(); assert loadField.kind() != Kind.Illegal; BarrierType barrierType = getFieldLoadBarrierType(field); - ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object))); + ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object))); graph.replaceFixedWithFixed(loadField, memoryRead); tool.createNullCheckGuard(memoryRead, object); @@ -569,7 +571,7 @@ HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object(); BarrierType barrierType = getFieldStoreBarrierType(storeField); - WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field), barrierType, storeField.field().getKind() == Kind.Object)); + WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object)); tool.createNullCheckGuard(memoryWrite, object); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); @@ -594,7 +596,7 @@ LoadIndexedNode loadIndexed = (LoadIndexedNode) n; GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool); Kind elementKind = loadIndexed.elementKind(); - LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index()); + LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false); ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object)); memoryRead.setGuard(boundsCheck); graph.replaceFixedWithFixed(loadIndexed, memoryRead); @@ -602,7 +604,7 @@ StoreIndexedNode storeIndexed = (StoreIndexedNode) n; GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool); Kind elementKind = storeIndexed.elementKind(); - LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index()); + LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false); ValueNode value = storeIndexed.value(); ValueNode array = storeIndexed.array(); @@ -717,7 +719,7 @@ value = allocations[commit.getVirtualObjects().indexOf(value)]; } if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - WriteNode write = new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i)), + WriteNode write = new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), virtualInstance.field(i).getKind() == Kind.Object ? BarrierType.IMPRECISE : BarrierType.NONE, virtualInstance.field(i).getKind() == Kind.Object); graph.addBeforeFixed(commit, graph.add(write)); @@ -735,7 +737,7 @@ value = allocations[indexOf]; } if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - WriteNode write = new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)), + WriteNode write = new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph), true), value.kind() == Kind.Object ? BarrierType.PRECISE : BarrierType.NONE, value.kind() == Kind.Object); graph.addBeforeFixed(commit, graph.add(write)); } @@ -788,6 +790,10 @@ osrStart.replaceAtUsages(newStart); osrStart.safeDelete(); } + } else if (n instanceof DynamicCounterNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + BenchmarkCounters.lower((DynamicCounterNode) n, this); + } } else if (n instanceof CheckCastDynamicNode) { checkcastDynamicSnippets.lower((CheckCastDynamicNode) n); } else if (n instanceof InstanceOfNode) { @@ -937,8 +943,9 @@ return barrierType; } - protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field) { - return ConstantLocationNode.create(field, field.getKind(), field.offset(), graph); + protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) { + LocationIdentity loc = initialization ? INIT_LOCATION : field; + return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph); } public int getScalingFactor(Kind kind) { @@ -949,9 +956,10 @@ } } - protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) { + protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) { + LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind); int scale = getScalingFactor(elementKind); - return IndexedLocationNode.create(NamedLocationIdentity.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale); + return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale); } @Override diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Oct 02 21:40:29 2013 +0200 @@ -40,14 +40,17 @@ import com.oracle.graal.graph.iterators.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.Fold; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; import com.oracle.graal.replacements.SnippetTemplate.Arguments; import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; @@ -63,6 +66,22 @@ */ public class MonitorSnippets implements Snippets { + public static class Options { + + //@formatter:off + @Option(help = "") + private static final OptionValue ProfileMonitors = new OptionValue<>(false); + //@formatter:on + } + + private static final boolean PROFILE_CONTEXT = false; + + @Fold + @SuppressWarnings("unused") + private static boolean doProfile(String path) { + return Options.ProfileMonitors.getValue(); + } + /** * Monitor operations on objects whose type contains this substring will be traced. */ @@ -118,7 +137,7 @@ trace(trace, " tmp: 0x%016lx\n", tmp); if (probability(FREQUENT_PROBABILITY, tmp.equal(0))) { // Object is already biased to current thread -> done - traceObject(trace, "+lock{bias:existing}", object); + traceObject(trace, "+lock{bias:existing}", object, true); return; } @@ -154,13 +173,13 @@ trace(trace, " biasedMark: 0x%016lx\n", biasedMark); if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) { // Object is now biased to current thread -> done - traceObject(trace, "+lock{bias:acquired}", object); + traceObject(trace, "+lock{bias:acquired}", object, true); return; } // If the biasing toward our thread failed, this means that another thread // owns the bias and we need to revoke that bias. The revocation will occur // in the interpreter runtime. - traceObject(trace, "+lock{stub:revoke}", object); + traceObject(trace, "+lock{stub:revoke}", object, true); monitorenterStub(MONITORENTER, object, lock); return; } else { @@ -174,13 +193,13 @@ trace(trace, " biasedMark: 0x%016lx\n", biasedMark); if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) { // Object is now biased to current thread -> done - traceObject(trace, "+lock{bias:transfer}", object); + traceObject(trace, "+lock{bias:transfer}", object, true); return; } // If the biasing toward our thread failed, then another thread // succeeded in biasing it toward itself and we need to revoke that // bias. The revocation will occur in the runtime in the slow case. - traceObject(trace, "+lock{stub:epoch-expired}", object); + traceObject(trace, "+lock{stub:epoch-expired}", object, true); monitorenterStub(MONITORENTER, object, lock); return; } @@ -237,16 +256,16 @@ final Word stackPointer = stackPointer(); if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) { // Most likely not a recursive lock, go into a slow runtime call - traceObject(trace, "+lock{stub:failed-cas}", object); + traceObject(trace, "+lock{stub:failed-cas}", object, true); monitorenterStub(MONITORENTER, object, lock); return; } else { // Recursively locked => write 0 to the lock slot lock.writeWord(lockDisplacedMarkOffset(), Word.zero(), DISPLACED_MARK_WORD_LOCATION); - traceObject(trace, "+lock{recursive}", object); + traceObject(trace, "+lock{recursive}", object, true); } } else { - traceObject(trace, "+lock{cas}", object); + traceObject(trace, "+lock{cas}", object, true); } } @@ -263,7 +282,7 @@ // BeginLockScope nodes do not read from object so a use of object // cannot float about the null check above final Word lock = beginLockScope(lockDepth); - traceObject(trace, "+lock{stub}", object); + traceObject(trace, "+lock{stub}", object, true); monitorenterStub(MONITORENTER, object, lock); } @@ -282,7 +301,7 @@ if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern())))) { endLockScope(); decCounter(); - traceObject(trace, "-lock{bias}", object); + traceObject(trace, "-lock{bias}", object, false); return; } } @@ -295,7 +314,7 @@ if (displacedMark.equal(0)) { // Recursive locking => done - traceObject(trace, "-lock{recursive}", object); + traceObject(trace, "-lock{recursive}", object, false); } else { verifyOop(object); // Test if object's mark word is pointing to the displaced mark word, and if so, restore @@ -304,10 +323,10 @@ if (probability(VERY_SLOW_PATH_PROBABILITY, DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock))) { // The object's mark word was not pointing to the displaced header, // we do unlocking via runtime call. - traceObject(trace, "-lock{stub}", object); + traceObject(trace, "-lock{stub}", object, false); MonitorExitStubCall.call(object, lockDepth); } else { - traceObject(trace, "-lock{cas}", object); + traceObject(trace, "-lock{cas}", object, false); } } endLockScope(); @@ -320,13 +339,16 @@ @Snippet public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) { verifyOop(object); - traceObject(trace, "-lock{stub}", object); + traceObject(trace, "-lock{stub}", object, false); MonitorExitStubCall.call(object, lockDepth); endLockScope(); decCounter(); } - private static void traceObject(boolean enabled, String action, Object object) { + private static void traceObject(boolean enabled, String action, Object object, boolean enter) { + if (doProfile(action)) { + DynamicCounterNode.counter(action, enter ? "~monitorenter" : "~monitorexit", 1, PROFILE_CONTEXT); + } if (enabled) { Log.print(action); Log.print(' '); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Oct 02 21:40:29 2013 +0200 @@ -34,17 +34,21 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.options.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.Fold; import com.oracle.graal.replacements.Snippet.VarargsParameter; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; import com.oracle.graal.replacements.SnippetTemplate.Arguments; @@ -59,6 +63,20 @@ public static final LocationIdentity INIT_LOCATION = new NamedLocationIdentity("Initialization"); + public static class Options { + + //@formatter:off + @Option(help = "") + private static final OptionValue ProfileAllocations = new OptionValue<>(false); + //@formatter:on + } + + static enum ProfileMode { + AllocatingMethods, InstanceOrArray, AllocatedTypes, AllocatedTypesInMethods, Total + } + + public static final ProfileMode PROFILE_MODE = ProfileMode.Total; + @Snippet public static Word allocate(int size) { Word thread = thread(); @@ -76,8 +94,41 @@ return Word.zero(); } + @Fold + private static String createName(String path, String typeContext) { + switch (PROFILE_MODE) { + case AllocatingMethods: + return ""; + case InstanceOrArray: + return path; + case AllocatedTypes: + case AllocatedTypesInMethods: + return typeContext; + case Total: + return "bytes"; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Fold + @SuppressWarnings("unused") + private static boolean doProfile(String path, String typeContext) { + return Options.ProfileAllocations.getValue(); + } + + private static void profileAllocation(String path, long size, String typeContext) { + if (doProfile(path, typeContext)) { + String name = createName(path, typeContext); + + boolean context = PROFILE_MODE == ProfileMode.AllocatingMethods || PROFILE_MODE == ProfileMode.AllocatedTypesInMethods; + DynamicCounterNode.counter(name, "~bytes", size, context); + DynamicCounterNode.counter(name, "~sites", 1, context); + } + } + @Snippet - public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents) { + public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) { Object result; Word thread = thread(); Word top = readTlabTop(thread); @@ -90,6 +141,7 @@ new_stub.inc(); result = NewInstanceStubCall.call(hub); } + profileAllocation("instance", size, typeContext); return piCast(verifyOop(result), StampFactory.forNodeIntrinsic()); } @@ -99,15 +151,16 @@ public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF; @Snippet - public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, @ConstantParameter boolean fillContents) { + public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, + @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) { if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { // This handles both negative array sizes and very large array sizes DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } - return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents); + return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, typeContext); } - private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents) { + private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, String typeContext) { Object result; int alignment = wordSize(); int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); @@ -123,6 +176,7 @@ newarray_stub.inc(); result = NewArrayStubCall.call(hub, length); } + profileAllocation("array", allocationSize, typeContext); return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); } @@ -156,7 +210,7 @@ int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents); + return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, "dynamic type"); } /** @@ -261,6 +315,7 @@ args.add("hub", hub); args.add("prototypeMarkWord", type.prototypeMarkWord()); args.addConst("fillContents", newInstanceNode.fillContents()); + args.addConst("typeContext", MetaUtil.toJavaName(type, false)); SnippetTemplate template = template(args); Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args); @@ -286,6 +341,7 @@ args.addConst("headerSize", headerSize); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", newArrayNode.fillContents()); + args.addConst("typeContext", MetaUtil.toJavaName(arrayType, false)); SnippetTemplate template = template(args); Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -59,49 +59,72 @@ } ResolvedJavaType type = ObjectStamp.typeOrNull(getObject()); - Method method; - /* - * The first condition tests if the parameter is an array, the second condition tests if the - * parameter can be an array. Otherwise, the parameter is known to be a non-array object. - */ - if (type.isArray()) { - method = ObjectCloneSnippets.arrayCloneMethod; - } else if (type == null || type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) { - method = ObjectCloneSnippets.genericCloneMethod; - } else { - method = ObjectCloneSnippets.instanceCloneMethod; + if (type != null) { + if (type.isArray()) { + Method method = ObjectCloneSnippets.arrayCloneMethods.get(type.getComponentType().getKind()); + if (method != null) { + final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method); + final Replacements replacements = tool.getReplacements(); + StructuredGraph snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable() { + + @Override + public StructuredGraph call() throws Exception { + return replacements.getSnippet(snippetMethod); + } + }); + + assert snippetGraph != null : "ObjectCloneSnippets should be installed"; + return lowerReplacement(snippetGraph.copy(), tool); + } + } else { + type = getConcreteType(getObject().stamp(), tool.assumptions(), tool.getRuntime()); + if (type != null) { + StructuredGraph newGraph = new StructuredGraph(); + LocalNode local = newGraph.add(new LocalNode(0, getObject().stamp())); + NewInstanceNode newInstance = newGraph.add(new NewInstanceNode(type, true)); + newGraph.addAfterFixed(newGraph.start(), newInstance); + ReturnNode returnNode = newGraph.add(new ReturnNode(newInstance)); + newGraph.addAfterFixed(newInstance, returnNode); + + for (ResolvedJavaField field : type.getInstanceFields(true)) { + LoadFieldNode load = newGraph.add(new LoadFieldNode(local, field)); + newGraph.addBeforeFixed(returnNode, load); + newGraph.addBeforeFixed(returnNode, newGraph.add(new StoreFieldNode(newInstance, field, load))); + } + return lowerReplacement(newGraph, tool); + } + } } - final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method); - final Replacements replacements = tool.getReplacements(); - StructuredGraph snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable() { - - @Override - public StructuredGraph call() throws Exception { - return replacements.getSnippet(snippetMethod); - } - }); - - assert snippetGraph != null : "ObjectCloneSnippets should be installed"; - return lowerReplacement(snippetGraph.copy(), tool); + return null; } private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) { - return type != null && metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type); + return metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type); } - private static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions) { + /* + * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an + * exact type) and if it is a cloneable type. + * + * If yes, then the exact type is returned, otherwise it returns null. + */ + private static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) { if (!(stamp instanceof ObjectStamp)) { return null; } ObjectStamp objectStamp = (ObjectStamp) stamp; - if (objectStamp.isExactType() || objectStamp.type() == null) { - return objectStamp.type(); + if (objectStamp.type() == null) { + return null; + } else if (objectStamp.isExactType()) { + return isCloneableType(objectStamp.type(), metaAccess) ? objectStamp.type() : null; } else { ResolvedJavaType type = objectStamp.type().findUniqueConcreteSubtype(); - if (type != null) { + if (type != null && isCloneableType(type, metaAccess)) { assumptions.recordConcreteSubtype(objectStamp.type(), type); + return type; + } else { + return null; } - return type; } } @@ -126,21 +149,19 @@ } else { obj = tool.getReplacedValue(getObject()); } - ResolvedJavaType type = getConcreteType(obj.stamp(), tool.getAssumptions()); - if (isCloneableType(type, tool.getMetaAccessProvider())) { - if (!type.isArray()) { - VirtualInstanceNode newVirtual = new VirtualInstanceNode(type, true); - ResolvedJavaField[] fields = newVirtual.getFields(); + ResolvedJavaType type = getConcreteType(obj.stamp(), tool.getAssumptions(), tool.getMetaAccessProvider()); + if (type != null && !type.isArray()) { + VirtualInstanceNode newVirtual = new VirtualInstanceNode(type, true); + ResolvedJavaField[] fields = newVirtual.getFields(); - ValueNode[] state = new ValueNode[fields.length]; - final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; - for (int i = 0; i < fields.length; i++) { - state[i] = loads[i] = new LoadFieldNode(obj, fields[i]); - tool.addNode(loads[i]); - } - tool.createVirtualObject(newVirtual, state, null); - tool.replaceWithVirtual(newVirtual); + ValueNode[] state = new ValueNode[fields.length]; + final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; + for (int i = 0; i < fields.length; i++) { + state[i] = loads[i] = new LoadFieldNode(obj, fields[i]); + tool.addNode(loads[i]); } + tool.createVirtualObject(newVirtual, state, null); + tool.replaceWithVirtual(newVirtual); } } } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Wed Oct 02 21:40:29 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, 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 @@ -22,113 +22,77 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.api.meta.LocationIdentity.*; -import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; -import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*; -import static com.oracle.graal.phases.GraalOptions.*; - import java.lang.reflect.*; +import java.util.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; public class ObjectCloneSnippets implements Snippets { - public static final Method instanceCloneMethod = getCloneMethod("instanceClone"); - public static final Method arrayCloneMethod = getCloneMethod("arrayClone"); - public static final Method genericCloneMethod = getCloneMethod("genericClone"); + public static final EnumMap arrayCloneMethods = new EnumMap<>(Kind.class); - private static Method getCloneMethod(String name) { + static { + arrayCloneMethods.put(Kind.Byte, getCloneMethod("byteArrayClone", byte[].class)); + arrayCloneMethods.put(Kind.Char, getCloneMethod("charArrayClone", char[].class)); + arrayCloneMethods.put(Kind.Int, getCloneMethod("intArrayClone", int[].class)); + arrayCloneMethods.put(Kind.Long, getCloneMethod("longArrayClone", long[].class)); + arrayCloneMethods.put(Kind.Object, getCloneMethod("objectArrayClone", Object[].class)); + } + + private static Method getCloneMethod(String name, Class param) { try { - return ObjectCloneSnippets.class.getDeclaredMethod(name, Object.class); + return ObjectCloneSnippets.class.getDeclaredMethod(name, param); } catch (SecurityException | NoSuchMethodException e) { throw new GraalInternalError(e); } } - private static Object instanceClone(Object src, Word hub, int layoutHelper) { - int instanceSize = layoutHelper; - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false); - - for (int offset = instanceHeaderSize(); offset < instanceSize; offset += wordSize()) { - /* - * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values - * to be copied atomically, but here they are copied as two 4-byte word values. - */ - ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION); + @Snippet(removeAllFrameStates = true) + public static byte[] byteArrayClone(byte[] src) { + byte[] result = new byte[src.length]; + for (int i = 0; i < result.length; i++) { + result[i] = src[i]; } - return result; } - private static Object arrayClone(Object src, Word hub, int layoutHelper) { - int arrayLength = ArrayLengthNode.arrayLength(src); - int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); - int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); - int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize); - - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false); - - for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { - /* - * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values - * to be copied atomically, but here they are copied as two 4-byte word values. - */ - ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION); + @Snippet(removeAllFrameStates = true) + public static char[] charArrayClone(char[] src) { + char[] result = new char[src.length]; + for (int i = 0; i < result.length; i++) { + result[i] = src[i]; } return result; } - private static Word getAndCheckHub(Object src) { - Word hub = loadHub(src); - if (!(src instanceof Cloneable)) { - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + @Snippet(removeAllFrameStates = true) + public static int[] intArrayClone(int[] src) { + int[] result = new int[src.length]; + for (int i = 0; i < result.length; i++) { + result[i] = src[i]; } - return hub; - } - - @Snippet - public static Object instanceClone(Object src) { - instanceCloneCounter.inc(); - Word hub = getAndCheckHub(src); - return instanceClone(src, hub, hub.readInt(layoutHelperOffset(), FINAL_LOCATION)); - } - - @Snippet - public static Object arrayClone(Object src) { - arrayCloneCounter.inc(); - Word hub = getAndCheckHub(src); - int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); - return arrayClone(src, hub, layoutHelper); + return result; } - @Snippet - public static Object genericClone(Object src) { - genericCloneCounter.inc(); - Word hub = getAndCheckHub(src); - int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); - if (probability(LIKELY_PROBABILITY, layoutHelper < 0)) { - genericArrayCloneCounter.inc(); - return arrayClone(src, hub, layoutHelper); - } else { - genericInstanceCloneCounter.inc(); - return instanceClone(src, hub, layoutHelper); + @Snippet(removeAllFrameStates = true) + public static long[] longArrayClone(long[] src) { + long[] result = new long[src.length]; + for (int i = 0; i < result.length; i++) { + result[i] = src[i]; } + return result; } - private static final SnippetCounter.Group cloneCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("Object.clone") : null; - private static final SnippetCounter instanceCloneCounter = new SnippetCounter(cloneCounters, "instanceClone", "clone snippet for instances"); - private static final SnippetCounter arrayCloneCounter = new SnippetCounter(cloneCounters, "arrayClone", "clone snippet for arrays"); - private static final SnippetCounter genericCloneCounter = new SnippetCounter(cloneCounters, "genericClone", "clone snippet for arrays and instances"); - - private static final SnippetCounter.Group genericCloneCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("Object.clone generic snippet") : null; - private static final SnippetCounter genericInstanceCloneCounter = new SnippetCounter(genericCloneCounters, "genericInstanceClone", "generic clone implementation took instance path"); - private static final SnippetCounter genericArrayCloneCounter = new SnippetCounter(genericCloneCounters, "genericArrayClone", "generic clone implementation took array path"); - + @Snippet(removeAllFrameStates = true) + public static Object[] objectArrayClone(Object[] src) { + Object[] result = (Object[]) DynamicNewArrayNode.newArray(GuardingPiNode.guardingNonNull(src.getClass().getComponentType()), src.length); + for (int i = 0; i < result.length; i++) { + result[i] = src[i]; + } + return result; + } } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Wed Oct 02 21:40:29 2013 +0200 @@ -305,7 +305,7 @@ private void inline(InvokeNode invoke) { ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget()); - StructuredGraph calleeGraph = repl.makeGraph(method, null, null); + StructuredGraph calleeGraph = repl.makeGraph(method, null, null, false); InliningUtil.inline(invoke, calleeGraph, false); } } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -121,7 +121,7 @@ @Override public void setNext(FixedNode x) { if (x != null) { - this.setNext(AbstractBeginNode.begin(x)); + this.setNext(KillingBeginNode.begin(x, getLocationIdentity())); } else { this.setNext(null); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, 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. + * + * 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.graal.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.extended.*; + +public class KillingBeginNode extends AbstractBeginNode implements MemoryCheckpoint.Single { + + private LocationIdentity locationIdentity; + + public KillingBeginNode(LocationIdentity locationIdentity) { + this.locationIdentity = locationIdentity; + } + + public static KillingBeginNode begin(FixedNode with, LocationIdentity locationIdentity) { + if (with instanceof KillingBeginNode) { + return (KillingBeginNode) with; + } + KillingBeginNode begin = with.graph().add(new KillingBeginNode(locationIdentity)); + begin.setNext(with); + return begin; + } + + @Override + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } +} diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -42,6 +42,12 @@ } @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + return Constant.forIntegerKind(kind(), inputs[0].asLong() & inputs[1].asLong(), null); + } + + @Override public Node canonical(CanonicalizerTool tool) { if (x() == y()) { return x(); @@ -50,12 +56,7 @@ return graph().unique(new AndNode(kind(), y(), x())); } if (x().isConstant()) { - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() & y().asConstant().asInt(), graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() & y().asConstant().asLong(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { if (kind() == Kind.Int) { int c = y().asConstant().asInt(); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -151,52 +151,59 @@ this.value = value; } + public Constant evalConst(Constant... inputs) { + assert inputs.length == 1; + Constant c = inputs[0]; + switch (opcode) { + case I2L: + return Constant.forLong(c.asInt()); + case L2I: + return Constant.forInt((int) c.asLong()); + case I2B: + return Constant.forByte((byte) c.asInt()); + case I2C: + return Constant.forChar((char) c.asInt()); + case I2S: + return Constant.forShort((short) c.asInt()); + case F2D: + return Constant.forDouble(c.asFloat()); + case D2F: + return Constant.forFloat((float) c.asDouble()); + case I2F: + return Constant.forFloat(c.asInt()); + case I2D: + return Constant.forDouble(c.asInt()); + case F2I: + return Constant.forInt((int) c.asFloat()); + case D2I: + return Constant.forInt((int) c.asDouble()); + case L2F: + return Constant.forFloat(c.asLong()); + case L2D: + return Constant.forDouble(c.asLong()); + case F2L: + return Constant.forLong((long) c.asFloat()); + case D2L: + return Constant.forLong((long) c.asDouble()); + case UNSIGNED_I2L: + return Constant.forLong(c.asInt() & 0xffffffffL); + case MOV_I2F: + return Constant.forFloat(java.lang.Float.intBitsToFloat(c.asInt())); + case MOV_L2D: + return Constant.forDouble(java.lang.Double.longBitsToDouble(c.asLong())); + case MOV_F2I: + return Constant.forInt(java.lang.Float.floatToRawIntBits(c.asFloat())); + case MOV_D2L: + return Constant.forLong(java.lang.Double.doubleToRawLongBits(c.asDouble())); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + @Override public Node canonical(CanonicalizerTool tool) { - if (value instanceof ConstantNode) { - Constant c = ((ConstantNode) value).asConstant(); - switch (opcode) { - case I2L: - return ConstantNode.forLong(c.asInt(), graph()); - case L2I: - return ConstantNode.forInt((int) c.asLong(), graph()); - case I2B: - return ConstantNode.forByte((byte) c.asInt(), graph()); - case I2C: - return ConstantNode.forChar((char) c.asInt(), graph()); - case I2S: - return ConstantNode.forShort((short) c.asInt(), graph()); - case F2D: - return ConstantNode.forDouble(c.asFloat(), graph()); - case D2F: - return ConstantNode.forFloat((float) c.asDouble(), graph()); - case I2F: - return ConstantNode.forFloat(c.asInt(), graph()); - case I2D: - return ConstantNode.forDouble(c.asInt(), graph()); - case F2I: - return ConstantNode.forInt((int) c.asFloat(), graph()); - case D2I: - return ConstantNode.forInt((int) c.asDouble(), graph()); - case L2F: - return ConstantNode.forFloat(c.asLong(), graph()); - case L2D: - return ConstantNode.forDouble(c.asLong(), graph()); - case F2L: - return ConstantNode.forLong((long) c.asFloat(), graph()); - case D2L: - return ConstantNode.forLong((long) c.asDouble(), graph()); - case UNSIGNED_I2L: - return ConstantNode.forLong(c.asInt() & 0xffffffffL, graph()); - case MOV_I2F: - return ConstantNode.forFloat(java.lang.Float.intBitsToFloat(c.asInt()), graph()); - case MOV_L2D: - return ConstantNode.forDouble(java.lang.Double.longBitsToDouble(c.asLong()), graph()); - case MOV_F2I: - return ConstantNode.forInt(java.lang.Float.floatToRawIntBits(c.asFloat()), graph()); - case MOV_D2L: - return ConstantNode.forLong(java.lang.Double.doubleToRawLongBits(c.asDouble()), graph()); - } + if (value.isConstant()) { + return ConstantNode.forPrimitive(evalConst(value.asConstant()), graph()); } return this; } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -35,18 +35,23 @@ super(kind, x, y, isStrictFP); } + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + if (kind() == Kind.Float) { + return Constant.forFloat(inputs[0].asFloat() + inputs[1].asFloat()); + } else { + assert kind() == Kind.Double; + return Constant.forDouble(inputs[0].asDouble() + inputs[1].asDouble()); + } + } + @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && !y().isConstant()) { return graph().unique(new FloatAddNode(kind(), y(), x(), isStrictFP())); } if (x().isConstant()) { - if (kind() == Kind.Float) { - return ConstantNode.forFloat(x().asConstant().asFloat() + y().asConstant().asFloat(), graph()); - } else { - assert kind() == Kind.Double; - return ConstantNode.forDouble(x().asConstant().asDouble() + y().asConstant().asDouble(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { if (kind() == Kind.Float) { float c = y().asConstant().asFloat(); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -35,19 +35,20 @@ super(kind, x, y, isStrictFP); } + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + if (kind() == Kind.Float) { + return Constant.forFloat(inputs[0].asFloat() / inputs[1].asFloat()); + } else { + assert kind() == Kind.Double; + return Constant.forDouble(inputs[0].asDouble() / inputs[1].asDouble()); + } + } + @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && y().isConstant()) { - if (kind() == Kind.Float) { - if (y().asConstant().asFloat() != 0) { - return ConstantNode.forFloat(x().asConstant().asFloat() / y().asConstant().asFloat(), graph()); - } - } else { - assert kind() == Kind.Double; - if (y().asConstant().asDouble() != 0) { - return ConstantNode.forDouble(x().asConstant().asDouble() / y().asConstant().asDouble(), graph()); - } - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } return this; } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -35,18 +35,23 @@ super(kind, x, y, isStrictFP); } + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + if (kind() == Kind.Float) { + return Constant.forFloat(inputs[0].asFloat() * inputs[1].asFloat()); + } else { + assert kind() == Kind.Double; + return Constant.forDouble(inputs[0].asDouble() * inputs[1].asDouble()); + } + } + @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && !y().isConstant()) { return graph().unique(new FloatMulNode(kind(), y(), x(), isStrictFP())); } if (x().isConstant()) { - if (kind() == Kind.Float) { - return ConstantNode.forFloat(x().asConstant().asFloat() * y().asConstant().asFloat(), graph()); - } else { - assert kind() == Kind.Double; - return ConstantNode.forDouble(x().asConstant().asDouble() * y().asConstant().asDouble(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } return this; } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -35,15 +35,20 @@ super(kind, x, y, isStrictFP); } + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + if (kind() == Kind.Float) { + return Constant.forFloat(inputs[0].asFloat() % inputs[1].asFloat()); + } else { + assert kind() == Kind.Double; + return Constant.forDouble(inputs[0].asDouble() % inputs[1].asDouble()); + } + } + @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && y().isConstant()) { - if (kind() == Kind.Float) { - return ConstantNode.forFloat(x().asConstant().asFloat() % y().asConstant().asFloat(), graph()); - } else { - assert kind() == Kind.Double; - return ConstantNode.forDouble(x().asConstant().asDouble() % y().asConstant().asDouble(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } return this; } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -35,18 +35,23 @@ super(kind, x, y, isStrictFP); } + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + if (kind() == Kind.Float) { + return Constant.forFloat(inputs[0].asFloat() - inputs[1].asFloat()); + } else { + assert kind() == Kind.Double; + return Constant.forDouble(inputs[0].asDouble() - inputs[1].asDouble()); + } + } + @Override public Node canonical(CanonicalizerTool tool) { if (x() == y()) { return ConstantNode.forFloatingKind(kind(), 0.0f, graph()); } if (x().isConstant() && y().isConstant()) { - if (kind() == Kind.Float) { - return ConstantNode.forFloat(x().asConstant().asFloat() - y().asConstant().asFloat(), graph()); - } else { - assert kind() == Kind.Double; - return ConstantNode.forDouble(x().asConstant().asDouble() - y().asConstant().asDouble(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { if (kind() == Kind.Float) { float c = y().asConstant().asFloat(); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -42,6 +42,12 @@ } @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + return Constant.forIntegerKind(kind(), inputs[0].asLong() + inputs[1].asLong(), null); + } + + @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && !y().isConstant()) { return graph().unique(new IntegerAddNode(kind(), y(), x())); @@ -61,12 +67,7 @@ } } if (x().isConstant()) { - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() + y().asConstant().asInt(), graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() + y().asConstant().asLong(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { long c = y().asConstant().asLong(); if (c == 0) { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -37,17 +37,18 @@ } @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + return Constant.forIntegerKind(kind(), inputs[0].asLong() * inputs[1].asLong(), null); + } + + @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && !y().isConstant()) { return graph().unique(new IntegerMulNode(kind(), y(), x())); } if (x().isConstant()) { - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() * y().asConstant().asInt(), graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() * y().asConstant().asLong(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { long c = y().asConstant().asLong(); if (c == 1) { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -42,6 +42,12 @@ } @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + return Constant.forIntegerKind(kind(), inputs[0].asLong() - inputs[1].asLong(), null); + } + + @Override public Node canonical(CanonicalizerTool tool) { if (x() == y()) { return ConstantNode.forIntegerKind(kind(), 0, graph()); @@ -81,12 +87,7 @@ } } if (x().isConstant() && y().isConstant()) { - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() - y().asConstant().asInt(), graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() - y().asConstant().asLong(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { long c = y().asConstant().asLong(); if (c == 0) { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -42,8 +42,21 @@ } @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + if (kind() == Kind.Int) { + return Constant.forInt(inputs[0].asInt() << inputs[1].asInt()); + } else { + assert kind() == Kind.Long; + return Constant.forLong(inputs[0].asLong() << inputs[1].asLong()); + } + } + + @Override public Node canonical(CanonicalizerTool tool) { - if (y().isConstant()) { + if (x().isConstant() && y().isConstant()) { + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); + } else if (y().isConstant()) { int amount = y().asConstant().asInt(); int originalAmout = amount; int mask; @@ -54,14 +67,6 @@ mask = 0x3f; } amount &= mask; - if (x().isConstant()) { - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() << amount, graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() << amount, graph()); - } - } if (amount == 0) { return x(); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; @@ -54,19 +55,26 @@ this.x = x; } + public Constant evalConst(Constant... inputs) { + assert inputs.length == 1; + switch (inputs[0].getKind()) { + case Int: + return Constant.forInt(-inputs[0].asInt()); + case Long: + return Constant.forLong(-inputs[0].asLong()); + case Float: + return Constant.forFloat(-inputs[0].asFloat()); + case Double: + return Constant.forDouble(-inputs[0].asDouble()); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant()) { - switch (x().kind()) { - case Int: - return ConstantNode.forInt(-x().asConstant().asInt(), graph()); - case Long: - return ConstantNode.forLong(-x().asConstant().asLong(), graph()); - case Float: - return ConstantNode.forFloat(-x().asConstant().asFloat(), graph()); - case Double: - return ConstantNode.forDouble(-x().asConstant().asDouble(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x.asConstant()), graph()); } if (x() instanceof NegateNode) { return ((NegateNode) x()).x(); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -45,6 +45,12 @@ return updateStamp(StampTool.not(x().stamp())); } + @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 1; + return Constant.forIntegerKind(kind(), ~inputs[0].asLong(), null); + } + /** * Creates new NegateNode instance. * @@ -59,12 +65,7 @@ @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant()) { - switch (x().kind()) { - case Int: - return ConstantNode.forInt(~x().asConstant().asInt(), graph()); - case Long: - return ConstantNode.forLong(~x().asConstant().asLong(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant()), graph()); } if (x() instanceof NotNode) { return ((NotNode) x()).x(); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -42,6 +42,12 @@ } @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + return Constant.forIntegerKind(kind(), inputs[0].asLong() | inputs[1].asLong(), null); + } + + @Override public Node canonical(CanonicalizerTool tool) { if (x() == y()) { return x(); @@ -50,12 +56,7 @@ return graph().unique(new OrNode(kind(), y(), x())); } if (x().isConstant()) { - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() | y().asConstant().asInt(), graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() | y().asConstant().asLong(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { if (kind() == Kind.Int) { int c = y().asConstant().asInt(); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -37,11 +37,24 @@ } @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + if (kind() == Kind.Int) { + return Constant.forInt(inputs[0].asInt() >> inputs[1].asInt()); + } else { + assert kind() == Kind.Long; + return Constant.forLong(inputs[0].asLong() >> inputs[1].asLong()); + } + } + + @Override public Node canonical(CanonicalizerTool tool) { if (x().stamp() instanceof IntegerStamp && ((IntegerStamp) x().stamp()).isPositive()) { return graph().unique(new UnsignedRightShiftNode(kind(), x(), y())); } - if (y().isConstant()) { + if (x().isConstant() && y().isConstant()) { + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); + } else if (y().isConstant()) { int amount = y().asConstant().asInt(); int originalAmout = amount; int mask; @@ -52,14 +65,6 @@ mask = 0x3f; } amount &= mask; - if (x().isConstant()) { - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() >> amount, graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() >> amount, graph()); - } - } if (amount == 0) { return x(); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -42,8 +42,21 @@ } @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + if (kind() == Kind.Int) { + return Constant.forInt(inputs[0].asInt() >>> inputs[1].asInt()); + } else { + assert kind() == Kind.Long; + return Constant.forLong(inputs[0].asLong() >>> inputs[1].asLong()); + } + } + + @Override public Node canonical(CanonicalizerTool tool) { - if (y().isConstant()) { + if (x().isConstant() && y().isConstant()) { + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); + } else if (y().isConstant()) { int amount = y().asConstant().asInt(); int originalAmout = amount; int mask; @@ -54,14 +67,6 @@ mask = 0x3f; } amount &= mask; - if (x().isConstant()) { - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() >>> amount, graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() >>> amount, graph()); - } - } if (amount == 0) { return x(); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -42,6 +42,12 @@ } @Override + public Constant evalConst(Constant... inputs) { + assert inputs.length == 2; + return Constant.forIntegerKind(kind(), inputs[0].asLong() ^ inputs[1].asLong(), null); + } + + @Override public Node canonical(CanonicalizerTool tool) { if (x() == y()) { return ConstantNode.forIntegerKind(kind(), 0, graph()); @@ -50,12 +56,7 @@ return graph().unique(new XorNode(kind(), y(), x())); } if (x().isConstant()) { - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() ^ y().asConstant().asInt(), graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() ^ y().asConstant().asLong(), graph()); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { if (kind() == Kind.Int) { int c = y().asConstant().asInt(); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -22,200 +22,61 @@ */ package com.oracle.graal.nodes.debug; -import java.io.*; -import java.util.*; - -import sun.misc.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; /** * This node can be used to add a counter to the code that will estimate the dynamic number of calls * by adding an increment to the compiled code. This should of course only be used for - * debugging/testing purposes, and is not 100% accurate (because of concurrency issues while - * accessing the counters). + * debugging/testing purposes. * - * A unique counter will be created for each unique String passed to the constructor. + * A unique counter will be created for each unique name passed to the constructor. Depending on the + * value of withContext, the name of the root method is added to the counter's name. */ public class DynamicCounterNode extends FixedWithNextNode implements Lowerable { - private static final int MAX_COUNTERS = 10 * 1024; - public static final long[] COUNTERS = new long[MAX_COUNTERS]; - private static final long[] STATIC_COUNTERS = new long[MAX_COUNTERS]; - private static final String[] GROUPS = new String[MAX_COUNTERS]; - private static final HashMap INDEXES = new HashMap<>(); - public static String excludedClassPrefix = null; - public static boolean enabled = false; + @Input private ValueNode increment; private final String name; private final String group; - private final long increment; - private final boolean addContext; + private final boolean withContext; - public DynamicCounterNode(String name, String group, long increment, boolean addContext) { + public DynamicCounterNode(String name, String group, ValueNode increment, boolean withContext) { super(StampFactory.forVoid()); - if (!enabled) { - throw new GraalInternalError("dynamic counters not enabled"); - } this.name = name; this.group = group; this.increment = increment; - this.addContext = addContext; + this.withContext = withContext; + } + + public ValueNode getIncrement() { + return increment; } public String getName() { return name; } - public long getIncrement() { - return increment; - } - - public boolean isAddContext() { - return addContext; - } - - private static synchronized int getIndex(String name) { - Integer index = INDEXES.get(name); - if (index == null) { - index = INDEXES.size(); - INDEXES.put(name, index); - if (index >= MAX_COUNTERS) { - throw new GraalInternalError("too many dynamic counters"); - } - return index; - } else { - return index; - } - } - - public static synchronized void dump(PrintStream out, double seconds) { - for (String group : new HashSet<>(Arrays.asList(GROUPS))) { - if (group != null) { - dumpCounters(out, seconds, true, group); - dumpCounters(out, seconds, false, group); - } - } - out.println("============================"); - - clear(); + public String getGroup() { + return group; } - private static void dumpCounters(PrintStream out, double seconds, boolean staticCounter, String group) { - TreeMap sorted = new TreeMap<>(); - - long[] array = staticCounter ? STATIC_COUNTERS : COUNTERS; - long sum = 0; - for (Map.Entry entry : INDEXES.entrySet()) { - int index = entry.getValue(); - if (GROUPS[index].equals(group)) { - sum += array[index]; - sorted.put(array[index] * MAX_COUNTERS + index, entry.getKey()); - } - } - - if (sum > 0) { - long cutoff = sum / 1000; - long sum2 = 0; - if (staticCounter) { - out.println("=========== " + group + " static counters: "); - for (Map.Entry entry : sorted.entrySet()) { - long counter = entry.getKey() / MAX_COUNTERS; - sum2 += counter; - if (sum2 >= cutoff) { - out.println(counter + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); - } - } - out.println(sum + ": total"); - } else { - if (group.startsWith("~")) { - out.println("=========== " + group + " dynamic counters"); - for (Map.Entry entry : sorted.entrySet()) { - long counter = entry.getKey() / MAX_COUNTERS; - sum2 += counter; - if (sum2 >= cutoff) { - out.println(counter + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); - } - } - out.println(sum + "/s: total"); - } else { - out.println("=========== " + group + " dynamic counters, time = " + seconds + " s"); - for (Map.Entry entry : sorted.entrySet()) { - long counter = entry.getKey() / MAX_COUNTERS; - sum2 += counter; - if (sum2 >= cutoff) { - out.println((long) (counter / seconds) + "/s \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); - } - } - out.println((long) (sum / seconds) + "/s: total"); - } - } - } - } - - public static void clear() { - Arrays.fill(COUNTERS, 0); + public boolean isWithContext() { + return withContext; } @Override public void lower(LoweringTool tool) { - if (!enabled) { - throw new GraalInternalError("counter nodes shouldn't exist when not enabled"); - } - if (excludedClassPrefix == null || !graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) { - int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", graph().method())) : getIndex(name); - STATIC_COUNTERS[index] += increment; - GROUPS[index] = group; - - ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph()); - ConstantNode indexConstant = ConstantNode.forInt(index, graph()); - LoadIndexedNode load = graph().add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long)); - IntegerAddNode add = graph().add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph()))); - StoreIndexedNode store = graph().add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add)); - - graph().addBeforeFixed(this, load); - graph().addBeforeFixed(this, store); - load.lower(tool); - store.lower(tool); - } - graph().removeFixed(this); + tool.getRuntime().lower(this, tool); } - public static void addLowLevel(String group, String name, long increment, boolean addContext, FixedNode position, MetaAccessProvider runtime) { - if (!enabled) { - throw new GraalInternalError("counter nodes shouldn't exist when not enabled"); - } + public static void addCounterBefore(String group, String name, long increment, boolean withContext, FixedNode position) { StructuredGraph graph = position.graph(); - if (excludedClassPrefix == null || !graph.method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) { - int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", graph.method())) : getIndex(name); - STATIC_COUNTERS[index] += increment; - GROUPS[index] = group; - - ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, runtime, graph); - ConstantLocationNode location = ConstantLocationNode.create(NamedLocationIdentity.getArrayLocation(Kind.Long), Kind.Long, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * - index, graph); - ReadNode read = graph.add(new ReadNode(arrayConstant, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false)); - IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, read, ConstantNode.forLong(increment, graph))); - WriteNode write = graph.add(new WriteNode(arrayConstant, add, location, BarrierType.NONE, false)); - - graph.addBeforeFixed(position, read); - graph.addBeforeFixed(position, write); - } + graph.addBeforeFixed(position, position.graph().add(new DynamicCounterNode(name, group, ConstantNode.forLong(increment, position.graph()), withContext))); } - public static void addCounterBefore(String group, String name, long increment, boolean addContext, FixedNode position) { - if (enabled) { - StructuredGraph graph = position.graph(); - DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, group, increment, addContext)); - graph.addBeforeFixed(position, counter); - } - } + @NodeIntrinsic + public static native void counter(@ConstantNodeParameter String name, @ConstantNodeParameter String group, long increment, @ConstantNodeParameter boolean addContext); + } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -36,7 +36,7 @@ @Input private ValueNode checkedValue; - public SurvivingCounterNode(String group, String name, long increment, boolean addContext, ValueNode checkedValue) { + public SurvivingCounterNode(String group, String name, ValueNode increment, boolean addContext, ValueNode checkedValue) { super(group, name, increment, addContext); this.checkedValue = checkedValue; } @@ -56,4 +56,10 @@ tool.delete(); } } + + public static void addCounterBefore(String group, String name, long increment, boolean addContext, ValueNode checkedValue, FixedNode position) { + StructuredGraph graph = position.graph(); + SurvivingCounterNode counter = graph.add(new SurvivingCounterNode(name, group, ConstantNode.forLong(increment, graph), addContext, checkedValue)); + graph.addBeforeFixed(position, counter); + } } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -74,4 +75,25 @@ public Access asFixedNode() { return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), getGuard(), getBarrierType(), isCompressible())); } + + private static boolean isMemoryCheckPoint(Node n) { + return n instanceof MemoryCheckpoint.Single || n instanceof MemoryCheckpoint.Multi; + } + + private static boolean isMemoryPhi(Node n) { + return n instanceof PhiNode && ((PhiNode) n).type() == PhiType.Memory; + } + + private static boolean isMemoryProxy(Node n) { + return n instanceof ProxyNode && ((ProxyNode) n).type() == PhiType.Memory; + } + + @Override + public boolean verify() { + Node lla = lastLocationAccess(); + if (lla != null && !(isMemoryCheckPoint(lla) || isMemoryPhi(lla) || isMemoryProxy(lla))) { + assert false : "lastLocationAccess of " + this + " should be a MemoryCheckpoint, but is " + lla; + } + return super.verify(); + } } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Wed Oct 02 21:40:29 2013 +0200 @@ -34,7 +34,7 @@ public interface Virtualizable { public static enum EscapeState { - Virtual, ThreadLocal, Global + Virtual, Materialized } public abstract static class State { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Wed Oct 02 21:40:29 2013 +0200 @@ -87,15 +87,6 @@ */ void setVirtualEntry(State state, int index, ValueNode value); - /** - * Queries the current state of the given value: if it was materialized or not. - * - * @param value the value whose state should be queried. - * @return the materialized value (usually a MaterializeObjectNode or a {@link PhiNode}) if it - * was materialized, null otherwise. - */ - ValueNode getMaterializedValue(ValueNode value); - // scalar replacement /** diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Wed Oct 02 21:40:29 2013 +0200 @@ -234,7 +234,7 @@ boolean result = baseTryCanonicalize(node, nodeClass); if (!result && customCanonicalizer != null && node instanceof ValueNode) { ValueNode valueNode = (ValueNode) node; - ValueNode canonical = customCanonicalizer.canonicalize(valueNode); + Node canonical = customCanonicalizer.canonicalize(valueNode); result = performReplacement(node, canonical); } return result; diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Wed Oct 02 21:40:29 2013 +0200 @@ -36,6 +36,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.tiers.*; @@ -172,6 +173,9 @@ int fixedCount = 0; while (fixed instanceof FixedWithNextNode) { fixed = ((FixedWithNextNode) fixed).next(); + if (fixed instanceof CommitAllocationNode) { + return false; + } fixedCount++; } if (fixedCount > 1) { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Wed Oct 02 21:40:29 2013 +0200 @@ -70,8 +70,6 @@ @Option(help = "") public static final OptionValue PartialEscapeAnalysis = new OptionValue<>(true); @Option(help = "") - public static final OptionValue EscapeAnalysisHistogram = new OptionValue<>(false); - @Option(help = "") public static final OptionValue EscapeAnalysisIterations = new OptionValue<>(2); @Option(help = "") public static final OptionValue EscapeAnalyzeOnly = new OptionValue<>(null); diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Wed Oct 02 21:40:29 2013 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; @@ -99,7 +100,7 @@ @Override protected HashSet processBlock(Block block, HashSet currentState) { - for (Node node : getBlockToNodesMap().get(block)) { + for (Node node : blockToNodesMap.get(block)) { if (node instanceof FloatingReadNode) { currentState.add((FloatingReadNode) node); } else if (node instanceof MemoryCheckpoint.Single) { @@ -183,37 +184,49 @@ @Override protected Map processBlock(Block block, Map currentState) { - Map initKillMap = getBlockToKillMap().get(block); - initKillMap.putAll(currentState); + + if (block.getBeginNode() instanceof MergeNode) { + MergeNode mergeNode = (MergeNode) block.getBeginNode(); + for (PhiNode phi : mergeNode.usages().filter(PhiNode.class)) { + if (phi.type() == PhiType.Memory) { + LocationIdentity identity = (LocationIdentity) phi.getIdentity(); + locationKilledBy(identity, phi, currentState); + } + } + } + currentState.putAll(blockToKillMapInit.get(block)); for (Node node : block.getNodes()) { if (node instanceof MemoryCheckpoint.Single) { LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity(); - initKillMap.put(identity, node); + locationKilledBy(identity, node, currentState); } else if (node instanceof MemoryCheckpoint.Multi) { for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) { - initKillMap.put(identity, node); + locationKilledBy(identity, node, currentState); } } assert MemoryCheckpoint.TypeAssertion.correctType(node); } - return cloneState(initKillMap); + blockToKillMap.put(block, currentState); + return cloneState(currentState); + } + + private void locationKilledBy(LocationIdentity identity, Node checkpoint, Map state) { + state.put(identity, checkpoint); + if (identity == ANY_LOCATION) { + for (LocationIdentity locid : state.keySet()) { + state.put(locid, checkpoint); + } + } } @Override protected Map merge(Block merge, List> states) { - return merge(merge, states, false); - } - - protected Map merge(Block merge, List> states, boolean loopbegin) { assert merge.getBeginNode() instanceof MergeNode; MergeNode mergeNode = (MergeNode) merge.getBeginNode(); Map initKillMap = new HashMap<>(); - if (loopbegin) { - initKillMap.putAll(getBlockToKillMap().get(merge)); - } for (Map state : states) { for (LocationIdentity locid : state.keySet()) { if (initKillMap.containsKey(locid)) { @@ -226,10 +239,7 @@ } } - getMergeToKillMap().set(mergeNode, cloneState(initKillMap)); - if (!loopbegin) { - initKillMap.putAll(getBlockToKillMap().get(merge)); - } + mergeToKillMap.set(mergeNode, cloneState(initKillMap)); return initKillMap; } @@ -240,18 +250,27 @@ @Override protected List> processLoop(Loop loop, Map state) { - LoopInfo> info = ReentrantBlockIterator.processLoop(this, loop, new HashMap<>(state)); + LoopInfo> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(state)); assert loop.header.getBeginNode() instanceof LoopBeginNode; - Map headerState = merge(loop.header, info.endStates, true); - getBlockToKillMap().put(loop.header, headerState); + Map headerState = merge(loop.header, info.endStates); + // second iteration, for computing information at loop exits + info = ReentrantBlockIterator.processLoop(this, loop, cloneState(headerState)); + + int i = 0; + for (Block exit : loop.exits) { + Map exitState = info.exitStates.get(i++); - for (Map exitState : info.exitStates) { - for (LocationIdentity key : headerState.keySet()) { - exitState.put(key, headerState.get(key)); + Node begin = exit.getBeginNode(); + assert begin instanceof LoopExitNode; + for (Node usage : begin.usages()) { + if (usage instanceof ProxyNode && ((ProxyNode) usage).type() == PhiType.Memory) { + ProxyNode proxy = (ProxyNode) usage; + LocationIdentity identity = (LocationIdentity) proxy.getIdentity(); + locationKilledBy(identity, proxy, exitState); + } } } - return info.exitStates; } } @@ -263,6 +282,7 @@ * Map from blocks to the nodes in each block. */ private BlockMap> blockToNodesMap; + private BlockMap> blockToKillMapInit; private BlockMap> blockToKillMap; private NodeMap> mergeToKillMap; private final Map> phantomUsages = new IdentityHashMap<>(); @@ -315,8 +335,10 @@ } else if (memsched == MemoryScheduling.OPTIMAL && selectedStrategy != SchedulingStrategy.EARLIEST && graph.getNodes(FloatingReadNode.class).isNotEmpty()) { mergeToKillMap = graph.createNodeMap(); + blockToKillMapInit = new BlockMap<>(cfg); blockToKillMap = new BlockMap<>(cfg); for (Block b : cfg.getBlocks()) { + blockToKillMapInit.put(b, new HashMap()); blockToKillMap.put(b, new HashMap()); } @@ -328,7 +350,7 @@ Node first = n.lastLocationAccess(); assert first != null; - Map killMap = blockToKillMap.get(forKillLocation(first)); + Map killMap = blockToKillMapInit.get(forKillLocation(first)); killMap.put(n.location().getLocationIdentity(), first); } @@ -357,20 +379,27 @@ private void printSchedule(String desc) { Debug.printf("=== %s / %s / %s (%s) ===\n", getCFG().getStartBlock().getBeginNode().graph(), selectedStrategy, memsched, desc); for (Block b : getCFG().getBlocks()) { - Debug.printf("==== b: %s. ", b); + Debug.printf("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth()); Debug.printf("dom: %s. ", b.getDominator()); Debug.printf("post-dom: %s. ", b.getPostdominator()); Debug.printf("preds: %s. ", b.getPredecessors()); Debug.printf("succs: %s ====\n", b.getSuccessors()); - BlockMap> killMaps = getBlockToKillMap(); + BlockMap> killMaps = blockToKillMap; if (killMaps != null) { + if (b.getBeginNode() instanceof MergeNode) { + MergeNode merge = (MergeNode) b.getBeginNode(); + Debug.printf("M merge kills: \n"); + for (LocationIdentity locId : mergeToKillMap.get(merge).keySet()) { + Debug.printf("M %s killed by %s\n", locId, mergeToKillMap.get(merge).get(locId)); + } + } Debug.printf("X block kills: \n"); for (LocationIdentity locId : killMaps.get(b).keySet()) { Debug.printf("X %s killed by %s\n", locId, killMaps.get(b).get(locId)); } } - if (getBlockToNodesMap().get(b) != null) { + if (blockToNodesMap.get(b) != null) { for (Node n : nodesFor(b)) { printNode(n); } @@ -414,14 +443,6 @@ return blockToNodesMap; } - public BlockMap> getBlockToKillMap() { - return blockToKillMap; - } - - public NodeMap> getMergeToKillMap() { - return mergeToKillMap; - } - /** * Gets the nodes in a given block. */ @@ -465,10 +486,11 @@ throw new SchedulingError("%s should already have been placed in a block", node); } + Block earliestBlock = earliestBlock(node); Block block; switch (strategy) { case EARLIEST: - block = earliestBlock(node); + block = earliestBlock; break; case LATEST: case LATEST_OUT_OF_LOOPS: @@ -477,23 +499,19 @@ } else { block = latestBlock(node, strategy); if (block == null) { - block = earliestBlock(node); + block = earliestBlock; } else if (strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS && !(node instanceof VirtualObjectNode)) { // schedule at the latest position possible in the outermost loop possible - Block earliestBlock = earliestBlock(node); - Block before = block; block = scheduleOutOfLoops(node, block, earliestBlock); - if (!earliestBlock.dominates(block)) { - throw new SchedulingError("%s: Graph cannot be scheduled : inconsistent for %s, %d usages, (%s needs to dominate %s (before %s))", node.graph(), node, - node.usages().count(), earliestBlock, block, before); - } } } break; default: throw new GraalInternalError("unknown scheduling strategy"); } - assert earliestBlock(node).dominates(block) : "node " + node + " in block " + block + " is not dominated by earliest " + earliestBlock(node); + if (!earliestBlock.dominates(block)) { + throw new SchedulingError("%s: Graph cannot be scheduled : inconsistent for %s, %d usages, (%s needs to dominate %s)", node.graph(), node, node.usages().count(), earliestBlock, block); + } cfg.getNodeToBlock().set(node, block); blockToNodesMap.get(block).add(node); } @@ -541,9 +559,8 @@ // iterate the dominator tree while (true) { iterations++; - assert earliestBlock.dominates(previousBlock) : "iterations: " + iterations; Node lastKill = blockToKillMap.get(currentBlock).get(locid); - boolean isAtEarliest = earliestBlock == previousBlock && previousBlock != currentBlock; + assert lastKill != null : "should be never null, due to init of killMaps: " + currentBlock + ", location: " + locid; if (lastKill.equals(upperBound)) { // assign node to the block which kills the location @@ -553,7 +570,6 @@ // schedule read out of the loop if possible, in terms of killMaps and earliest // schedule if (currentBlock != earliestBlock && previousBlock != earliestBlock) { - assert earliestBlock.dominates(currentBlock); Block t = currentBlock; while (t.getLoop() != null && t.getDominator() != null && earliestBlock.dominates(t)) { Block dom = t.getDominator(); @@ -568,17 +584,12 @@ if (!outOfLoop && previousBlock.getBeginNode() instanceof MergeNode) { // merges kill locations right at the beginning of a block. if a merge is the - // killing node, we assign it to the dominating node. + // killing node, we assign it to the dominating block. MergeNode merge = (MergeNode) previousBlock.getBeginNode(); - Node killer = getMergeToKillMap().get(merge).get(locid); + Node killer = mergeToKillMap.get(merge).get(locid); if (killer != null && killer == merge) { - // check if we violate earliest schedule condition - if (isAtEarliest) { - printIterations(iterations, "earliest bound in merge: " + earliestBlock); - return earliestBlock; - } printIterations(iterations, "kill by merge: " + currentBlock); return currentBlock; } @@ -590,11 +601,6 @@ return previousBlock; } - if (isAtEarliest) { - printIterations(iterations, "earliest bound: " + earliestBlock); - return earliestBlock; - } - if (upperBoundBlock == currentBlock) { printIterations(iterations, "upper bound: " + currentBlock + ", previous: " + previousBlock); return currentBlock; diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -22,9 +22,10 @@ */ package com.oracle.graal.replacements.amd64; +import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.ConvertNode.Op; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -44,6 +45,12 @@ this.value = value; } + public Constant evalConst(Constant... inputs) { + // this node should never have been created if its input is constant + assert false; + return null; + } + public void generate(ArithmeticLIRGenerator gen) { gen.setResult(this, gen.emitConvert(opcode, gen.operand(value))); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Wed Oct 02 21:40:29 2013 +0200 @@ -57,7 +57,7 @@ @Override protected StructuredGraph parse(Method m) { ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, null, inliningPolicy.get()); + return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false); } @Test diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Wed Oct 02 21:40:29 2013 +0200 @@ -61,7 +61,7 @@ @Override protected StructuredGraph parse(Method m) { ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, null, inliningPolicy.get()); + return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false); } @Test diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Wed Oct 02 21:40:29 2013 +0200 @@ -51,7 +51,7 @@ @Override protected StructuredGraph parse(Method m) { ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, null, inliningPolicy.get()); + return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false); } @LongTest diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Oct 02 21:40:29 2013 +0200 @@ -84,7 +84,7 @@ StructuredGraph graph = graphs.get(method); if (graph == null) { - graphs.putIfAbsent(method, makeGraph(method, null, inliningPolicy(method))); + graphs.putIfAbsent(method, makeGraph(method, null, inliningPolicy(method), method.getAnnotation(Snippet.class).removeAllFrameStates())); graph = graphs.get(method); } return graph; @@ -97,7 +97,7 @@ } StructuredGraph graph = graphs.get(substitute); if (graph == null) { - graphs.putIfAbsent(substitute, makeGraph(substitute, original, inliningPolicy(substitute))); + graphs.putIfAbsent(substitute, makeGraph(substitute, original, inliningPolicy(substitute), false)); graph = graphs.get(substitute); } return graph; @@ -221,9 +221,10 @@ * @param original the original method if {@code method} is a {@linkplain MethodSubstitution * substitution} otherwise null * @param policy the inlining policy to use during preprocessing + * @param removeAllFrameStates removes all frame states from side effecting instructions */ - public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy) { - return createGraphMaker(method, original).makeGraph(policy); + public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy, boolean removeAllFrameStates) { + return createGraphMaker(method, original).makeGraph(policy, removeAllFrameStates); } /** @@ -261,7 +262,7 @@ this.original = original; } - public StructuredGraph makeGraph(final SnippetInliningPolicy policy) { + public StructuredGraph makeGraph(final SnippetInliningPolicy policy, final boolean removeAllFrameStates) { return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable() { @Override @@ -271,7 +272,7 @@ // Cannot have a finalized version of a graph in the cache graph = graph.copy(); - finalizeGraph(graph); + finalizeGraph(graph, removeAllFrameStates); Debug.dump(graph, "%s: Final", method.getName()); @@ -283,7 +284,7 @@ /** * Does final processing of a snippet graph. */ - protected void finalizeGraph(StructuredGraph graph) { + protected void finalizeGraph(StructuredGraph graph, boolean removeAllFrameStates) { new NodeIntrinsificationPhase(runtime).apply(graph); if (!SnippetTemplate.hasConstantParameter(method)) { NodeIntrinsificationVerificationPhase.verify(graph); @@ -291,7 +292,15 @@ new ConvertDeoptimizeToGuardPhase().apply(graph); if (original == null) { - new SnippetFrameStateCleanupPhase().apply(graph); + if (removeAllFrameStates) { + for (Node node : graph.getNodes()) { + if (node instanceof StateSplit) { + ((StateSplit) node).setStateAfter(null); + } + } + } else { + new SnippetFrameStateCleanupPhase().apply(graph); + } } new DeadCodeEliminationPhase().apply(graph); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Wed Oct 02 21:40:29 2013 +0200 @@ -45,6 +45,13 @@ Class inlining() default SnippetInliningPolicy.class; /** + * Specifies whether all FrameStates within this snippet should always be removed. If this is + * false, FrameStates are only removed if there are no side-effecting instructions in the + * snippet. + */ + boolean removeAllFrameStates() default false; + + /** * Guides inlining decisions used when installing a snippet. */ public interface SnippetInliningPolicy { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Wed Oct 02 21:40:29 2013 +0200 @@ -86,28 +86,15 @@ gen.setResult(this, result); } + public Constant evalConst(Constant... inputs) { + assert inputs.length == 1; + return Constant.forDouble(compute(inputs[0].asDouble(), operation())); + } + @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant()) { - double value = x().asConstant().asDouble(); - switch (operation()) { - case ABS: - return ConstantNode.forDouble(Math.abs(value), graph()); - case SQRT: - return ConstantNode.forDouble(Math.sqrt(value), graph()); - case LOG: - return ConstantNode.forDouble(Math.log(value), graph()); - case LOG10: - return ConstantNode.forDouble(Math.log10(value), graph()); - case SIN: - return ConstantNode.forDouble(Math.sin(value), graph()); - case COS: - return ConstantNode.forDouble(Math.cos(value), graph()); - case TAN: - return ConstantNode.forDouble(Math.tan(value), graph()); - default: - throw GraalInternalError.shouldNotReachHere(); - } + return ConstantNode.forPrimitive(evalConst(x().asConstant()), graph()); } return this; } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java Wed Oct 02 21:40:29 2013 +0200 @@ -30,8 +30,7 @@ /** * An {@link EffectList} can be used to maintain a list of {@link Effect}s and backtrack to a - * previous state by truncating the list. It can also maintain a level for each effect, which helps - * in creating a string representation for the list. + * previous state by truncating the list. */ public class EffectList implements Iterable { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java Wed Oct 02 21:40:29 2013 +0200 @@ -24,48 +24,14 @@ import java.util.*; -import com.oracle.graal.nodes.*; - public abstract class EffectsBlockState> { - protected final IdentityHashMap scalarAliases; - - protected EffectsBlockState() { - scalarAliases = new IdentityHashMap<>(); - } - - protected EffectsBlockState(EffectsBlockState other) { - scalarAliases = new IdentityHashMap<>(other.scalarAliases); - } - - public void addScalarAlias(ValueNode alias, ValueNode value) { - scalarAliases.put(alias, value); - } - - public ValueNode getScalarAlias(ValueNode alias) { - ValueNode result = scalarAliases.get(alias); - return result == null ? alias : result; - } - @Override public String toString() { - return "Scalar Aliases: " + scalarAliases.toString(); + return ""; } - public void meetAliases(List states) { - scalarAliases.putAll(states.get(0).scalarAliases); - for (int i = 1; i < states.size(); i++) { - EffectsBlockState state = states.get(i); - meetMaps(scalarAliases, state.scalarAliases); - } - } - - public boolean equivalentTo(T other) { - if (this == other) { - return true; - } - return scalarAliases.equals(other.scalarAliases); - } + protected abstract boolean equivalentTo(T other); protected static boolean compareMaps(Map left, Map right) { if (left.size() != right.size()) { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Wed Oct 02 21:40:29 2013 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo; @@ -40,6 +41,7 @@ private final SchedulePhase schedule; + protected final NodeMap aliases; protected final BlockMap blockEffects; private final IdentityHashMap loopMergeEffects = new IdentityHashMap<>(); @@ -47,6 +49,7 @@ public EffectsClosure(SchedulePhase schedule) { this.schedule = schedule; + this.aliases = schedule.getCFG().graph.createNodeMap(); this.blockEffects = new BlockMap<>(schedule.getCFG()); for (Block block : schedule.getCFG().getBlocks()) { blockEffects.put(block, new GraphEffectList()); @@ -118,6 +121,7 @@ GraphEffectList effects = blockEffects.get(block); FixedWithNextNode lastFixedNode = null; for (Node node : schedule.getBlockToNodesMap().get(block)) { + aliases.set(node, null); changed |= processNode(node, state, effects, lastFixedNode); if (node instanceof FixedWithNextNode) { lastFixedNode = (FixedWithNextNode) node; @@ -202,9 +206,11 @@ this.afterMergeEffects = new GraphEffectList(); } + /** + * @param states the states that should be merged. + */ protected void merge(List states) { newState = getInitialState(); - newState.meetAliases(states); mergeEffects.clear(); afterMergeEffects.clear(); } @@ -213,4 +219,18 @@ protected void commitEnds(List states) { } } + + public void addScalarAlias(ValueNode node, ValueNode alias) { + assert !(alias instanceof VirtualObjectNode); + aliases.set(node, alias); + } + + public ValueNode getScalarAlias(ValueNode node) { + assert !(node instanceof VirtualObjectNode); + if (node == null || !node.isAlive() || aliases.isNew(node)) { + return node; + } + ValueNode result = aliases.get(node); + return (result == null || result instanceof VirtualObjectNode) ? node : result; + } } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Wed Oct 02 21:40:29 2013 +0200 @@ -24,7 +24,6 @@ import java.util.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -35,9 +34,6 @@ public class GraphEffectList extends EffectList { public void addCounterBefore(final String group, final String name, final int increment, final boolean addContext, final FixedNode position) { - if (!DynamicCounterNode.enabled) { - return; - } add(new Effect() { @Override @@ -48,16 +44,12 @@ @Override public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { assert position.isAlive(); - DynamicCounterNode node = graph.add(new DynamicCounterNode(group, name, increment, addContext)); - graph.addBeforeFixed(position, node); + DynamicCounterNode.addCounterBefore(group, name, increment, addContext, position); } }); } public void addSurvivingCounterBefore(final String group, final String name, final int increment, final boolean addContext, final ValueNode checkedValue, final FixedNode position) { - if (!DynamicCounterNode.enabled) { - return; - } add(new Effect() { @Override @@ -68,8 +60,7 @@ @Override public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { assert position.isAlive(); - DynamicCounterNode node = graph.add(new SurvivingCounterNode(group, name, increment, addContext, checkedValue)); - graph.addBeforeFixed(position, node); + SurvivingCounterNode.addCounterBefore(group, name, increment, addContext, checkedValue, position); } }); } @@ -368,24 +359,4 @@ } }); } - - public void addLowLevelCounterBefore(final String group, final String name, final int increment, final boolean addContext, final FixedNode position, final MetaAccessProvider runtime) { - add(new Effect() { - - @Override - public String name() { - return "addLowLevelCounterBefore"; - } - - @Override - public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { - DynamicCounterNode.addLowLevel(group, name, increment, addContext, position, runtime); - } - - @Override - public boolean isVisible() { - return true; - } - }); - } } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Wed Oct 02 21:40:29 2013 +0200 @@ -137,7 +137,7 @@ } public void escape(ValueNode materialized, EscapeState newState) { - assert state == EscapeState.Virtual || (state == EscapeState.ThreadLocal && newState == EscapeState.Global); + assert state == EscapeState.Virtual && newState == EscapeState.Materialized; state = newState; materializedValue = materialized; entries = null; @@ -146,7 +146,7 @@ @Override public ValueNode getMaterializedValue() { - assert state == EscapeState.ThreadLocal || state == EscapeState.Global; + assert state == EscapeState.Materialized; return materializedValue; } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Wed Oct 02 21:40:29 2013 +0200 @@ -92,9 +92,9 @@ return super.equivalentTo(other); } - public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) { + public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value, PartialEscapeClosure closure) { ValueNode cacheObject; - ObjectState obj = getObjectState(object); + ObjectState obj = closure.getObjectState(this, object); if (obj != null) { assert !obj.isVirtual(); cacheObject = obj.getMaterializedValue(); @@ -104,9 +104,9 @@ readCache.put(new ReadCacheEntry(identity, cacheObject), value); } - public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) { + public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity, PartialEscapeClosure closure) { ValueNode cacheObject; - ObjectState obj = getObjectState(object); + ObjectState obj = closure.getObjectState(this, object); if (obj != null) { assert !obj.isVirtual(); cacheObject = obj.getMaterializedValue(); @@ -114,13 +114,13 @@ cacheObject = object; } ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject)); - obj = getObjectState(cacheValue); + obj = closure.getObjectState(this, cacheValue); if (obj != null) { assert !obj.isVirtual(); cacheValue = obj.getMaterializedValue(); } else { // assert !scalarAliases.containsKey(cacheValue); - cacheValue = getScalarAlias(cacheValue); + cacheValue = closure.getScalarAlias(cacheValue); } return cacheValue; } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Wed Oct 02 21:40:29 2013 +0200 @@ -57,13 +57,13 @@ LoadFieldNode load = (LoadFieldNode) node; if (!load.isVolatile()) { ValueNode object = GraphUtil.unproxify(load.object()); - ValueNode cachedValue = state.getReadCache(object, load.field()); + ValueNode cachedValue = state.getReadCache(object, load.field(), this); if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue); - state.addScalarAlias(load, cachedValue); + addScalarAlias(load, cachedValue); deleted = true; } else { - state.addReadCache(object, load.field(), load); + state.addReadCache(object, load.field(), load, this); } } else { processIdentity(state, ANY_LOCATION); @@ -72,15 +72,15 @@ StoreFieldNode store = (StoreFieldNode) node; if (!store.isVolatile()) { ValueNode object = GraphUtil.unproxify(store.object()); - ValueNode cachedValue = state.getReadCache(object, store.field()); + ValueNode cachedValue = state.getReadCache(object, store.field(), this); - ValueNode value = state.getScalarAlias(store.value()); + ValueNode value = getScalarAlias(store.value()); if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { effects.deleteFixedNode(store); deleted = true; } state.killReadCache(store.field()); - state.addReadCache(object, store.field(), value); + state.addReadCache(object, store.field(), value, this); } else { processIdentity(state, ANY_LOCATION); } @@ -112,7 +112,7 @@ for (Map.Entry entry : exitState.getReadCache().entrySet()) { if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) { - ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity); + ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, this); if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) { ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null); effects.addFloatingNode(proxy, "readCacheProxy"); @@ -165,7 +165,7 @@ PhiNode phiNode = getCachedPhi(entry, value.kind()); mergeEffects.addFloatingNode(phiNode, "mergeReadCache"); for (int i = 0; i < states.size(); i++) { - afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity)); + afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity, PEReadEliminationClosure.this)); } newState.readCache.put(key, phiNode); } else if (value != null) { @@ -187,7 +187,7 @@ private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List states) { ValueNode[] values = new ValueNode[phi.valueCount()]; for (int i = 0; i < phi.valueCount(); i++) { - ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity); + ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, PEReadEliminationClosure.this); if (value == null) { return; } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Wed Oct 02 21:40:29 2013 +0200 @@ -24,7 +24,6 @@ import java.util.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; @@ -32,7 +31,6 @@ public abstract class PartialEscapeBlockState> extends EffectsBlockState { protected final IdentityHashMap objectStates = new IdentityHashMap<>(); - protected final IdentityHashMap objectAliases; /** * Final subclass of PartialEscapeBlockState, for performance and to make everything behave @@ -49,15 +47,12 @@ } protected PartialEscapeBlockState() { - objectAliases = new IdentityHashMap<>(); } protected PartialEscapeBlockState(PartialEscapeBlockState other) { - super(other); for (Map.Entry entry : other.objectStates.entrySet()) { objectStates.put(entry.getKey(), entry.getValue().cloneState()); } - objectAliases = new IdentityHashMap<>(other.objectAliases); } public ObjectState getObjectState(VirtualObjectNode object) { @@ -69,11 +64,6 @@ return objectStates.get(object); } - public ObjectState getObjectState(ValueNode value) { - VirtualObjectNode object = objectAliases.get(value); - return object == null ? null : getObjectState(object); - } - public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) { PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment(); List objects = new ArrayList<>(2); @@ -100,8 +90,8 @@ values.add(null); } for (int i = 0; i < entries.length; i++) { - ObjectState entryObj = getObjectState(entries[i]); - if (entryObj != null) { + if (entries[i] instanceof VirtualObjectNode) { + ObjectState entryObj = getObjectState((VirtualObjectNode) entries[i]); if (entryObj.isVirtual()) { materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state); } @@ -122,26 +112,6 @@ VirtualUtil.trace("materialized %s as %s with values %s", virtual, representation, values); } - void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, NodeBitMap usages) { - objectAliases.put(node, virtual); - if (node.isAlive()) { - for (Node usage : node.usages()) { - markVirtualUsages(usage, usages); - } - } - } - - private void markVirtualUsages(Node node, NodeBitMap usages) { - if (!usages.isNew(node)) { - usages.mark(node); - } - if (node instanceof VirtualState) { - for (Node usage : node.usages()) { - markVirtualUsages(usage, usages); - } - } - } - public void addObject(VirtualObjectNode virtual, ObjectState state) { objectStates.put(virtual, state); } @@ -150,30 +120,18 @@ return objectStates.values(); } - public Collection getVirtualObjects() { - return objectAliases.values(); + public Set getVirtualObjects() { + return objectStates.keySet(); } @Override public String toString() { - return super.toString() + ", Object Aliases: " + objectAliases + ", Object States: " + objectStates; - } - - @Override - public void meetAliases(List states) { - super.meetAliases(states); - objectAliases.putAll(states.get(0).objectAliases); - for (int i = 1; i < states.size(); i++) { - meetMaps(objectAliases, states.get(i).objectAliases); - } + return super.toString() + ", Object States: " + objectStates; } @Override public boolean equivalentTo(T other) { - if (!compareMaps(objectAliases, other.objectAliases) || !compareMaps(objectStates, other.objectStates)) { - return false; - } - return super.equivalentTo(other); + return compareMaps(objectStates, other.objectStates); } protected static boolean compareMaps(Map left, Map right) { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Oct 02 21:40:29 2013 +0200 @@ -79,7 +79,7 @@ public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) { super(schedule); this.usages = schedule.getCFG().graph.createNodeBitMap(); - this.tool = new VirtualizerToolImpl(usages, metaAccess, assumptions); + this.tool = new VirtualizerToolImpl(metaAccess, assumptions, this); } public Map getHints() { @@ -129,7 +129,7 @@ @Override public void apply(Node usage, ValueNode value) { - ObjectState valueObj = state.getObjectState(value); + ObjectState valueObj = getObjectState(state, value); if (valueObj != null) { virtual.add(valueObj); effects.replaceFirstInput(usage, value, valueObj.virtual); @@ -158,8 +158,8 @@ ObjectState obj = queue.removeLast(); if (obj.isVirtual()) { for (ValueNode field : obj.getEntries()) { - ObjectState fieldObj = state.getObjectState(field); - if (fieldObj != null) { + if (field instanceof VirtualObjectNode) { + ObjectState fieldObj = state.getObjectState((VirtualObjectNode) field); if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) { virtual.add(fieldObj); queue.addLast(fieldObj); @@ -173,7 +173,7 @@ if (obj.isVirtual()) { ValueNode[] fieldState = obj.getEntries().clone(); for (int i = 0; i < fieldState.length; i++) { - ObjectState valueObj = state.getObjectState(fieldState[i]); + ObjectState valueObj = getObjectState(state, fieldState[i]); if (valueObj != null) { if (valueObj.isVirtual()) { fieldState[i] = valueObj.virtual; @@ -191,7 +191,7 @@ } } for (ValueNode input : node.inputs().filter(ValueNode.class)) { - ObjectState obj = state.getObjectState(input); + ObjectState obj = getObjectState(state, input); if (obj != null) { if (obj.isVirtual() && node instanceof MethodCallTargetNode) { Invoke invoke = ((MethodCallTargetNode) node).invoke(); @@ -205,18 +205,18 @@ return false; } - private static void ensureMaterialized(PartialEscapeBlockState state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) { + private void ensureMaterialized(BlockT state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) { assert obj != null; if (obj.getState() == EscapeState.Virtual) { metric.increment(); - state.materializeBefore(materializeBefore, obj.virtual, EscapeState.Global, effects); + state.materializeBefore(materializeBefore, obj.virtual, EscapeState.Materialized, effects); } else { - assert obj.getState() == EscapeState.Global; + assert obj.getState() == EscapeState.Materialized; } assert !obj.isVirtual(); } - private static void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, PartialEscapeBlockState state, ObjectState obj, GraphEffectList effects, DebugMetric metric) { + private void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockT state, ObjectState obj, GraphEffectList effects, DebugMetric metric) { ensureMaterialized(state, obj, materializeBefore, effects, metric); effects.replaceFirstInput(usage, value, obj.getMaterializedValue()); } @@ -226,7 +226,7 @@ HashMap proxies = new HashMap<>(); for (ProxyNode proxy : exitNode.proxies()) { - ObjectState obj = exitState.getObjectState(proxy.value()); + ObjectState obj = getObjectState(exitState, proxy.value()); if (obj != null) { proxies.put(obj.virtual, proxy); } @@ -236,8 +236,7 @@ if (obj.isVirtual()) { for (int i = 0; i < obj.getEntries().length; i++) { ValueNode value = obj.getEntry(i); - ObjectState valueObj = exitState.getObjectState(value); - if (valueObj == null) { + if (!(value instanceof VirtualObjectNode)) { if (exitNode.loopBegin().isPhiAtMerge(value) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) { ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null); obj.setEntry(i, proxy); @@ -327,16 +326,21 @@ * and so on. */ - HashSet virtualObjects = new HashSet<>(newState.getVirtualObjects()); + HashSet virtualObjTemp = new HashSet<>(states.get(0).getVirtualObjects()); + for (int i = 1; i < states.size(); i++) { + virtualObjTemp.retainAll(states.get(i).getVirtualObjects()); + } + boolean materialized; do { mergeEffects.clear(); afterMergeEffects.clear(); materialized = false; - for (VirtualObjectNode object : virtualObjects) { + for (VirtualObjectNode object : virtualObjTemp) { ObjectState[] objStates = new ObjectState[states.size()]; for (int i = 0; i < states.size(); i++) { - objStates[i] = states.get(i).getObjectState(object); + objStates[i] = states.get(i).getObjectStateOptional(object); + assert objStates[i] != null; } int virtual = 0; ObjectState startObj = objStates[0]; @@ -359,16 +363,16 @@ PhiNode materializedValuePhi = getCachedPhi(object, Kind.Object); mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi"); for (int i = 0; i < states.size(); i++) { - PartialEscapeBlockState state = states.get(i); + BlockT state = states.get(i); ObjectState obj = objStates[i]; materialized |= obj.isVirtual(); Block predecessor = mergeBlock.getPredecessors().get(i); ensureMaterialized(state, obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); afterMergeEffects.addPhiInput(materializedValuePhi, obj.getMaterializedValue()); } - newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Global, null)); + newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null)); } else { - newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Global, null)); + newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Materialized, null)); } } else { assert virtual == states.size(); @@ -396,8 +400,8 @@ break outer; } ValueNode[] fields = objStates[i].getEntries(); - ObjectState obj = states.get(i).getObjectState(fields[index]); - if (obj != null) { + if (fields[index] instanceof VirtualObjectNode) { + ObjectState obj = states.get(i).getObjectState((VirtualObjectNode) fields[index]); materialized |= obj.isVirtual(); Block predecessor = mergeBlock.getPredecessors().get(i); ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); @@ -421,6 +425,7 @@ } private boolean processPhi(PhiNode phi, List states) { + aliases.set(phi, null); assert states.size() == phi.valueCount(); int virtualInputs = 0; boolean materialized = false; @@ -430,7 +435,7 @@ boolean hasIdentity = false; for (int i = 0; i < phi.valueCount(); i++) { ValueNode value = phi.valueAt(i); - ObjectState obj = states.get(i).getObjectState(value); + ObjectState obj = getObjectState(states.get(i), value); if (obj != null) { if (obj.isVirtual()) { virtualInputs++; @@ -460,10 +465,10 @@ // nothing to do... } else if (virtualInputs == phi.valueCount()) { if (sameObject != null) { - newState.addAndMarkAlias(sameObject, phi, usages); + addAndMarkAlias(sameObject, phi); } else if (sameType != null && sameEntryCount != -1) { if (!hasIdentity) { - VirtualObjectNode virtual = getValueObjectVirtual(phi, states.get(0).getObjectState(phi.valueAt(0)).virtual); + VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual); PhiNode[] phis = getValueObjectMergePhis(phi, virtual.entryCount()); for (int i = 0; i < virtual.entryCount(); i++) { @@ -473,13 +478,13 @@ } mergeEffects.addFloatingNode(phis[i], "valueObjectPhi"); for (int i2 = 0; i2 < phi.valueCount(); i2++) { - afterMergeEffects.addPhiInput(phis[i], states.get(i2).getObjectState(phi.valueAt(i2)).getEntry(i)); + afterMergeEffects.addPhiInput(phis[i], getObjectState(states.get(i2), phi.valueAt(i2)).getEntry(i)); } } mergeEffects.addFloatingNode(virtual, "valueObjectNode"); newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, null)); - newState.addAndMarkAlias(virtual, virtual, usages); - newState.addAndMarkAlias(virtual, phi, usages); + addAndMarkAlias(virtual, virtual); + addAndMarkAlias(virtual, phi); } else { materialize = true; } @@ -493,7 +498,7 @@ if (materialize) { for (int i = 0; i < phi.valueCount(); i++) { ValueNode value = phi.valueAt(i); - ObjectState obj = states.get(i).getObjectState(value); + ObjectState obj = getObjectState(states.get(i), value); if (obj != null) { materialized |= obj.isVirtual(); Block predecessor = mergeBlock.getPredecessors().get(i); @@ -504,4 +509,39 @@ return materialized; } } + + public ObjectState getObjectState(PartialEscapeBlockState state, ValueNode value) { + if (value == null) { + return null; + } + if (value.isAlive() && !aliases.isNew(value)) { + ValueNode object = aliases.get(value); + return object instanceof VirtualObjectNode ? state.getObjectStateOptional((VirtualObjectNode) object) : null; + } else { + if (value instanceof VirtualObjectNode) { + return state.getObjectStateOptional((VirtualObjectNode) value); + } + return null; + } + } + + void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node) { + if (node.isAlive()) { + aliases.set(node, virtual); + for (Node usage : node.usages()) { + markVirtualUsages(usage); + } + } + } + + private void markVirtualUsages(Node node) { + if (!usages.isNew(node)) { + usages.mark(node); + } + if (node instanceof VirtualState) { + for (Node usage : node.usages()) { + markVirtualUsages(usage); + } + } + } } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java Wed Oct 02 21:40:29 2013 +0200 @@ -103,7 +103,6 @@ } public ReadEliminationBlockState(ReadEliminationBlockState other) { - super(other); readCache = new HashMap<>(other.readCache); } @@ -114,10 +113,7 @@ @Override public boolean equivalentTo(ReadEliminationBlockState other) { - if (!compareMapsNoSize(readCache, other.readCache)) { - return false; - } - return super.equivalentTo(other); + return compareMapsNoSize(readCache, other.readCache); } public void addCacheEntry(CacheEntry identifier, ValueNode value) { diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Wed Oct 02 21:40:29 2013 +0200 @@ -61,7 +61,7 @@ ValueNode cachedValue = state.getCacheEntry(identifier); if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue); - state.addScalarAlias(load, cachedValue); + addScalarAlias(load, cachedValue); deleted = true; } else { state.addCacheEntry(identifier, load); @@ -76,7 +76,7 @@ LoadCacheEntry identifier = new LoadCacheEntry(object, store.field()); ValueNode cachedValue = state.getCacheEntry(identifier); - ValueNode value = state.getScalarAlias(store.value()); + ValueNode value = getScalarAlias(store.value()); if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { effects.deleteFixedNode(store); deleted = true; @@ -94,7 +94,7 @@ ValueNode cachedValue = state.getCacheEntry(identifier); if (cachedValue != null) { effects.replaceAtUsages(read, cachedValue); - state.addScalarAlias(read, cachedValue); + addScalarAlias(read, cachedValue); deleted = true; } else { state.addCacheEntry(identifier, read); @@ -107,7 +107,7 @@ ReadCacheEntry identifier = new ReadCacheEntry(object, write.location()); ValueNode cachedValue = state.getCacheEntry(identifier); - ValueNode value = state.getScalarAlias(write.value()); + ValueNode value = getScalarAlias(write.value()); if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { effects.deleteFixedNode(write); deleted = true; diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Wed Oct 02 21:40:29 2013 +0200 @@ -36,18 +36,18 @@ class VirtualizerToolImpl implements VirtualizerTool { - private final NodeBitMap usages; private final MetaAccessProvider metaAccess; private final Assumptions assumptions; + private final PartialEscapeClosure closure; - VirtualizerToolImpl(NodeBitMap usages, MetaAccessProvider metaAccess, Assumptions assumptions) { - this.usages = usages; + VirtualizerToolImpl(MetaAccessProvider metaAccess, Assumptions assumptions, PartialEscapeClosure closure) { this.metaAccess = metaAccess; this.assumptions = assumptions; + this.closure = closure; } private boolean deleted; - private PartialEscapeBlockState state; + private PartialEscapeBlockState state; private ValueNode current; private FixedNode position; private GraphEffectList effects; @@ -76,15 +76,15 @@ @Override public State getObjectState(ValueNode value) { - return state.getObjectState(value); + return closure.getObjectState(state, value); } @Override public void setVirtualEntry(State objectState, int index, ValueNode value) { ObjectState obj = (ObjectState) objectState; assert obj != null && obj.isVirtual() : "not virtual: " + obj; - ObjectState valueState = state.getObjectState(value); - ValueNode newValue = value; + ObjectState valueState = closure.getObjectState(state, value); + ValueNode newValue; if (valueState == null) { newValue = getReplacedValue(value); assert obj.getEntry(index) == null || obj.getEntry(index).kind() == newValue.kind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue)); @@ -105,19 +105,13 @@ } @Override - public ValueNode getMaterializedValue(ValueNode value) { - ObjectState obj = state.getObjectState(value); - return obj != null && !obj.isVirtual() ? obj.getMaterializedValue() : null; - } - - @Override public ValueNode getReplacedValue(ValueNode original) { - return state.getScalarAlias(original); + return closure.getScalarAlias(original); } @Override public void replaceWithVirtual(VirtualObjectNode virtual) { - state.addAndMarkAlias(virtual, current, usages); + closure.addAndMarkAlias(virtual, current); if (current instanceof FixedWithNextNode) { effects.deleteFixedNode((FixedWithNextNode) current); } @@ -126,8 +120,8 @@ @Override public void replaceWithValue(ValueNode replacement) { - effects.replaceAtUsages(current, state.getScalarAlias(replacement)); - state.addScalarAlias(current, replacement); + effects.replaceAtUsages(current, closure.getScalarAlias(replacement)); + closure.addScalarAlias(current, replacement); deleted = true; } @@ -154,16 +148,21 @@ @Override public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks) { VirtualUtil.trace("{{%s}} ", current); - if (virtualObject.isAlive()) { - state.addAndMarkAlias(virtualObject, virtualObject, usages); - } else { + if (!virtualObject.isAlive()) { effects.addFloatingNode(virtualObject, "newVirtualObject"); } for (int i = 0; i < entryState.length; i++) { - entryState[i] = state.getScalarAlias(entryState[i]); + if (!(entryState[i] instanceof VirtualObjectNode)) { + ObjectState v = closure.getObjectState(state, entryState[i]); + if (v != null) { + entryState[i] = v.isVirtual() ? v.getVirtualObject() : v.getMaterializedValue(); + } else { + entryState[i] = closure.getScalarAlias(entryState[i]); + } + } } state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks)); - state.addAndMarkAlias(virtualObject, virtualObject, usages); + closure.addAndMarkAlias(virtualObject, virtualObject); PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment(); } diff -r 51059863da73 -r 673f93db4adc graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Oct 02 20:57:11 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Oct 02 21:40:29 2013 +0200 @@ -663,7 +663,7 @@ } final StringBuilder sb = new StringBuilder(); for (int i = 0; i < level; i++) { - sb.append(" "); + sb.append("| "); } if (parent != null) { diff -r 51059863da73 -r 673f93db4adc mx/commands.py --- a/mx/commands.py Wed Oct 02 20:57:11 2013 +0200 +++ b/mx/commands.py Wed Oct 02 21:40:29 2013 +0200 @@ -1318,6 +1318,14 @@ mx.abort('jacocoreport takes only one argument : an output directory') mx.run_java(['-jar', jacocoreport.get_path(True), '-in', 'jacoco.exec', '-g', join(_graal_home, 'graal'), out]) +def sl(args): + """run an SL program + + VM args should have a @ prefix.""" + vmArgs = [a[1:] for a in args if a[0] == '@'] + slArgs = [a for a in args if a[0] != '@'] + vm(vmArgs + ['-cp', mx.classpath("com.oracle.truffle.sl"), "com.oracle.truffle.sl.SimpleLanguage"] + slArgs) + def isGraalEnabled(vm): return vm != 'original' and not vm.endswith('nograal') @@ -1361,7 +1369,8 @@ 'vmg': [vmg, '[-options] class [args...]'], 'vmfg': [vmfg, '[-options] class [args...]'], 'deoptalot' : [deoptalot, '[n]'], - 'longtests' : [longtests, ''] + 'longtests' : [longtests, ''], + 'sl' : [sl, '[SL args|@VM options]'] } mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append']) diff -r 51059863da73 -r 673f93db4adc src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Wed Oct 02 20:57:11 2013 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Wed Oct 02 21:40:29 2013 +0200 @@ -202,6 +202,7 @@ do_klass(HotSpotResolvedObjectType_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType, Opt) \ do_klass(HotSpotMonitorValue_klass, com_oracle_graal_hotspot_meta_HotSpotMonitorValue, Opt) \ do_klass(LocalImpl_klass, com_oracle_graal_hotspot_debug_LocalImpl, Opt) \ + do_klass(CompilerThread_klass, com_oracle_graal_hotspot_CompilerThread, Opt) \ /* graal.api.code */ \ do_klass(Assumptions_klass, com_oracle_graal_api_code_Assumptions, Opt) \ do_klass(Assumptions_ConcreteMethod_klass, com_oracle_graal_api_code_Assumptions_ConcreteMethod, Opt) \ diff -r 51059863da73 -r 673f93db4adc src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Wed Oct 02 20:57:11 2013 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Wed Oct 02 21:40:29 2013 +0200 @@ -311,6 +311,7 @@ template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType, "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType") \ template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue, "com/oracle/graal/hotspot/meta/HotSpotMonitorValue") \ template(com_oracle_graal_hotspot_debug_LocalImpl, "com/oracle/graal/hotspot/debug/LocalImpl") \ + template(com_oracle_graal_hotspot_CompilerThread, "com/oracle/graal/hotspot/CompilerThread") \ template(com_oracle_graal_hotspot_ptx_PTXHotSpotGraalRuntime, "com/oracle/graal/hotspot/ptx/PTXHotSpotGraalRuntime")\ AMD64_ONLY(template(com_oracle_graal_hotspot_amd64_AMD64HotSpotGraalRuntime,"com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime"))\ SPARC_ONLY(template(com_oracle_graal_hotspot_sparc_SPARCHotSpotGraalRuntime,"com/oracle/graal/hotspot/sparc/SPARCHotSpotGraalRuntime"))\ diff -r 51059863da73 -r 673f93db4adc src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Oct 02 20:57:11 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Oct 02 21:40:29 2013 +0200 @@ -875,6 +875,9 @@ set_int("arrayClassElementOffset", in_bytes(ObjArrayKlass::element_klass_offset())); + set_int("graalCountersThreadOffset", in_bytes(JavaThread::graal_counters_offset())); + set_int("graalCountersSize", (jint) GRAAL_COUNTERS_SIZE); + #undef set_boolean #undef set_int #undef set_long @@ -1145,6 +1148,12 @@ return klass; C2V_END +C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv *env, jobject)) + typeArrayOop arrayOop = oopFactory::new_longArray(GRAAL_COUNTERS_SIZE, CHECK_NULL); + JavaThread::collect_counters(arrayOop); + return (jlongArray) JNIHandles::make_local(arrayOop); +C2V_END + #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) @@ -1224,6 +1233,7 @@ {CC"invalidateInstalledCode", CC"("HS_INSTALLED_CODE")V", FN_PTR(invalidateInstalledCode)}, {CC"readUnsafeUncompressedPointer", CC"("OBJECT"J)"OBJECT, FN_PTR(readUnsafeUncompressedPointer)}, {CC"readUnsafeKlassPointer", CC"("OBJECT")J", FN_PTR(readUnsafeKlassPointer)}, + {CC"collectCounters", CC"()[J", FN_PTR(collectCounters)}, }; int CompilerToVM_methods_count() { diff -r 51059863da73 -r 673f93db4adc src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Oct 02 20:57:11 2013 +0200 +++ b/src/share/vm/runtime/thread.cpp Wed Oct 02 21:40:29 2013 +0200 @@ -1411,6 +1411,36 @@ // ======= JavaThread ======== +#ifdef GRAAL + +#if GRAAL_COUNTERS_SIZE > 0 +jlong JavaThread::_graal_old_counters[GRAAL_COUNTERS_SIZE]; + +bool graal_counters_include(oop threadObj) { + return !GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS || threadObj == NULL || threadObj->klass() != SystemDictionary::CompilerThread_klass(); +} + +void JavaThread::collect_counters(typeArrayOop array) { + MutexLocker tl(Threads_lock); + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, _graal_old_counters[i]); + } + for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { + if (graal_counters_include(tp->threadObj())) { + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, array->long_at(i) + tp->_graal_counters[i]); + } + } + } +} +#else +void JavaThread::collect_counters(typeArrayOop array) { + // empty +} +#endif // GRAAL_COUNTERS_SIZE > 0 + +#endif // GRAAL + // A JavaThread is a normal Java thread void JavaThread::initialize() { @@ -1449,6 +1479,9 @@ _stack_guard_state = stack_guard_unused; #ifdef GRAAL _graal_alternate_call_target = NULL; + for (int i = 0; i < GRAAL_COUNTERS_SIZE; i++) { + _graal_counters[i] = 0; + } #endif _exception_oop = NULL; _exception_pc = 0; @@ -1638,6 +1671,14 @@ ThreadSafepointState::destroy(this); if (_thread_profiler != NULL) delete _thread_profiler; if (_thread_stat != NULL) delete _thread_stat; + +#if defined(GRAAL) && (GRAAL_COUNTERS_SIZE > 0) + if (graal_counters_include(threadObj())) { + for (int i = 0; i < GRAAL_COUNTERS_SIZE; i++) { + _graal_old_counters[i] += _graal_counters[i]; + } + } +#endif } diff -r 51059863da73 -r 673f93db4adc src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Wed Oct 02 20:57:11 2013 +0200 +++ b/src/share/vm/runtime/thread.hpp Wed Oct 02 21:40:29 2013 +0200 @@ -919,6 +919,17 @@ #ifdef GRAAL address _graal_alternate_call_target; address _graal_implicit_exception_pc; // pc at which the most recent implicit exception occurred + + // number of counters, increase as needed. 0 == disabled +#define GRAAL_COUNTERS_SIZE (0) +#define GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS (true) + + jlong _graal_counters[GRAAL_COUNTERS_SIZE]; + static jlong _graal_old_counters[GRAAL_COUNTERS_SIZE]; + + public: + static void collect_counters(typeArrayOop array); + private: #endif StackGuardState _stack_guard_state; @@ -1379,6 +1390,7 @@ #ifdef GRAAL static ByteSize graal_alternate_call_target_offset() { return byte_offset_of(JavaThread, _graal_alternate_call_target); } static ByteSize graal_implicit_exception_pc_offset() { return byte_offset_of(JavaThread, _graal_implicit_exception_pc); } + static ByteSize graal_counters_offset() { return byte_offset_of(JavaThread, _graal_counters ); } #endif static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop ); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc ); }