# HG changeset patch # User Christian Humer # Date 1380720805 -7200 # Node ID 9d1a5d61cc11a1cd4cf828a4f98114dbf0411e0e # Parent 96c1d057a5ed690d74837cc4b07192e1cc2ae71f# Parent cdff87c89c5f972832c69466d9d5ba7ba6b24294 Merge. diff -r 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:25 2013 +0200 @@ -0,0 +1,313 @@ +/* + * 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.*; + +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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Oct 02 15:33:25 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; @@ -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) { diff -r 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java Wed Oct 02 15:33:25 2013 +0200 @@ -35,7 +35,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; } @@ -55,4 +55,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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 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 15:33:08 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Wed Oct 02 15:33:08 2013 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Wed Oct 02 15:33:08 2013 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Oct 02 15:33:08 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Oct 02 15:33:08 2013 +0200 +++ b/src/share/vm/runtime/thread.cpp Wed Oct 02 15:33:25 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 96c1d057a5ed -r 9d1a5d61cc11 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Wed Oct 02 15:33:08 2013 +0200 +++ b/src/share/vm/runtime/thread.hpp Wed Oct 02 15:33:25 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 ); }