# HG changeset patch
# User Thomas Wuerthinger
# Date 1400665550 -7200
# Node ID a6eeb37502384dcfc3886467dc3c92c68bc6da51
# Parent a43ff5d18350adb4af26978fbcb7044451993dc1# Parent b5a993ed67ea44ac4227bb1ab93ca5d771980061
Merge.
diff -r a43ff5d18350 -r a6eeb3750238 CHANGELOG.md
--- a/CHANGELOG.md Tue May 13 19:19:27 2014 +0200
+++ b/CHANGELOG.md Wed May 21 11:45:50 2014 +0200
@@ -3,6 +3,9 @@
## `tip`
### Graal
* Made initialization of Graal runtime lazy in hosted mode.
+* Added supported for new 'jrelibrary' dependency type in mx/projects.
+* Java projects with compliance level higher than the JDKs specified by JAVA_HOME and EXTRA_JAVA_HOMES are ignored once mx/projects has been processed.
+* ResolvedJavaType.resolveMethod now takes a context type used to perform access checks. It now works correctly regarding default methods.
### Truffle
* `truffle.jar`: strip out build-time only dependency into a seperated JAR file (`truffle-dsl-processor.jar`)
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java Wed May 21 11:45:50 2014 +0200
@@ -96,7 +96,8 @@
public ConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) {
this.context = context;
this.subtype = subtype;
- assert !subtype.isInterface() : subtype.toString() + " : " + context.toString();
+ assert !subtype.isAbstract() : subtype.toString() + " : " + context.toString();
+ assert !subtype.isArray() || getElementalType(subtype).isFinal() : subtype.toString() + " : " + context.toString();
}
@Override
@@ -264,7 +265,7 @@
/**
* Returns whether any assumptions have been registered.
- *
+ *
* @return {@code true} if at least one assumption has been registered, {@code false} otherwise.
*/
public boolean isEmpty() {
@@ -303,7 +304,7 @@
/**
* Records an assumption that the specified type has no finalizable subclasses.
- *
+ *
* @param receiverType the type that is assumed to have no finalizable subclasses
*/
public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) {
@@ -314,7 +315,7 @@
/**
* Records that {@code subtype} is the only concrete subtype in the class hierarchy below
* {@code context}.
- *
+ *
* @param context the root of the subtree of the class hierarchy that this assumptions is about
* @param subtype the one concrete subtype
*/
@@ -326,7 +327,7 @@
/**
* Records that {@code impl} is the only possible concrete target for a virtual call to
* {@code method} with a receiver of type {@code context}.
- *
+ *
* @param method a method that is the target of a virtual call
* @param context the receiver type of a call to {@code method}
* @param impl the concrete method that is the only possible target for the virtual call
@@ -338,7 +339,7 @@
/**
* Records that {@code method} was used during the compilation.
- *
+ *
* @param method a method whose contents were used
*/
public void recordMethodContents(ResolvedJavaMethod method) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/ResolvedJavaTypeResolveMethodTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/ResolvedJavaTypeResolveMethodTest.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.api.meta.test;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.phases.util.*;
+import com.oracle.graal.runtime.*;
+
+public class ResolvedJavaTypeResolveMethodTest {
+ public final MetaAccessProvider metaAccess;
+
+ public ResolvedJavaTypeResolveMethodTest() {
+ Providers providers = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders();
+ metaAccess = providers.getMetaAccess();
+ }
+
+ protected static abstract class A {
+ @SuppressWarnings("unused")
+ private void priv() {
+ }
+
+ public void v1() {
+ }
+
+ public void v2() {
+ }
+
+ public abstract void abs();
+ }
+
+ protected static class B extends A implements I {
+ public void i() {
+ }
+
+ @Override
+ public void v2() {
+ }
+
+ @Override
+ public void abs() {
+
+ }
+ }
+
+ protected static class C extends B {
+ public void d() {
+ }
+ }
+
+ protected static abstract class D extends A {
+
+ }
+
+ protected static class E extends D {
+ @Override
+ public void abs() {
+ }
+ }
+
+ protected interface I {
+ void i();
+
+ default void d() {
+ }
+ }
+
+ @Test
+ public void testDefaultMethod() {
+ ResolvedJavaType i = getType(I.class);
+ ResolvedJavaType b = getType(B.class);
+ ResolvedJavaType c = getType(C.class);
+ ResolvedJavaMethod di = getMethod(i, "d");
+ ResolvedJavaMethod dc = getMethod(c, "d");
+
+ assertEquals(di, i.resolveMethod(di, c));
+ assertEquals(di, b.resolveMethod(di, c));
+ assertEquals(dc, c.resolveMethod(di, c));
+ }
+
+ @Test
+ public void testPrivateMethod() {
+ ResolvedJavaType a = getType(A.class);
+ ResolvedJavaType b = getType(B.class);
+ ResolvedJavaType c = getType(C.class);
+ ResolvedJavaMethod priv = getMethod(a, "priv");
+
+ assertNull(a.resolveMethod(priv, c));
+ assertNull(b.resolveMethod(priv, c));
+ }
+
+ @Test
+ public void testAbstractMethod() {
+ ResolvedJavaType a = getType(A.class);
+ ResolvedJavaType b = getType(B.class);
+ ResolvedJavaType c = getType(C.class);
+ ResolvedJavaType d = getType(D.class);
+ ResolvedJavaType e = getType(E.class);
+ ResolvedJavaMethod absa = getMethod(a, "abs");
+ ResolvedJavaMethod absb = getMethod(b, "abs");
+ ResolvedJavaMethod abse = getMethod(e, "abs");
+
+ assertNull(a.resolveMethod(absa, c));
+ assertNull(d.resolveMethod(absa, c));
+
+ assertEquals(absb, b.resolveMethod(absa, c));
+ assertEquals(absb, b.resolveMethod(absb, c));
+ assertEquals(absb, c.resolveMethod(absa, c));
+ assertEquals(absb, c.resolveMethod(absb, c));
+ assertEquals(abse, e.resolveMethod(absa, c));
+ assertNull(e.resolveMethod(absb, c));
+ assertEquals(abse, e.resolveMethod(abse, c));
+ }
+
+ @Test
+ public void testVirtualMethod() {
+ ResolvedJavaType a = getType(A.class);
+ ResolvedJavaType b = getType(B.class);
+ ResolvedJavaType c = getType(C.class);
+ ResolvedJavaMethod v1a = getMethod(a, "v1");
+ ResolvedJavaMethod v2a = getMethod(a, "v2");
+ ResolvedJavaMethod v2b = getMethod(b, "v2");
+
+ assertEquals(v1a, a.resolveMethod(v1a, c));
+ assertEquals(v1a, b.resolveMethod(v1a, c));
+ assertEquals(v1a, c.resolveMethod(v1a, c));
+ assertEquals(v2a, a.resolveMethod(v2a, c));
+ assertEquals(v2b, b.resolveMethod(v2a, c));
+ assertEquals(v2b, b.resolveMethod(v2b, c));
+ assertEquals(v2b, c.resolveMethod(v2a, c));
+ assertEquals(v2b, c.resolveMethod(v2b, c));
+
+ }
+
+ private static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) {
+ for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
+ if (method.getName().equals(methodName)) {
+ return method;
+ }
+ }
+ throw new IllegalArgumentException();
+ }
+
+ protected ResolvedJavaType getType(Class> clazz) {
+ ResolvedJavaType type = metaAccess.lookupJavaType(clazz);
+ type.initialize();
+ return type;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java Wed May 21 11:45:50 2014 +0200
@@ -164,6 +164,9 @@
public void testCoverage() {
Set known = new HashSet<>(Arrays.asList(untestedApiMethods));
for (Method m : ResolvedJavaField.class.getDeclaredMethods()) {
+ if (m.isSynthetic()) {
+ continue;
+ }
if (findTestMethod(m) == null) {
assertTrue("test missing for " + m, known.contains(m.getName()));
} else {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java Wed May 21 11:45:50 2014 +0200
@@ -265,10 +265,13 @@
static class Concrete3 extends Concrete2 {
}
+ static final class Final1 extends Abstract1 {
+ }
+
abstract static class Abstract4 extends Concrete3 {
}
- void checkConcreteSubtype(ResolvedJavaType type, Class> expected) {
+ void checkConcreteSubtype(ResolvedJavaType type, ResolvedJavaType expected) {
ResolvedJavaType subtype = type.findUniqueConcreteSubtype();
if (subtype == null) {
// findUniqueConcreteSubtype() is conservative
@@ -276,7 +279,7 @@
if (expected == null) {
assertNull(subtype);
} else {
- assertTrue(subtype.equals(metaAccess.lookupJavaType(expected)));
+ assertTrue(subtype.equals(expected));
}
}
@@ -294,31 +297,44 @@
@Test
public void findUniqueConcreteSubtypeTest() {
ResolvedJavaType base = metaAccess.lookupJavaType(Base.class);
- checkConcreteSubtype(base, Base.class);
+ checkConcreteSubtype(base, base);
ResolvedJavaType a1 = metaAccess.lookupJavaType(Abstract1.class);
ResolvedJavaType c1 = metaAccess.lookupJavaType(Concrete1.class);
checkConcreteSubtype(base, null);
- checkConcreteSubtype(a1, Concrete1.class);
- checkConcreteSubtype(c1, Concrete1.class);
+ checkConcreteSubtype(a1, c1);
+ checkConcreteSubtype(c1, c1);
ResolvedJavaType i1 = metaAccess.lookupJavaType(Interface1.class);
ResolvedJavaType c2 = metaAccess.lookupJavaType(Concrete2.class);
checkConcreteSubtype(base, null);
checkConcreteSubtype(a1, null);
- checkConcreteSubtype(c1, Concrete1.class);
- checkConcreteSubtype(i1, Concrete2.class);
- checkConcreteSubtype(c2, Concrete2.class);
+ checkConcreteSubtype(c1, c1);
+ checkConcreteSubtype(i1, c2);
+ checkConcreteSubtype(c2, c2);
ResolvedJavaType c3 = metaAccess.lookupJavaType(Concrete3.class);
checkConcreteSubtype(c2, null);
- checkConcreteSubtype(c3, Concrete3.class);
+ checkConcreteSubtype(c3, c3);
ResolvedJavaType a4 = metaAccess.lookupJavaType(Abstract4.class);
checkConcreteSubtype(c3, null);
checkConcreteSubtype(a4, null);
+
+ ResolvedJavaType a1a = metaAccess.lookupJavaType(Abstract1[].class);
+ checkConcreteSubtype(a1a, null);
+ ResolvedJavaType c1a = metaAccess.lookupJavaType(Concrete1[].class);
+ checkConcreteSubtype(c1a, null);
+ ResolvedJavaType f1a = metaAccess.lookupJavaType(Final1[].class);
+ checkConcreteSubtype(f1a, f1a);
+
+ ResolvedJavaType obja = metaAccess.lookupJavaType(Object[].class);
+ checkConcreteSubtype(obja, null);
+
+ ResolvedJavaType inta = metaAccess.lookupJavaType(int[].class);
+ checkConcreteSubtype(inta, inta);
}
@Test
@@ -431,20 +447,21 @@
return declarations;
}
- private static void checkResolveMethod(ResolvedJavaType type, ResolvedJavaMethod decl, ResolvedJavaMethod expected) {
- ResolvedJavaMethod impl = type.resolveMethod(decl);
+ private static void checkResolveMethod(ResolvedJavaType type, ResolvedJavaType context, ResolvedJavaMethod decl, ResolvedJavaMethod expected) {
+ ResolvedJavaMethod impl = type.resolveMethod(decl, context);
assertEquals(expected, impl);
}
@Test
public void resolveMethodTest() {
+ ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class);
for (Class> c : classes) {
if (c.isInterface() || c.isPrimitive()) {
ResolvedJavaType type = metaAccess.lookupJavaType(c);
for (Method m : c.getDeclaredMethods()) {
if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) {
ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m);
- ResolvedJavaMethod impl = type.resolveMethod(resolved);
+ ResolvedJavaMethod impl = type.resolveMethod(resolved, context);
ResolvedJavaMethod expected = resolved.isDefault() ? resolved : null;
assertEquals(m.toString(), expected, impl);
} else {
@@ -458,12 +475,14 @@
Set decls = findDeclarations(impl, c);
for (Method decl : decls) {
ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl);
- ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
- checkResolveMethod(type, m, i);
+ if (m.isPublic()) {
+ ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
+ checkResolveMethod(type, context, m, i);
+ }
}
}
for (Method m : c.getDeclaredMethods()) {
- ResolvedJavaMethod impl = type.resolveMethod(metaAccess.lookupJavaMethod(m));
+ ResolvedJavaMethod impl = type.resolveMethod(metaAccess.lookupJavaMethod(m), context);
ResolvedJavaMethod expected = isAbstract(m.getModifiers()) ? null : impl;
assertEquals(type + " " + m.toString(), expected, impl);
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Wed May 21 11:45:50 2014 +0200
@@ -218,9 +218,10 @@
Constant getEncoding();
/**
- * Checks if this method is present in the virtual table.
+ * Checks if this method is present in the virtual table for subtypes of the specified
+ * {@linkplain ResolvedJavaType type}.
*
- * @return true is this method is present in the virtual table
+ * @return true is this method is present in the virtual table for subtypes of this type.
*/
- boolean isInVirtualMethodTable();
+ boolean isInVirtualMethodTable(ResolvedJavaType resolved);
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Wed May 21 11:45:50 2014 +0200
@@ -211,10 +211,11 @@
* {@link #findUniqueConcreteMethod(ResolvedJavaMethod)}.
*
* @param method the method to select the implementation of
+ * @param callerType the caller or context type used to perform access checks
* @return the concrete method that would be selected at runtime, or {@code null} if there is no
* concrete implementation of {@code method} in this type or any of its superclasses
*/
- ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method);
+ ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType);
/**
* Given a {@link ResolvedJavaMethod} A, returns a concrete {@link ResolvedJavaMethod} B that is
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Wed May 21 11:45:50 2014 +0200
@@ -784,15 +784,39 @@
}
public final void idivl(Register src) {
- int encode = prefixAndEncode(src.encoding);
+ int encode = prefixAndEncode(7, src.encoding);
emitByte(0xF7);
- emitByte(0xF8 | encode);
+ emitByte(0xC0 | encode);
}
public final void divl(Register src) {
- int encode = prefixAndEncode(src.encoding);
+ int encode = prefixAndEncode(6, src.encoding);
+ emitByte(0xF7);
+ emitByte(0xC0 | encode);
+ }
+
+ public final void mull(Register src) {
+ int encode = prefixAndEncode(4, src.encoding);
+ emitByte(0xF7);
+ emitByte(0xC0 | encode);
+ }
+
+ public final void mull(AMD64Address src) {
+ prefix(src);
emitByte(0xF7);
- emitByte(0xF0 | encode);
+ emitOperandHelper(4, src);
+ }
+
+ public final void imull(Register src) {
+ int encode = prefixAndEncode(5, src.encoding);
+ emitByte(0xF7);
+ emitByte(0xC0 | encode);
+ }
+
+ public final void imull(AMD64Address src) {
+ prefix(src);
+ emitByte(0xF7);
+ emitOperandHelper(5, src);
}
public final void imull(Register dst, Register src) {
@@ -2346,15 +2370,39 @@
}
public final void divq(Register src) {
- int encode = prefixqAndEncode(src.encoding);
+ int encode = prefixqAndEncode(6, src.encoding);
emitByte(0xF7);
- emitByte(0xF0 | encode);
+ emitByte(0xC0 | encode);
}
public final void idivq(Register src) {
- int encode = prefixqAndEncode(src.encoding);
+ int encode = prefixqAndEncode(7, src.encoding);
+ emitByte(0xF7);
+ emitByte(0xC0 | encode);
+ }
+
+ public final void mulq(Register src) {
+ int encode = prefixqAndEncode(4, src.encoding);
+ emitByte(0xF7);
+ emitByte(0xC0 | encode);
+ }
+
+ public final void mulq(AMD64Address src) {
+ prefixq(src);
emitByte(0xF7);
- emitByte(0xF8 | encode);
+ emitOperandHelper(4, src);
+ }
+
+ public final void imulq(Register src) {
+ int encode = prefixqAndEncode(5, src.encoding);
+ emitByte(0xF7);
+ emitByte(0xC0 | encode);
+ }
+
+ public final void imulq(AMD64Address src) {
+ prefixq(src);
+ emitByte(0xF7);
+ emitOperandHelper(5, src);
}
public final void imulq(Register dst, Register src) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Wed May 21 11:45:50 2014 +0200
@@ -601,6 +601,37 @@
}
}
+ private Value emitMulHigh(AMD64Arithmetic opcode, Value a, Value b) {
+ MulHighOp mulHigh = new MulHighOp(opcode, asAllocatable(b));
+ emitMove(mulHigh.x, a);
+ append(mulHigh);
+ return emitMove(mulHigh.highResult);
+ }
+
+ @Override
+ public Value emitMulHigh(Value a, Value b) {
+ switch (a.getKind().getStackKind()) {
+ case Int:
+ return emitMulHigh(IMUL, a, b);
+ case Long:
+ return emitMulHigh(LMUL, a, b);
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ }
+
+ @Override
+ public Value emitUMulHigh(Value a, Value b) {
+ switch (a.getKind().getStackKind()) {
+ case Int:
+ return emitMulHigh(IUMUL, a, b);
+ case Long:
+ return emitMulHigh(LUMUL, a, b);
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ }
+
public Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
Variable result = newVariable(a.getKind());
append(new BinaryMemory(op, kind, result, a, location, state));
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java Wed May 21 11:45:50 2014 +0200
@@ -107,6 +107,11 @@
return StampFactory.illegal(Kind.Illegal);
}
ObjectStamp other = (ObjectStamp) otherStamp;
+ if (!isLegal()) {
+ return other;
+ } else if (!other.isLegal()) {
+ return this;
+ }
ResolvedJavaType meetType;
boolean meetExactType;
boolean meetNonNull;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Wed May 21 11:45:50 2014 +0200
@@ -131,11 +131,18 @@
}
/**
+ * Determines if the JVM supports the required typeProfileWidth.
+ */
+ public boolean typeProfileWidthAtLeast(int val) {
+ return (getHSAILBackend().getRuntime().getConfig().typeProfileWidth >= val);
+ }
+
+ /**
* Determines if the runtime supports {@link VirtualObject}s in {@link DebugInfo} associated
* with HSAIL code.
*/
public boolean canHandleDeoptVirtualObjects() {
- return false;
+ return true;
}
/**
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java Wed May 21 11:45:50 2014 +0200
@@ -34,16 +34,19 @@
import java.util.logging.*;
import com.amd.okra.*;
+import com.oracle.graal.test.*;
/**
* Abstract class on which the HSAIL unit tests are built. Executes a method or lambda on both the
* Java side and the Okra side and compares the results for fields that are annotated with
- * {@link KernelTester.Result}.
+ * {@link Result}.
*/
-public abstract class KernelTester {
+public abstract class KernelTester extends GraalTest {
/**
- * Denotes a field whose value is to be compared as part of computing the result of a test.
+ * Denotes a field whose value is to be
+ * {@linkplain KernelTester#assertResultFieldsEqual(KernelTester) compared} as part of computing
+ * the result of a test.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@@ -129,171 +132,27 @@
public abstract void runTest();
- // Default comparison is to compare all things marked @Result.
- public boolean compareResults(KernelTester base) {
+ /**
+ * Asserts that the value of all {@link Result} annotated fields in this object and
+ * {@code other} are {@linkplain #assertDeepEquals(Object, Object) equal}.
+ *
+ * @throws AssertionError if the value of a result field in this and {@code other} are not equal
+ */
+ public void assertResultFieldsEqual(KernelTester other) {
Class> clazz = this.getClass();
while (clazz != null && clazz != KernelTester.class) {
for (Field f : clazz.getDeclaredFields()) {
if (!Modifier.isStatic(f.getModifiers())) {
Result annos = f.getAnnotation(Result.class);
if (annos != null) {
- logger.fine("@Result field = " + f);
- Object myResult = getFieldFromObject(f, this);
- Object otherResult = getFieldFromObject(f, base);
- boolean same = compareObjects(myResult, otherResult);
- logger.fine("comparing " + myResult + ", " + otherResult + ", match=" + same);
- if (!same) {
- logger.severe("mismatch comparing " + f + ", " + myResult + " vs. " + otherResult);
- logSevere("FAILED!!! " + this.getClass());
- return false;
- }
+ Object actualResult = getFieldFromObject(f, this);
+ Object expectedResult = getFieldFromObject(f, other);
+ assertDeepEquals(f.toString(), expectedResult, actualResult);
}
}
}
clazz = clazz.getSuperclass();
}
- logInfo("PASSED: " + this.getClass());
- return true;
- }
-
- private boolean compareObjects(Object first, Object second) {
- if (first == null) {
- return (second == null);
- }
- if (second == null) {
- return (first == null);
- }
- Class> clazz = first.getClass();
- if (clazz != second.getClass()) {
- return false;
- }
- if (!clazz.isArray()) {
- // Non arrays.
- if (clazz.equals(float.class) || clazz.equals(double.class)) {
- return isEqualsFP((double) first, (double) second);
- } else {
- return first.equals(second);
- }
- } else {
- // Handle the case where Objects are arrays.
- ArrayComparer comparer;
- if (clazz.equals(float[].class) || clazz.equals(double[].class)) {
- comparer = new FPArrayComparer();
- } else if (clazz.equals(long[].class) || clazz.equals(int[].class) || clazz.equals(byte[].class)) {
- comparer = new IntArrayComparer();
- } else if (clazz.equals(boolean[].class)) {
- comparer = new BooleanArrayComparer();
- } else {
- comparer = new ObjArrayComparer();
- }
- return comparer.compareArrays(first, second);
- }
- }
-
- static final int MISMATCHLIMIT = 10;
- static final int ELEMENTDISPLAYLIMIT = 20;
-
- public int getMisMatchLimit() {
- return MISMATCHLIMIT;
- }
-
- public int getElementDisplayLimit() {
- return ELEMENTDISPLAYLIMIT;
- }
-
- abstract class ArrayComparer {
-
- abstract Object getElement(Object ary, int index);
-
- // Equality test, can be overridden
- boolean isEquals(Object firstElement, Object secondElement) {
- return firstElement.equals(secondElement);
- }
-
- boolean compareArrays(Object first, Object second) {
- int len = Array.getLength(first);
- if (len != Array.getLength(second)) {
- return false;
- }
- // If info logLevel, build string of first few elements from first array.
- if (logLevel.intValue() <= Level.INFO.intValue()) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < Math.min(len, getElementDisplayLimit()); i++) {
- sb.append(getElement(first, i));
- sb.append(", ");
- }
- logger.info(sb.toString());
- }
- boolean success = true;
- int mismatches = 0;
- for (int i = 0; i < len; i++) {
- Object firstElement = getElement(first, i);
- Object secondElement = getElement(second, i);
- if (!isEquals(firstElement, secondElement)) {
- logSevere("mismatch at index " + i + ", expected " + secondElement + ", saw " + firstElement);
- success = false;
- mismatches++;
- if (mismatches >= getMisMatchLimit()) {
- logSevere("...Truncated");
- break;
- }
- }
- }
- return success;
- }
- }
-
- class FPArrayComparer extends ArrayComparer {
-
- @Override
- Object getElement(Object ary, int index) {
- return Array.getDouble(ary, index);
- }
-
- @Override
- boolean isEquals(Object firstElement, Object secondElement) {
- return isEqualsFP((double) firstElement, (double) secondElement);
- }
- }
-
- class IntArrayComparer extends ArrayComparer {
-
- @Override
- Object getElement(Object ary, int index) {
- return Array.getLong(ary, index);
- }
- }
-
- class BooleanArrayComparer extends ArrayComparer {
-
- @Override
- Object getElement(Object ary, int index) {
- return Array.getBoolean(ary, index);
- }
- }
-
- class ObjArrayComparer extends ArrayComparer {
-
- @Override
- Object getElement(Object ary, int index) {
- return Array.get(ary, index);
- }
-
- @Override
- boolean isEquals(Object firstElement, Object secondElement) {
- return compareObjects(firstElement, secondElement);
- }
- }
-
- /**
- * Tests two floating point values for equality.
- */
- public boolean isEqualsFP(double first, double second) {
- // Special case for checking whether expected and actual values are both NaNs.
- if (Double.isNaN(first) && Double.isNaN(second)) {
- return true;
- }
- return first == second;
}
public void setDispatchMode(DispatchMode dispatchMode) {
@@ -761,8 +620,8 @@
}
}
- private void compareOkraToSeq(HsailMode hsailModeToUse) {
- compareOkraToSeq(hsailModeToUse, false);
+ private void assertOkraEqualsSeq(HsailMode hsailModeToUse) {
+ assertOkraEqualsSeq(hsailModeToUse, false);
}
/**
@@ -770,7 +629,7 @@
* runOkraFirst flag controls which order they are done in. Note the compiler must use eager
* resolving if Okra is done first.
*/
- private void compareOkraToSeq(HsailMode hsailModeToUse, boolean useLambda) {
+ private void assertOkraEqualsSeq(HsailMode hsailModeToUse, boolean useLambda) {
KernelTester testerSeq;
if (runOkraFirst) {
runOkraInstance(hsailModeToUse, useLambda);
@@ -779,7 +638,7 @@
testerSeq = runSeqInstance();
runOkraInstance(hsailModeToUse, useLambda);
}
- assertTrue("failed comparison to SEQ", compareResults(testerSeq));
+ assertResultFieldsEqual(testerSeq);
}
private void runOkraInstance(HsailMode hsailModeToUse, boolean useLambda) {
@@ -800,19 +659,19 @@
}
public void testGeneratedHsail() {
- compareOkraToSeq(HsailMode.COMPILED);
+ assertOkraEqualsSeq(HsailMode.COMPILED);
}
public void testGeneratedHsailUsingLambdaMethod() {
- compareOkraToSeq(HsailMode.COMPILED, true);
+ assertOkraEqualsSeq(HsailMode.COMPILED, true);
}
public void testInjectedHsail() {
- newInstance().compareOkraToSeq(HsailMode.INJECT_HSAIL);
+ newInstance().assertOkraEqualsSeq(HsailMode.INJECT_HSAIL);
}
public void testInjectedOpencl() {
- newInstance().compareOkraToSeq(HsailMode.INJECT_OCL);
+ newInstance().assertOkraEqualsSeq(HsailMode.INJECT_OCL);
}
protected static Object getFieldFromObject(Field f, Object fromObj) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchManyBase.java
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchManyBase.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchManyBase.java Wed May 21 11:45:50 2014 +0200
@@ -33,11 +33,6 @@
return (gid < 4096 && gid % 512 == 1);
}
- @Override
- public int getMisMatchLimit() {
- return 1000;
- }
-
public void run(int gid) {
int outval = getOutval(gid);
try {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/EscapingNewStringConcatTest.java
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/EscapingNewStringConcatTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/EscapingNewStringConcatTest.java Wed May 21 11:45:50 2014 +0200
@@ -24,7 +24,7 @@
import static com.oracle.graal.debug.Debug.*;
-import org.junit.Test;
+import org.junit.*;
import com.oracle.graal.debug.*;
@@ -51,7 +51,8 @@
}
// Node implementing Lowerable not handled in HSAIL Backend: 6274|MonitorEnter
- @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+ @Ignore
+ @Test
public void test() {
try (DebugConfigScope s = disableIntercept()) {
testGeneratedHsail();
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/FloatDivPrecisionTest.java
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/FloatDivPrecisionTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/FloatDivPrecisionTest.java Wed May 21 11:45:50 2014 +0200
@@ -49,8 +49,8 @@
}
@Override
- public boolean isEqualsFP(double first, double second) {
- return Math.abs(first - second) == 0;
+ protected double equalFloatsOrDoublesDelta() {
+ return 0.0D;
}
@Test
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VecmathNBodyDeoptTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VecmathNBodyDeoptTest.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2009, 2012, 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.compiler.hsail.test.lambda;
+
+import java.util.*;
+import org.junit.*;
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import javax.vecmath.*;
+
+/**
+ * Tests NBody algorithm using the javax.vecmath package (all objects non-escaping).
+ */
+public class VecmathNBodyDeoptTest extends GraalKernelTester {
+ static final int bodies = 1024;
+ static final float delT = .005f;
+ static final float espSqr = 1.0f;
+ static final float mass = 5f;
+ static final int width = 768;
+ static final int height = 768;
+
+ static class Body extends Vector3f {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public Body(float _x, float _y, float _z, float _m) {
+ super(_x, _y, _z);
+ m = _m;
+ v = new Vector3f(0, 0, 0);
+ }
+
+ float m;
+ Vector3f v;
+
+ public float getM() {
+ return m;
+ }
+
+ public Vector3f computeAcc(Body[] in_bodies, float espSqr1, float delT1) {
+ Vector3f acc = new Vector3f();
+
+ for (Body b : in_bodies) {
+ Vector3f d = new Vector3f();
+ d.sub(b, this);
+ float invDist = 1.0f / (float) Math.sqrt(d.lengthSquared() + espSqr1);
+ float s = b.getM() * invDist * invDist * invDist;
+ acc.scaleAdd(s, d, acc);
+ }
+
+ // now return acc scaled by delT
+ acc.scale(delT1);
+ return acc;
+ }
+ }
+
+ @Result Body[] in_bodies = new Body[bodies];
+ @Result Body[] out_bodies = new Body[bodies];
+
+ static Body[] seed_bodies = new Body[bodies];
+
+ static {
+ java.util.Random randgen = new Random(0);
+ final float maxDist = width / 4;
+ for (int body = 0; body < bodies; body++) {
+ final float theta = (float) (randgen.nextFloat() * Math.PI * 2);
+ final float phi = (float) (randgen.nextFloat() * Math.PI * 2);
+ final float radius = randgen.nextFloat() * maxDist;
+ float x = (float) (radius * Math.cos(theta) * Math.sin(phi)) + width / 2;
+ float y = (float) (radius * Math.sin(theta) * Math.sin(phi)) + height / 2;
+ float z = (float) (radius * Math.cos(phi));
+ seed_bodies[body] = new Body(x, y, z, mass);
+ }
+ }
+
+ @Override
+ public void runTest() {
+ System.arraycopy(seed_bodies, 0, in_bodies, 0, seed_bodies.length);
+ for (int b = 0; b < bodies; b++) {
+ out_bodies[b] = new Body(0, 0, 0, mass);
+ }
+ // no local copies of arrays so we make it an instance lambda
+
+ dispatchLambdaKernel(bodies, (gid) -> {
+ Body inb = in_bodies[gid];
+ Body outb = out_bodies[gid];
+ Vector3f acc = inb.computeAcc(in_bodies, espSqr, delT);
+
+ Vector3f tmpPos = new Vector3f();
+ tmpPos.scaleAdd(delT, inb.v, inb);
+ if (gid == bodies / 2) {
+ tmpPos.x += forceDeopt(gid);
+ }
+ tmpPos.scaleAdd(0.5f * delT, acc, tmpPos);
+ outb.set(tmpPos);
+
+ outb.v.add(inb.v, acc);
+ });
+ }
+
+ @Override
+ protected boolean supportsRequiredCapabilities() {
+ return (canHandleDeoptVirtualObjects());
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+
+ @Test
+ public void testUsingLambdaMethod() {
+ testGeneratedHsailUsingLambdaMethod();
+ }
+
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCall3Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCall3Test.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2009, 2012, 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.compiler.hsail.test.lambda;
+
+import org.junit.Test;
+
+/**
+ * Tests a true virtual method call with 3 targets.
+ */
+public class VirtualCall3Test extends VirtualCallBase {
+
+ void setupArrays() {
+ for (int i = 0; i < NUM; i++) {
+ outArray[i] = -i;
+ inShapeArray[i] = createShape(i % 3, i + 1);
+ }
+ }
+
+ // although runTest is the same in each class derived from VirtualCallBase
+ // we duplicate the logic in each derived test so as to have different lambda call sites
+ @Override
+ public void runTest() {
+ setupArrays();
+
+ dispatchLambdaKernel(NUM, (gid) -> {
+ Shape shape = inShapeArray[gid];
+ outArray[gid] = shape.getArea();
+ });
+ }
+
+ @Override
+ protected boolean supportsRequiredCapabilities() {
+ return typeProfileWidthAtLeast(3);
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+
+ @Test
+ public void testUsingLambdaMethod() {
+ testGeneratedHsailUsingLambdaMethod();
+ }
+
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCall4Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCall4Test.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2009, 2012, 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.compiler.hsail.test.lambda;
+
+import org.junit.Test;
+
+/**
+ * Tests a true virtual method call with 4 targets.
+ */
+public class VirtualCall4Test extends VirtualCallBase {
+
+ void setupArrays() {
+ for (int i = 0; i < NUM; i++) {
+ outArray[i] = -i;
+ inShapeArray[i] = createShape(i % 4, i + 1);
+ }
+ }
+
+ // although runTest is the same in each class derived from VirtualCallBase
+ // we duplicate the logic in each derived test so as to have different lambda call sites
+ @Override
+ public void runTest() {
+ setupArrays();
+
+ dispatchLambdaKernel(NUM, (gid) -> {
+ Shape shape = inShapeArray[gid];
+ outArray[gid] = shape.getArea();
+ });
+ }
+
+ @Override
+ protected boolean supportsRequiredCapabilities() {
+ return typeProfileWidthAtLeast(4);
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+
+ @Test
+ public void testUsingLambdaMethod() {
+ testGeneratedHsailUsingLambdaMethod();
+ }
+
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCallBase.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCallBase.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2009, 2012, 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.compiler.hsail.test.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+
+/**
+ * Base class for testing virtual method calls.
+ */
+abstract public class VirtualCallBase extends GraalKernelTester {
+
+ static final int NUM = 20000;
+
+ @Result public float[] outArray = new float[NUM];
+ public Shape[] inShapeArray = new Shape[NUM];
+
+ static abstract class Shape {
+
+ abstract public float getArea();
+ }
+
+ static class Circle extends Shape {
+
+ private float radius;
+
+ Circle(float r) {
+ radius = r;
+ }
+
+ @Override
+ public float getArea() {
+ return (float) (Math.PI * radius * radius);
+ }
+ }
+
+ static class Square extends Shape {
+
+ private float len;
+
+ Square(float _len) {
+ len = _len;
+ }
+
+ @Override
+ public float getArea() {
+ return len * len;
+ }
+ }
+
+ static class Triangle extends Shape {
+
+ private float base;
+ private float height;
+
+ Triangle(float base, float height) {
+ this.base = base;
+ this.height = height;
+ }
+
+ @Override
+ public float getArea() {
+ return (base * height / 2.0f);
+ }
+ }
+
+ static class Rectangle extends Shape {
+
+ private float base;
+ private float height;
+
+ Rectangle(float base, float height) {
+ this.base = base;
+ this.height = height;
+ }
+
+ @Override
+ public float getArea() {
+ return (base * height);
+ }
+ }
+
+ Shape createShape(int kind, int size) {
+ switch (kind) {
+ case 0:
+ return new Circle(size);
+ case 1:
+ return new Square(size);
+ case 2:
+ return new Triangle(size, size + 1);
+ case 3:
+ return new Rectangle(size, size + 1);
+ default:
+ return null;
+ }
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCallTest.java
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCallTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCallTest.java Wed May 21 11:45:50 2014 +0200
@@ -23,66 +23,23 @@
package com.oracle.graal.compiler.hsail.test.lambda;
-import static com.oracle.graal.debug.Debug.*;
-
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import com.oracle.graal.debug.*;
-
import org.junit.Test;
/**
- * Tests a true virtual method call.
+ * Tests a true virtual method call with 2 targets.
*/
-public class VirtualCallTest extends GraalKernelTester {
-
- static final int NUM = 20;
-
- static abstract class Shape {
-
- abstract public float getArea();
- }
+public class VirtualCallTest extends VirtualCallBase {
- static class Circle extends Shape {
-
- private float radius;
-
- Circle(float r) {
- radius = r;
- }
-
- @Override
- public float getArea() {
- return (float) (Math.PI * radius * radius);
+ void setupArrays() {
+ for (int i = 0; i < NUM; i++) {
+ outArray[i] = -i;
+ int kind = i % 3 == 0 ? 0 : 1;
+ inShapeArray[i] = createShape(kind, i + 1);
}
}
- static class Square extends Shape {
-
- private float len;
-
- Square(float _len) {
- len = _len;
- }
-
- @Override
- public float getArea() {
- return len * len;
- }
- }
-
- @Result public float[] outArray = new float[NUM];
- public Shape[] inShapeArray = new Shape[NUM];
-
- void setupArrays() {
- for (int i = 0; i < NUM; i++) {
- if (i % 2 == 0)
- inShapeArray[i] = new Circle(i + 1);
- else
- inShapeArray[i] = new Square(i + 1);
- outArray[i] = -i;
- }
- }
-
+ // although runTest is the same in each class derived from VirtualCallBase
+ // we duplicate the logic in each derived test so as to have different lambda call sites
@Override
public void runTest() {
setupArrays();
@@ -93,19 +50,19 @@
});
}
- // graal says not inlining getArea():float (0 bytes): no type profile exists
- @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
- public void test() {
- try (DebugConfigScope s = disableIntercept()) {
- testGeneratedHsail();
- }
+ @Override
+ protected boolean supportsRequiredCapabilities() {
+ return typeProfileWidthAtLeast(2);
}
- @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+
+ @Test
public void testUsingLambdaMethod() {
- try (DebugConfigScope s = disableIntercept()) {
- testGeneratedHsailUsingLambdaMethod();
- }
+ testGeneratedHsailUsingLambdaMethod();
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Wed May 21 11:45:50 2014 +0200
@@ -404,6 +404,16 @@
}
@Override
+ public Value emitMulHigh(Value a, Value b) {
+ throw GraalInternalError.unimplemented();
+ }
+
+ @Override
+ public Value emitUMulHigh(Value a, Value b) {
+ throw GraalInternalError.unimplemented();
+ }
+
+ @Override
public Value emitDiv(Value a, Value b, LIRFrameState state) {
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
@@ -828,16 +838,6 @@
* series of cascading compare and branch instructions. This is currently the recommended way of
* generating performant HSAIL code for switch constructs.
*
- * In Java bytecode the keys for switch statements are always ints.
- *
- * The x86 backend also adds support for handling keys of type long or Object but these two
- * special cases are for handling the TypeSwitchNode, which is a node that the JVM produces for
- * handling operations related to method dispatch. We haven't yet added support for the
- * TypeSwitchNode, so for the time being we have added a check to ensure that the keys are of
- * type int. This also allows us to flag any test cases/execution paths that may trigger the
- * creation of a TypeSwitchNode which we don't support yet.
- *
- *
* @param strategy the strategy used for this switch.
* @param keyTargets array of branch targets for each of the cases.
* @param defaultTarget the branch target for the default case.
@@ -845,12 +845,16 @@
*/
@Override
public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
- if ((key.getKind() == Kind.Int) || (key.getKind() == Kind.Long)) {
- // Append the LIR instruction for generating compare and branch instructions.
- append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key));
- } else {
- // Throw an exception if the keys aren't ints.
- throw GraalInternalError.unimplemented("Switch statements are only supported for keys of type int or long, not " + key.getKind());
+ switch (key.getKind()) {
+ case Int:
+ case Long:
+ case Object:
+ // Append the LIR instruction for generating compare and branch instructions.
+ append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key));
+ break;
+ default:
+ // Throw an exception if the key kind is anything else.
+ throw GraalInternalError.unimplemented("Switch statements not supported for keys of type " + key.getKind());
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Wed May 21 11:45:50 2014 +0200
@@ -485,6 +485,16 @@
}
@Override
+ public Value emitMulHigh(Value a, Value b) {
+ throw GraalInternalError.unimplemented();
+ }
+
+ @Override
+ public Value emitUMulHigh(Value a, Value b) {
+ throw GraalInternalError.unimplemented();
+ }
+
+ @Override
public Value emitDiv(Value a, Value b, LIRFrameState state) {
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Wed May 21 11:45:50 2014 +0200
@@ -580,6 +580,16 @@
}
@Override
+ public Value emitMulHigh(Value a, Value b) {
+ throw GraalInternalError.unimplemented();
+ }
+
+ @Override
+ public Value emitUMulHigh(Value a, Value b) {
+ throw GraalInternalError.unimplemented();
+ }
+
+ @Override
public Value emitDiv(Value a, Value b, LIRFrameState state) {
Variable result = newVariable(a.getKind());
switch (a.getKind().getStackKind()) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Wed May 21 11:45:50 2014 +0200
@@ -300,7 +300,7 @@
final ValueNode getResult(String snippet) {
processMethod(snippet);
- assertEquals(1, graph.getNodes(ReturnNode.class).count());
+ assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
return graph.getNodes(ReturnNode.class).first().result();
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java Wed May 21 11:45:50 2014 +0200
@@ -132,7 +132,7 @@
result = getResult(getCanonicalizedGraph("integerTestCanonicalization2"));
assertTrue(result.isConstant() && result.asConstant().asLong() == 1);
StructuredGraph graph = getCanonicalizedGraph("integerTestCanonicalization3");
- assertEquals(1, graph.getNodes(ReturnNode.class).count());
+ assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
assertTrue(graph.getNodes(ReturnNode.class).first().result() instanceof ConditionalNode);
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java Wed May 21 11:45:50 2014 +0200
@@ -100,7 +100,7 @@
new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context);
canonicalizer.apply(graph, context);
- assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(GuardNode.class).count());
}
public static String testInstanceOfCheckCastSnippet(Object e) {
@@ -123,7 +123,7 @@
new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context);
canonicalizer.apply(graph, context);
- assertEquals(0, graph.getNodes().filter(GuardNode.class).count());
+ assertDeepEquals(0, graph.getNodes().filter(GuardNode.class).count());
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java Wed May 21 11:45:50 2014 +0200
@@ -61,7 +61,7 @@
@Test
public void redundantCheckCastTest() {
- assertEquals(i7, redundantCheckCastSnippet(i7));
+ assertDeepEquals(i7, redundantCheckCastSnippet(i7));
StructuredGraph result = afterFlowSensitiveReduce("redundantCheckCastSnippet");
nodeCountEquals(result, CheckCastNode.class, 0);
nodeCountEquals(result, InstanceOfNode.class, 1);
@@ -79,7 +79,7 @@
@Test
public void redundantInstanceOfTest01() {
String snippet = "redundantInstanceOfSnippet01";
- assertEquals(true, redundantInstanceOfSnippet01(i7));
+ assertDeepEquals(true, redundantInstanceOfSnippet01(i7));
nodeCountEquals(afterFlowSensitiveReduce(snippet), InstanceOfNode.class, 1);
}
@@ -100,9 +100,9 @@
@Test
public void redundantInstanceOfTest02() {
String snippet = "redundantInstanceOfSnippet02";
- assertEquals(i7, redundantInstanceOfSnippet02(i7));
+ assertDeepEquals(i7, redundantInstanceOfSnippet02(i7));
int ioAfter = getNodes(afterFlowSensitiveReduce(snippet), InstanceOfNode.class).size();
- assertEquals(ioAfter, 1);
+ assertDeepEquals(ioAfter, 1);
}
/*
@@ -121,18 +121,18 @@
@Test
public void devirtualizationTest() {
String snippet = "devirtualizationSnippet";
- assertEquals(i7, devirtualizationSnippet(i7, i7));
+ assertDeepEquals(i7, devirtualizationSnippet(i7, i7));
nodeCountEquals(afterFlowSensitiveReduce(snippet), CheckCastNode.class, 0);
StructuredGraph graph = afterFlowSensitiveReduce(snippet);
- assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
+ assertDeepEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
List invokeNodes = getNodes(afterFlowSensitiveReduce(snippet), InvokeNode.class);
- assertEquals(1, invokeNodes.size());
+ assertDeepEquals(1, invokeNodes.size());
MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget();
- assertEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
- assertEquals("HotSpotMethod", target.targetMethod().toString());
+ assertDeepEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
+ assertDeepEquals("HotSpotMethod", target.targetMethod().toString());
}
/*
@@ -154,7 +154,7 @@
@Test
public void t5a() {
String snippet = "t5Snippet";
- assertEquals(false, t5Snippet(null, true));
+ assertDeepEquals(false, t5Snippet(null, true));
StructuredGraph resultGraph = canonicalize(afterFlowSensitiveReduce(snippet));
nodeCountEquals(resultGraph, ReturnNode.class, 2);
@@ -164,8 +164,8 @@
ConstantNode c1 = (ConstantNode) iter.next().result();
ConstantNode c2 = (ConstantNode) iter.next().result();
- assertEquals(c1, c2);
- assertEquals(0, c1.getValue().asInt());
+ assertDeepEquals(c1, c2);
+ assertDeepEquals(0, c1.getValue().asInt());
}
@Test
@@ -215,16 +215,16 @@
StructuredGraph graph = afterFlowSensitiveReduce(snippet);
graph = dce(canonicalize(graph));
// TODO how to simplify IfNode(false)
- assertEquals(1, getNodes(graph, InstanceOfNode.class).size());
+ assertDeepEquals(1, getNodes(graph, InstanceOfNode.class).size());
List returnNodes = getNodes(graph, ReturnNode.class);
- assertEquals(2, returnNodes.size());
+ assertDeepEquals(2, returnNodes.size());
Iterator iter = returnNodes.iterator();
ConstantNode c1 = (ConstantNode) iter.next().result();
ConstantNode c2 = (ConstantNode) iter.next().result();
- assertEquals(c1, c2);
+ assertDeepEquals(c1, c2);
Assert.assertTrue(c1.getValue().isNull());
}
@@ -253,14 +253,14 @@
String snippet = "devirtualizationSnippet02";
StructuredGraph graph = afterFlowSensitiveReduce(snippet);
- assertEquals(1, getNodes(graph, InvokeNode.class).size());
+ assertDeepEquals(1, getNodes(graph, InvokeNode.class).size());
List invokeNodes = getNodes(graph, InvokeNode.class);
- assertEquals(1, invokeNodes.size());
+ assertDeepEquals(1, invokeNodes.size());
MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget();
- assertEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
- assertEquals("HotSpotMethod", target.targetMethod().toString());
+ assertDeepEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
+ assertDeepEquals("HotSpotMethod", target.targetMethod().toString());
}
/*
@@ -312,7 +312,7 @@
dce(graph);
List returnNodes = getNodes(graph, ReturnNode.class);
- assertEquals(2, returnNodes.size());
+ assertDeepEquals(2, returnNodes.size());
Iterator iter = returnNodes.iterator();
ValueNode c1 = GraphUtil.unproxify(iter.next().result());
@@ -339,7 +339,7 @@
String snippet = "deduplicateInstanceOfSnippet";
StructuredGraph graph = afterFlowSensitiveReduce(snippet);
List ioNodes = getNodes(graph, InstanceOfNode.class);
- assertEquals(1, ioNodes.size());
+ assertDeepEquals(1, ioNodes.size());
}
@@ -371,7 +371,7 @@
}
public void nodeCountEquals(StructuredGraph graph, Class nodeClass, int expected) {
- assertEquals(expected, getNodes(graph, nodeClass).size());
+ assertDeepEquals(expected, getNodes(graph, nodeClass).size());
}
public StructuredGraph afterFlowSensitiveReduce(String snippet) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java Wed May 21 11:45:50 2014 +0200
@@ -209,7 +209,7 @@
new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first();
- assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
+ assertDeepEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
}
public static void testTypeMergingSnippet(Object o, boolean b) {
@@ -240,7 +240,7 @@
new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
- assertEquals(0, graph.getNodes().filter(StoreFieldNode.class).count());
+ assertDeepEquals(0, graph.getNodes().filter(StoreFieldNode.class).count());
}
public static String testInstanceOfCheckCastSnippet(Object e) {
@@ -258,7 +258,7 @@
new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
- assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
+ assertDeepEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
}
public static int testDuplicateNullChecksSnippet(Object a) {
@@ -287,7 +287,7 @@
new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
canonicalizer.apply(graph, context);
- assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(GuardNode.class).count());
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Wed May 21 11:45:50 2014 +0200
@@ -528,7 +528,7 @@
actual.exception.printStackTrace();
Assert.fail("expected " + expect.returnValue + " but got an exception");
}
- assertEquals(expect.returnValue, actual.returnValue);
+ assertDeepEquals(expect.returnValue, actual.returnValue);
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java Wed May 21 11:45:50 2014 +0200
@@ -30,6 +30,8 @@
import com.oracle.graal.debug.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
import com.oracle.graal.phases.tiers.*;
@@ -137,6 +139,59 @@
return 1;
}
+ @Test
+ public void test6() {
+ testCombinedIf("test6Snippet", 3);
+ test("test6Snippet", new int[]{0});
+ }
+
+ public static int test6Snippet(int[] a) {
+ int i = a[0];
+ if (i >= 0 && i < a.length) {
+ return a[i];
+ }
+ return 1;
+ }
+
+ @Test
+ public void test7() {
+ testCombinedIf("test7Snippet", 1);
+ test("test7Snippet", -1);
+ }
+
+ public static int test7Snippet(int v) {
+ if (v >= 0 && v < 1024) {
+ return v + 1;
+ }
+ return v - 1;
+ }
+
+ @Test
+ public void test8() {
+ testCombinedIf("test8Snippet", 1);
+ test("test8Snippet", -1);
+ }
+
+ public static int test8Snippet(int v) {
+ if (v >= 0 && v <= 1024) {
+ return v + 1;
+ }
+ return v - 1;
+ }
+
+ private void testCombinedIf(String snippet, int count) {
+ StructuredGraph graph = parse(snippet);
+ PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
+ new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+ new FloatingReadPhase().apply(graph);
+ MidTierContext midContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
+ new GuardLoweringPhase().apply(graph, midContext);
+ new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+ new ValueAnchorCleanupPhase().apply(graph);
+ new CanonicalizerPhase(true).apply(graph, context);
+ assertDeepEquals(count, graph.getNodes().filter(IfNode.class).count());
+ }
+
private void test(String snippet) {
StructuredGraph graph = parse(snippet);
ParameterNode param = graph.getNodes(ParameterNode.class).iterator().next();
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Wed May 21 11:45:50 2014 +0200
@@ -66,7 +66,7 @@
for (Infopoint sp : cr.getInfopoints()) {
assertNotNull(sp.reason);
if (sp instanceof Call) {
- assertEquals(InfopointReason.CALL, sp.reason);
+ assertDeepEquals(InfopointReason.CALL, sp.reason);
}
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java Wed May 21 11:45:50 2014 +0200
@@ -65,8 +65,8 @@
StructuredGraph graph = getGraph("testSynchronizedSnippet");
new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
new LockEliminationPhase().apply(graph);
- assertEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
- assertEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
}
public static void testSynchronizedMethodSnippet(A x) {
@@ -83,8 +83,8 @@
StructuredGraph graph = getGraph("testSynchronizedMethodSnippet");
new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
new LockEliminationPhase().apply(graph);
- assertEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
- assertEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
}
private StructuredGraph getGraph(String snippet) {
diff -r a43ff5d18350 -r a6eeb3750238 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 Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Wed May 21 11:45:50 2014 +0200
@@ -164,7 +164,7 @@
@Test
public void testLoop1() {
SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
- assertEquals(6, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(6, schedule.getCFG().getBlocks().size());
assertReadWithinStartBlock(schedule, true);
assertReadWithinAllReturnBlocks(schedule, false);
}
@@ -189,7 +189,7 @@
@Test
public void testLoop2() {
SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
- assertEquals(6, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(6, schedule.getCFG().getBlocks().size());
assertReadWithinStartBlock(schedule, false);
assertReadWithinAllReturnBlocks(schedule, true);
}
@@ -211,7 +211,7 @@
@Test
public void testLoop3() {
SchedulePhase schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES);
- assertEquals(6, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(6, schedule.getCFG().getBlocks().size());
assertReadWithinStartBlock(schedule, true);
assertReadWithinAllReturnBlocks(schedule, false);
}
@@ -247,7 +247,7 @@
@Test
public void testLoop5() {
SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
- assertEquals(10, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(10, schedule.getCFG().getBlocks().size());
assertReadWithinStartBlock(schedule, false);
assertReadWithinAllReturnBlocks(schedule, false);
}
@@ -264,10 +264,10 @@
public void testArrayCopy() {
SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
- assertEquals(1, graph.getNodes(ReturnNode.class).count());
+ assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
ReturnNode ret = graph.getNodes(ReturnNode.class).first();
assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode);
- assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
+ assertDeepEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
assertReadWithinAllReturnBlocks(schedule, true);
}
@@ -285,7 +285,7 @@
@Test
public void testIfRead1() {
SchedulePhase schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
- assertEquals(3, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(3, schedule.getCFG().getBlocks().size());
assertReadWithinStartBlock(schedule, true);
assertReadAndWriteInSameBlock(schedule, false);
}
@@ -306,8 +306,8 @@
@Test
public void testIfRead2() {
SchedulePhase schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
- assertEquals(3, schedule.getCFG().getBlocks().size());
- assertEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
+ assertDeepEquals(3, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
assertReadWithinStartBlock(schedule, false);
assertReadWithinAllReturnBlocks(schedule, false);
assertReadAndWriteInSameBlock(schedule, false);
@@ -328,7 +328,7 @@
@Test
public void testIfRead3() {
SchedulePhase schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
- assertEquals(4, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(4, schedule.getCFG().getBlocks().size());
assertReadWithinStartBlock(schedule, false);
assertReadWithinAllReturnBlocks(schedule, true);
}
@@ -349,7 +349,7 @@
@Test
public void testIfRead4() {
SchedulePhase schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES);
- assertEquals(3, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(3, schedule.getCFG().getBlocks().size());
assertReadWithinStartBlock(schedule, false);
assertReadWithinAllReturnBlocks(schedule, false);
assertReadAndWriteInSameBlock(schedule, true);
@@ -368,12 +368,36 @@
@Test
public void testIfRead5() {
SchedulePhase schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
- assertEquals(4, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(4, schedule.getCFG().getBlocks().size());
assertReadWithinStartBlock(schedule, false);
assertReadWithinAllReturnBlocks(schedule, true);
assertReadAndWriteInSameBlock(schedule, false);
}
+ public static int testAntiDependencySnippet(int a) {
+ /*
+ * This read must not be scheduled after the following write.
+ */
+ int res = container.a;
+ container.a = 10;
+
+ /*
+ * Add some more basic blocks.
+ */
+ if (a < 0) {
+ container.b = 20;
+ }
+ container.c = 30;
+ return res;
+ }
+
+ @Test
+ public void testAntiDependency() {
+ SchedulePhase schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES);
+ assertDeepEquals(4, schedule.getCFG().getBlocks().size());
+ assertReadBeforeAllWritesInStartBlock(schedule);
+ }
+
/**
* testing scheduling within a block.
*/
@@ -397,9 +421,9 @@
StructuredGraph graph = schedule.getCFG().graph;
NodeIterable writeNodes = graph.getNodes().filter(WriteNode.class);
- assertEquals(1, schedule.getCFG().getBlocks().size());
- assertEquals(8, writeNodes.count());
- assertEquals(1, graph.getNodes().filter(FloatingReadNode.class).count());
+ assertDeepEquals(1, schedule.getCFG().getBlocks().size());
+ assertDeepEquals(8, writeNodes.count());
+ assertDeepEquals(1, graph.getNodes().filter(FloatingReadNode.class).count());
FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first();
@@ -554,7 +578,7 @@
}
returnBlocks++;
}
- assertEquals(withRead == returnBlocks, withinReturnBlock);
+ assertDeepEquals(withRead == returnBlocks, withinReturnBlock);
}
private void assertReadWithinStartBlock(SchedulePhase schedule, boolean withinStartBlock) {
@@ -564,7 +588,7 @@
readEncountered = true;
}
}
- assertEquals(withinStartBlock, readEncountered);
+ assertDeepEquals(withinStartBlock, readEncountered);
}
private static void assertReadAndWriteInSameBlock(SchedulePhase schedule, boolean inSame) {
@@ -574,6 +598,20 @@
assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write)));
}
+ private static void assertReadBeforeAllWritesInStartBlock(SchedulePhase schedule) {
+ boolean writeNodeFound = false;
+ boolean readNodeFound = false;
+ for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) {
+ if (node instanceof FloatingReadNode) {
+ assertTrue(!writeNodeFound);
+ readNodeFound = true;
+ } else if (node instanceof WriteNode) {
+ writeNodeFound = true;
+ }
+ }
+ assertTrue(readNodeFound);
+ }
+
private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode) {
return getFinalSchedule(snippet, mode, MemoryScheduling.OPTIMAL);
}
@@ -617,7 +655,7 @@
SchedulePhase schedule = new SchedulePhase(schedulingStrategy, memsched);
schedule.apply(graph);
- assertEquals(1, graph.getNodes().filter(StartNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count());
return schedule;
}
} catch (Throwable e) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java Wed May 21 11:45:50 2014 +0200
@@ -61,6 +61,6 @@
new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
Debug.dump(graph, "Graph");
- assertEquals(returnCount, graph.getNodes(ReturnNode.class).count());
+ assertDeepEquals(returnCount, graph.getNodes(ReturnNode.class).count());
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java Wed May 21 11:45:50 2014 +0200
@@ -65,24 +65,24 @@
List blocks = cfg.getBlocks();
// check number of blocks
- assertEquals(4, blocks.size());
+ assertDeepEquals(4, blocks.size());
// check block - node assignment
- assertEquals(blocks.get(0), cfg.blockFor(graph.start()));
- assertEquals(blocks.get(0), cfg.blockFor(ifNode));
- assertEquals(blocks.get(1), cfg.blockFor(trueBegin));
- assertEquals(blocks.get(1), cfg.blockFor(trueEnd));
- assertEquals(blocks.get(2), cfg.blockFor(falseBegin));
- assertEquals(blocks.get(2), cfg.blockFor(falseEnd));
- assertEquals(blocks.get(3), cfg.blockFor(merge));
- assertEquals(blocks.get(3), cfg.blockFor(returnNode));
+ assertDeepEquals(blocks.get(0), cfg.blockFor(graph.start()));
+ assertDeepEquals(blocks.get(0), cfg.blockFor(ifNode));
+ assertDeepEquals(blocks.get(1), cfg.blockFor(trueBegin));
+ assertDeepEquals(blocks.get(1), cfg.blockFor(trueEnd));
+ assertDeepEquals(blocks.get(2), cfg.blockFor(falseBegin));
+ assertDeepEquals(blocks.get(2), cfg.blockFor(falseEnd));
+ assertDeepEquals(blocks.get(3), cfg.blockFor(merge));
+ assertDeepEquals(blocks.get(3), cfg.blockFor(returnNode));
// check postOrder
Iterator it = cfg.postOrder().iterator();
for (int i = blocks.size() - 1; i >= 0; i--) {
assertTrue(it.hasNext());
Block b = it.next();
- assertEquals(blocks.get(i), b);
+ assertDeepEquals(blocks.get(i), b);
}
// check dominators
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EAMergingTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EAMergingTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EAMergingTest.java Wed May 21 11:45:50 2014 +0200
@@ -33,7 +33,7 @@
@Test
public void testSimpleMerge() {
testEscapeAnalysis("simpleMergeSnippet", null, false);
- assertEquals(1, returnNodes.size());
+ assertDeepEquals(1, returnNodes.size());
assertTrue(returnNodes.get(0).result() instanceof ValuePhiNode);
PhiNode phi = (PhiNode) returnNodes.get(0).result();
assertTrue(phi.valueAt(0) instanceof ParameterNode);
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java Wed May 21 11:45:50 2014 +0200
@@ -74,12 +74,12 @@
public void testSimple() {
ValueNode result = getReturn("testSimpleSnippet").result();
assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
- assertEquals(graph.getParameter(0), result);
+ assertDeepEquals(graph.getParameter(0), result);
}
final ReturnNode getReturn(String snippet) {
processMethod(snippet);
- assertEquals(1, graph.getNodes(ReturnNode.class).count());
+ assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
return graph.getNodes(ReturnNode.class).first();
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Wed May 21 11:45:50 2014 +0200
@@ -87,7 +87,7 @@
ValueNode result = getReturn("testSimpleSnippet").result();
assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
assertTrue(result.isConstant());
- assertEquals(2, result.asConstant().asInt());
+ assertDeepEquals(2, result.asConstant().asInt());
}
@SuppressWarnings("all")
@@ -115,7 +115,7 @@
public void testParam() {
ValueNode result = getReturn("testParamSnippet").result();
assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
- assertEquals(graph.getParameter(1), result);
+ assertDeepEquals(graph.getParameter(1), result);
}
@SuppressWarnings("all")
@@ -129,7 +129,7 @@
public void testMaterialized() {
ValueNode result = getReturn("testMaterializedSnippet").result();
assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
- assertEquals(graph.getParameter(0), result);
+ assertDeepEquals(graph.getParameter(0), result);
}
@SuppressWarnings("all")
@@ -145,7 +145,7 @@
public void testSimpleLoop() {
ValueNode result = getReturn("testSimpleLoopSnippet").result();
assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
- assertEquals(graph.getParameter(1), result);
+ assertDeepEquals(graph.getParameter(1), result);
}
@SuppressWarnings("all")
@@ -162,7 +162,7 @@
@Test
public void testBadLoop() {
ValueNode result = getReturn("testBadLoopSnippet").result();
- assertEquals(0, graph.getNodes().filter(LoadFieldNode.class).count());
+ assertDeepEquals(0, graph.getNodes().filter(LoadFieldNode.class).count());
assertTrue(result instanceof ProxyNode);
assertTrue(((ProxyNode) result).value() instanceof ValuePhiNode);
}
@@ -180,7 +180,7 @@
@Test
public void testBadLoop2() {
ValueNode result = getReturn("testBadLoop2Snippet").result();
- assertEquals(1, graph.getNodes().filter(LoadFieldNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(LoadFieldNode.class).count());
assertTrue(result instanceof LoadFieldNode);
}
@@ -199,7 +199,7 @@
processMethod("testPhiSnippet");
assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
List returnNodes = graph.getNodes(ReturnNode.class).snapshot();
- assertEquals(2, returnNodes.size());
+ assertDeepEquals(2, returnNodes.size());
assertTrue(returnNodes.get(0).predecessor() instanceof StoreFieldNode);
assertTrue(returnNodes.get(1).predecessor() instanceof StoreFieldNode);
assertTrue(returnNodes.get(0).result().isConstant());
@@ -215,7 +215,7 @@
@Test
public void testSimpleStore() {
processMethod("testSimpleStoreSnippet");
- assertEquals(1, graph.getNodes().filter(StoreFieldNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(StoreFieldNode.class).count());
}
public static int testValueProxySnippet(boolean b, TestObject o) {
@@ -233,12 +233,12 @@
@Test
public void testValueProxy() {
processMethod("testValueProxySnippet");
- assertEquals(2, graph.getNodes().filter(LoadFieldNode.class).count());
+ assertDeepEquals(2, graph.getNodes().filter(LoadFieldNode.class).count());
}
final ReturnNode getReturn(String snippet) {
processMethod(snippet);
- assertEquals(1, graph.getNodes(ReturnNode.class).count());
+ assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
return graph.getNodes(ReturnNode.class).first();
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Wed May 21 11:45:50 2014 +0200
@@ -171,7 +171,7 @@
@Test
public void testReference1() {
prepareGraph("testReference1Snippet", false);
- assertEquals(1, graph.getNodes().filter(NewInstanceNode.class).count());
+ assertDeepEquals(1, graph.getNodes().filter(NewInstanceNode.class).count());
}
@SafeVarargs
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java Wed May 21 11:45:50 2014 +0200
@@ -32,5 +32,10 @@
* @returns null if the match can't be generated or a {@link ComplexMatchResult} that can be
* evaluated during LIR generation to produce the final LIR value.
*/
- ComplexMatchResult match(NodeLIRBuilder gen);
+ ComplexMatchResult match(NodeLIRBuilder gen, Object... args);
+
+ /**
+ * @return a descriptive name meaningful to the user.
+ */
+ String getName();
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Wed May 21 11:45:50 2014 +0200
@@ -22,7 +22,6 @@
*/
package com.oracle.graal.compiler.match;
-import com.oracle.graal.compiler.common.*;
import com.oracle.graal.debug.*;
import com.oracle.graal.graph.Node.Verbosity;
import com.oracle.graal.graph.*;
@@ -197,36 +196,6 @@
return result;
}
- /**
- * Convert a list of field names into {@link com.oracle.graal.graph.NodeClass.Position} objects
- * that can be used to read them during a match. The names should already have been confirmed to
- * exist in the type.
- *
- * @param theClass
- * @param names
- * @return an array of Position objects corresponding to the named fields.
- */
- public static NodeClass.Position[] findPositions(Class extends ValueNode> theClass, String[] names) {
- NodeClass.Position[] result = new NodeClass.Position[names.length];
- NodeClass nodeClass = NodeClass.get(theClass);
- for (int i = 0; i < names.length; i++) {
- for (NodeClass.Position position : nodeClass.getFirstLevelInputPositions()) {
- String name = nodeClass.getName(position);
- if (name.endsWith("#NDF")) {
- name = name.substring(0, name.length() - 4);
- }
- if (name.equals(names[i])) {
- result[i] = position;
- break;
- }
- }
- if (result[i] == null) {
- throw new GraalInternalError("unknown field \"%s\" in class %s", names[i], theClass);
- }
- }
- return result;
- }
-
private Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) {
Result result = matchType(node);
if (result != Result.OK) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java Wed May 21 11:45:50 2014 +0200
@@ -331,7 +331,8 @@
List requiredPackages = new ArrayList<>();
/**
- * The java.lang.reflect.Method for invoking a method based MatchRule.
+ * The mapping between elements with MatchRules and the wrapper class used invoke the code
+ * generation after the match.
*/
private Map invokers = new LinkedHashMap<>();
@@ -455,7 +456,7 @@
}
String generatePositionDeclaration() {
- return String.format("private static final NodeClass.Position[] %s_positions = MatchPattern.findPositions(%s.class, new String[]{\"%s\"});", nodeType.nodeClass, nodeType.nodeClass,
+ return String.format("NodeClass.Position[] %s_positions = MatchRuleRegistry.findPositions(lookup, %s.class, new String[]{\"%s\"});", nodeType.nodeClass, nodeType.nodeClass,
String.join("\", \"", nodeType.inputs));
}
}
@@ -486,9 +487,7 @@
out.println("package " + pkg + ";");
out.println("");
out.println("import java.util.*;");
- out.println("import java.lang.reflect.*;");
out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
- out.println("import " + GraalInternalError.class.getName() + ";");
out.println("import " + NodeLIRBuilder.class.getName() + ";");
out.println("import " + NodeClass.class.getName() + ";");
for (String p : requiredPackages) {
@@ -498,64 +497,67 @@
out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {");
out.println();
- out.println(" private static Method lookupMethod(Class> theClass, String name, Class>... args) {");
- out.println(" try {");
- out.println(" return theClass.getDeclaredMethod(name, args);");
- out.println(" } catch (Exception e) {");
- out.println(" throw new GraalInternalError(e);");
- out.println(" }");
- out.println(" }");
- out.println();
- // Generate declarations for the reflective invocation of the code generation methods.
+ // Generate declarations for the wrapper class to invoke the code generation methods.
for (MethodInvokerItem invoker : invokers.values()) {
StringBuilder args = new StringBuilder();
StringBuilder types = new StringBuilder();
int count = invoker.fields.size();
+ int index = 0;
for (VariableElement arg : invoker.fields) {
args.append('"');
args.append(arg.getSimpleName());
args.append('"');
- types.append(fullClassName(typeUtils.asElement(arg.asType())));
- types.append(".class");
+ types.append(String.format("(%s) args[%s]", fullClassName(typeUtils.asElement(arg.asType())), index++));
if (count-- > 1) {
args.append(", ");
types.append(", ");
}
}
out.printf(" private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args);
- out.printf(" private static final Method %s = lookupMethod(%s.class, \"%s\", %s);\n", invoker.reflectiveMethodName(), invoker.nodeLIRBuilderClass, invoker.methodName, types);
+ out.printf(" private static final class %s implements MatchGenerator {\n", invoker.wrapperClass());
+ out.printf(" static MatchGenerator instance = new %s();\n", invoker.wrapperClass());
+ out.printf(" public ComplexMatchResult match(NodeLIRBuilder builder, Object...args) {\n");
+ out.printf(" return ((%s) builder).%s(%s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types);
+ out.printf(" }\n");
+ out.printf(" public String getName() {\n");
+ out.printf(" return \"%s\";\n", invoker.methodName);
+ out.printf(" }\n");
+ out.printf(" }\n");
out.println();
}
- for (String positionDeclaration : info.positionDeclarations) {
- out.println(" " + positionDeclaration);
- }
- out.println();
-
String desc = MatchStatement.class.getSimpleName();
- out.println(" // CheckStyle: stop line length check");
- out.println(" private static final List<" + desc + "> statements = Collections.unmodifiableList(Arrays.asList(");
-
- int i = 0;
- for (MatchRuleItem matchRule : info.matchRules) {
- String comma = i == info.matchRules.size() - 1 ? "" : ",";
- out.printf(" %s%s\n", matchRule.ruleBuilder(), comma);
- i++;
- }
- out.println(" ));");
- out.println(" // CheckStyle: resume line length check");
- out.println();
out.println(" public Class extends NodeLIRBuilder> forClass() {");
out.println(" return " + topDeclaringClass + ".class;");
out.println(" }");
out.println();
out.println(" @Override");
- out.println(" public List<" + desc + "> statements() {");
+ out.println(" public List<" + desc + "> statements(MatchRuleRegistry.NodeClassLookup lookup) {");
+
+ for (String positionDeclaration : info.positionDeclarations) {
+ out.println(" " + positionDeclaration);
+ }
+ out.println();
+
+ out.println(" // CheckStyle: stop line length check");
+ out.println(" List<" + desc + "> statements = Collections.unmodifiableList(Arrays.asList(");
+
+ int i = 0;
+ for (MatchRuleItem matchRule : info.matchRules) {
+ String comma = i == info.matchRules.size() - 1 ? "" : ",";
+ out.printf(" %s%s\n", matchRule.ruleBuilder(), comma);
+ i++;
+ }
+ out.println(" ));");
+ out.println(" // CheckStyle: resume line length check");
out.println(" return statements;");
out.println(" }");
+
+ out.println();
+
out.println("}");
}
@@ -606,13 +608,12 @@
* @return a string which will construct the MatchStatement instance to match this pattern.
*/
public String ruleBuilder() {
- return String.format("new MatchStatement(\"%s\", %s, %s, %s)", invoker.name, matchPattern, invoker.reflectiveMethodName(), invoker.argumentsListName());
+ return String.format("new MatchStatement(\"%s\", %s, %s.instance, %s)", invoker.name, matchPattern, invoker.wrapperClass(), invoker.argumentsListName());
}
}
/**
- * Used to generate the declarations needed for reflective invocation of the code generation
- * method.
+ * Used to generate the wrapper class to invoke the code generation method.
*/
static class MethodInvokerItem {
final String name;
@@ -627,8 +628,8 @@
this.fields = fields;
}
- String reflectiveMethodName() {
- return methodName + "_invoke";
+ String wrapperClass() {
+ return "MatchGenerator_" + methodName;
}
String argumentsListName() {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Wed May 21 11:45:50 2014 +0200
@@ -27,13 +27,61 @@
import java.util.*;
import java.util.Map.Entry;
+import com.oracle.graal.compiler.common.*;
import com.oracle.graal.compiler.gen.*;
import com.oracle.graal.debug.*;
import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
public class MatchRuleRegistry {
+ /**
+ * Helper interface for mapping between Class and NodeClass. In static compilation environments,
+ * the current NodeClass might not be the same NodeClass used in the target so this provides a
+ * level of indirection.
+ */
+ public static interface NodeClassLookup {
+ NodeClass get(Class> theClass);
+
+ }
+
+ static class DefaultNodeClassLookup implements NodeClassLookup {
+ public NodeClass get(Class> theClass) {
+ return NodeClass.get(theClass);
+ }
+ }
+
+ /**
+ * Convert a list of field names into {@link com.oracle.graal.graph.NodeClass.Position} objects
+ * that can be used to read them during a match. The names should already have been confirmed to
+ * exist in the type.
+ *
+ * @param theClass
+ * @param names
+ * @return an array of Position objects corresponding to the named fields.
+ */
+ public static NodeClass.Position[] findPositions(NodeClassLookup lookup, Class extends ValueNode> theClass, String[] names) {
+ NodeClass.Position[] result = new NodeClass.Position[names.length];
+ NodeClass nodeClass = lookup.get(theClass);
+ for (int i = 0; i < names.length; i++) {
+ for (NodeClass.Position position : nodeClass.getFirstLevelInputPositions()) {
+ String name = nodeClass.getName(position);
+ if (name.endsWith("#NDF")) {
+ name = name.substring(0, name.length() - 4);
+ }
+ if (name.equals(names[i])) {
+ result[i] = position;
+ break;
+ }
+ }
+ if (result[i] == null) {
+ throw new GraalInternalError("unknown field \"%s\" in class %s", names[i], theClass);
+ }
+ }
+ return result;
+ }
+
private static final HashMap, Map, List>> registry = new HashMap<>();
/**
@@ -46,10 +94,11 @@
Map, List> result = registry.get(theClass);
if (result == null) {
+ NodeClassLookup lookup = new DefaultNodeClassLookup();
HashMap, List> localRules = new HashMap<>();
ServiceLoader sl = ServiceLoader.loadInstalled(MatchStatementSet.class);
for (MatchStatementSet rules : sl) {
- localRules.put(rules.forClass(), rules.statements());
+ localRules.put(rules.forClass(), rules.statements(lookup));
}
// Walk the class hierarchy collecting lists and merge them together. The subclass
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Wed May 21 11:45:50 2014 +0200
@@ -24,11 +24,9 @@
import static com.oracle.graal.compiler.GraalDebugConfig.*;
-import java.lang.reflect.*;
import java.util.*;
import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
import com.oracle.graal.compiler.gen.*;
import com.oracle.graal.compiler.match.MatchPattern.MatchResultCode;
import com.oracle.graal.compiler.match.MatchPattern.Result;
@@ -59,14 +57,14 @@
/**
* The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission.
*/
- private Method generatorMethod;
+ private MatchGenerator generatorMethod;
/**
* The name of arguments in the order they are expected to be passed to the generator method.
*/
private String[] arguments;
- public MatchStatement(String name, MatchPattern pattern, Method generator, String[] arguments) {
+ public MatchStatement(String name, MatchPattern pattern, MatchGenerator generator, String[] arguments) {
this.name = name;
this.pattern = pattern;
this.generatorMethod = generator;
@@ -93,23 +91,19 @@
MatchContext context = new MatchContext(builder, this, index, node, nodes);
result = pattern.matchUsage(node, context);
if (result == Result.OK) {
- try {
- // Invoke the generator method and set the result if it's non null.
- ComplexMatchResult value = (ComplexMatchResult) generatorMethod.invoke(builder, buildArgList(context));
- if (value != null) {
- context.setResult(value);
- MatchStatementSuccess.increment();
- Debug.metric("MatchStatement[%s]", getName()).increment();
- return true;
- }
- // The pattern matched but some other code generation constraint disallowed code
- // generation for the pattern.
- if (LogVerbose.getValue()) {
- Debug.log("while matching %s|%s %s %s returned null", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), generatorMethod.getName());
- Debug.log("with nodes %s", formatMatch(node));
- }
- } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
- throw new GraalInternalError(e);
+ // Invoke the generator method and set the result if it's non null.
+ ComplexMatchResult value = generatorMethod.match(builder, buildArgList(context));
+ if (value != null) {
+ context.setResult(value);
+ MatchStatementSuccess.increment();
+ Debug.metric("MatchStatement[%s]", getName()).increment();
+ return true;
+ }
+ // The pattern matched but some other code generation constraint disallowed code
+ // generation for the pattern.
+ if (LogVerbose.getValue()) {
+ Debug.log("while matching %s|%s %s %s returned null", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), generatorMethod.getName());
+ Debug.log("with nodes %s", formatMatch(node));
}
} else {
if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java Wed May 21 11:45:50 2014 +0200
@@ -36,5 +36,5 @@
/**
* @return the {@link MatchStatement}s available for this {@link NodeLIRBuilder} subclass.
*/
- public List statements();
+ public List statements(MatchRuleRegistry.NodeClassLookup lookup);
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/AnsiColor.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/AnsiColor.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.debug;
+
+/**
+ * Ansi terminal color escape codes.
+ */
+public final class AnsiColor {
+ /** Foreground black */
+ public static final String BLACK = "\u001b[30m";
+ /** Foreground red */
+ public static final String RED = "\u001b[31m";
+ /** Foreground green */
+ public static final String GREEN = "\u001b[32m";
+ /** Foreground yellow */
+ public static final String YELLOW = "\u001b[33m";
+ /** Foreground blue */
+ public static final String BLUE = "\u001b[34m";
+ /** Foreground magenta */
+ public static final String MAGENTA = "\u001b[35m";
+ /** Foreground cyan */
+ public static final String CYAN = "\u001b[36m";
+ /** Foreground white */
+ public static final String WHITE = "\u001b[37m";
+
+ /** Foreground bold black */
+ public static final String BOLD_BLACK = "\u001b[30;1m";
+ /** Foreground bold red */
+ public static final String BOLD_RED = "\u001b[31;1m";
+ /** Foreground bold green */
+ public static final String BOLD_GREEN = "\u001b[32;1m";
+ /** Foreground bold yellow */
+ public static final String BOLD_YELLOW = "\u001b[33;1m";
+ /** Foreground bold blue */
+ public static final String BOLD_BLUE = "\u001b[34;1m";
+ /** Foreground bold magenta */
+ public static final String BOLD_MAGENTA = "\u001b[35;1m";
+ /** Foreground bold cyan */
+ public static final String BOLD_CYAN = "\u001b[36;1m";
+ /** Foreground bold white */
+ public static final String BOLD_WHITE = "\u001b[37;1m";
+
+ /** Background black */
+ public static final String BG_BLACK = "\u001b[40m";
+ /** Background red */
+ public static final String BG_RED = "\u001b[41m";
+ /** Background green */
+ public static final String BG_GREEN = "\u001b[42m";
+ /** Background yellow */
+ public static final String BG_YELLOW = "\u001b[43m";
+ /** Background blue */
+ public static final String BG_BLUE = "\u001b[44m";
+ /** Background magenta */
+ public static final String BG_MAGENTA = "\u001b[45m";
+ /** Background cyan */
+ public static final String BG_CYAN = "\u001b[46m";
+ /** Background white */
+ public static final String BG_WHITE = "\u001b[47m";
+
+ /** Reset */
+ public static final String RESET = "\u001b[0m";
+ /** Underline */
+ public static final String UNDERLINED = "\u001b[4m";
+
+ /** Prevent instantiation */
+ private AnsiColor() {
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Wed May 21 11:45:50 2014 +0200
@@ -741,7 +741,7 @@
private static DebugMetric createMetric(String format, Object arg1, Object arg2) {
String name = formatDebugName(format, arg1, arg2);
- boolean conditional = enabledMetrics != null && enabledMetrics.contains(name);
+ boolean conditional = enabledMetrics == null || !enabledMetrics.contains(name);
return new MetricImpl(name, conditional);
}
@@ -981,7 +981,7 @@
private static DebugTimer createTimer(String format, Object arg1, Object arg2) {
String name = formatDebugName(format, arg1, arg2);
- boolean conditional = enabledTimers != null && enabledTimers.contains(name);
+ boolean conditional = enabledTimers == null || !enabledTimers.contains(name);
return new TimerImpl(name, conditional);
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Wed May 21 11:45:50 2014 +0200
@@ -197,4 +197,9 @@
public boolean contains(Node node) {
return isMarked(node);
}
+
+ @Override
+ public String toString() {
+ return snapshot().toString();
+ }
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Wed May 21 11:45:50 2014 +0200
@@ -32,6 +32,9 @@
import java.lang.reflect.*;
import java.util.*;
+import java.util.Map.Entry;
+import java.util.function.*;
+import java.util.stream.*;
import com.amd.okra.*;
import com.oracle.graal.api.code.*;
@@ -69,9 +72,11 @@
import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
import com.oracle.graal.options.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.virtual.nodes.*;
/**
* HSAIL specific backend.
@@ -266,7 +271,7 @@
StructuredGraph hostGraph = hsailCode.getHostGraph();
if (hostGraph != null) {
// TODO get rid of the unverified entry point in the host code
- try (Scope ds = Debug.scope("GeneratingHostGraph")) {
+ try (Scope ds = Debug.scope("GeneratingHostGraph", new DebugDumpScope("HostGraph"))) {
HotSpotBackend hostBackend = getRuntime().getHostBackend();
JavaType[] parameterTypes = new JavaType[hostGraph.getNodes(ParameterNode.class).count()];
Debug.log("Param count: %d", parameterTypes.length);
@@ -726,6 +731,8 @@
asm.emitString(spillsegStringFinal, spillsegDeclarationPosition);
// Emit the epilogue.
+ HSAILHotSpotLIRGenerationResult lirGenRes = ((HSAILCompilationResultBuilder) crb).lirGenRes;
+
int numSRegs = 0;
int numDRegs = 0;
int numStackSlotBytes = 0;
@@ -736,31 +743,39 @@
Set infoUsedRegs = new TreeSet<>();
Set infoUsedStackSlots = new HashSet<>();
List infoList = crb.compilationResult.getInfopoints();
+ Queue workList = new LinkedList<>();
for (Infopoint info : infoList) {
BytecodeFrame frame = info.debugInfo.frame();
while (frame != null) {
- for (int i = 0; i < frame.numLocals + frame.numStack; i++) {
- Value val = frame.values[i];
- if (isLegal(val)) {
- if (isRegister(val)) {
- Register reg = asRegister(val);
- infoUsedRegs.add(reg);
- if (hsailRegConfig.isAllocatableSReg(reg)) {
- numSRegs = Math.max(numSRegs, reg.encoding + 1);
- } else if (hsailRegConfig.isAllocatableDReg(reg)) {
- numDRegs = Math.max(numDRegs, reg.encoding + 1);
- }
- } else if (isStackSlot(val)) {
- StackSlot slot = asStackSlot(val);
- Kind slotKind = slot.getKind();
- int slotSizeBytes = (slotKind.isObject() ? 8 : slotKind.getByteCount());
- int slotOffsetMax = HSAIL.getStackOffsetStart(slot, slotSizeBytes * 8) + slotSizeBytes;
- numStackSlotBytes = Math.max(numStackSlotBytes, slotOffsetMax);
- infoUsedStackSlots.add(slot);
+ workList.add(frame.values);
+ frame = frame.caller();
+ }
+ }
+ while (!workList.isEmpty()) {
+ Value[] values = workList.poll();
+ for (Value val : values) {
+ if (isLegal(val)) {
+ if (isRegister(val)) {
+ Register reg = asRegister(val);
+ infoUsedRegs.add(reg);
+ if (hsailRegConfig.isAllocatableSReg(reg)) {
+ numSRegs = Math.max(numSRegs, reg.encoding + 1);
+ } else if (hsailRegConfig.isAllocatableDReg(reg)) {
+ numDRegs = Math.max(numDRegs, reg.encoding + 1);
}
+ } else if (isStackSlot(val)) {
+ StackSlot slot = asStackSlot(val);
+ Kind slotKind = slot.getKind();
+ int slotSizeBytes = (slotKind.isObject() ? 8 : slotKind.getByteCount());
+ int slotOffsetMax = HSAIL.getStackOffsetStart(slot, slotSizeBytes * 8) + slotSizeBytes;
+ numStackSlotBytes = Math.max(numStackSlotBytes, slotOffsetMax);
+ infoUsedStackSlots.add(slot);
+ } else if (isVirtualObject(val)) {
+ workList.add(((VirtualObject) val).getValues());
+ } else {
+ assert isConstant(val) : "Unsupported value: " + val;
}
}
- frame = frame.caller();
}
}
@@ -923,8 +938,9 @@
asm.emitString0("}; \n");
ExternalCompilationResult compilationResult = (ExternalCompilationResult) crb.compilationResult;
- HSAILHotSpotLIRGenerationResult lirGenRes = ((HSAILCompilationResultBuilder) crb).lirGenRes;
- compilationResult.setHostGraph(prepareHostGraph(method, lirGenRes.getDeopts(), getProviders(), config, numSRegs, numDRegs));
+ if (useHSAILDeoptimization) {
+ compilationResult.setHostGraph(prepareHostGraph(method, lirGenRes.getDeopts(), getProviders(), config, numSRegs, numDRegs));
+ }
}
private static class OopMapArrayBuilder {
@@ -1090,26 +1106,53 @@
}
private static FrameState createFrameState(BytecodeFrame lowLevelFrame, ParameterNode hsailFrame, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs, int numDRegs) {
+ return createFrameState(lowLevelFrame, hsailFrame, providers, config, numSRegs, numDRegs, new HashMap());
+ }
+
+ private static FrameState createFrameState(BytecodeFrame lowLevelFrame, ParameterNode hsailFrame, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs, int numDRegs,
+ Map virtualObjects) {
+ FrameState outterFrameState = null;
+ if (lowLevelFrame.caller() != null) {
+ outterFrameState = createFrameState(lowLevelFrame.caller(), hsailFrame, providers, config, numSRegs, numDRegs, virtualObjects);
+ }
StructuredGraph hostGraph = hsailFrame.graph();
+ Function super Value, ? extends ValueNode> lirValueToHirNode = v -> getNodeForValueFromFrame(v, hsailFrame, hostGraph, providers, config, numSRegs, numDRegs, virtualObjects);
ValueNode[] locals = new ValueNode[lowLevelFrame.numLocals];
for (int i = 0; i < lowLevelFrame.numLocals; i++) {
- locals[i] = getNodeForValueFromFrame(lowLevelFrame.getLocalValue(i), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs);
+ locals[i] = lirValueToHirNode.apply(lowLevelFrame.getLocalValue(i));
}
List stack = new ArrayList<>(lowLevelFrame.numStack);
for (int i = 0; i < lowLevelFrame.numStack; i++) {
- stack.add(getNodeForValueFromFrame(lowLevelFrame.getStackValue(i), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs));
+ stack.add(lirValueToHirNode.apply(lowLevelFrame.getStackValue(i)));
}
ValueNode[] locks = new ValueNode[lowLevelFrame.numLocks];
MonitorIdNode[] monitorIds = new MonitorIdNode[lowLevelFrame.numLocks];
for (int i = 0; i < lowLevelFrame.numLocks; i++) {
HotSpotMonitorValue lockValue = (HotSpotMonitorValue) lowLevelFrame.getLockValue(i);
- locks[i] = getNodeForValueFromFrame(lockValue, hsailFrame, hostGraph, providers, config, numSRegs, numDRegs);
+ locks[i] = lirValueToHirNode.apply(lockValue);
monitorIds[i] = getMonitorIdForHotSpotMonitorValueFromFrame(lockValue, hsailFrame, hostGraph);
}
FrameState frameState = hostGraph.add(new FrameState(lowLevelFrame.getMethod(), lowLevelFrame.getBCI(), locals, stack, locks, monitorIds, lowLevelFrame.rethrowException, false));
- if (lowLevelFrame.caller() != null) {
- frameState.setOuterFrameState(createFrameState(lowLevelFrame.caller(), hsailFrame, providers, config, numSRegs, numDRegs));
+ if (outterFrameState != null) {
+ frameState.setOuterFrameState(outterFrameState);
}
+ Map virtualObjectsCopy;
+ // TODO this could be implemented more efficiently with a mark into the map
+ // unfortunately LinkedHashMap doesn't seem to provide that.
+ List virtualStates = new ArrayList<>(virtualObjects.size());
+ do {
+ virtualObjectsCopy = new HashMap<>(virtualObjects);
+ virtualStates.clear();
+ for (Entry entry : virtualObjectsCopy.entrySet()) {
+ VirtualObject virtualObject = entry.getKey();
+ VirtualObjectNode virtualObjectNode = entry.getValue();
+ List fieldValues = Arrays.stream(virtualObject.getValues()).map(lirValueToHirNode).collect(Collectors.toList());
+ virtualStates.add(new VirtualObjectState(virtualObjectNode, fieldValues));
+ }
+ // New virtual objects may have been discovered while processing the previous set.
+ // Wait until a fixed point is reached
+ } while (virtualObjectsCopy.size() < virtualObjects.size());
+ virtualStates.forEach(vos -> frameState.addVirtualObjectMapping(hostGraph.unique(vos)));
return frameState;
}
@@ -1122,18 +1165,18 @@
}
private static ValueNode getNodeForValueFromFrame(Value localValue, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs,
- int numDRegs) {
+ int numDRegs, Map virtualObjects) {
ValueNode valueNode;
if (localValue instanceof Constant) {
valueNode = ConstantNode.forConstant((Constant) localValue, providers.getMetaAccess(), hostGraph);
} else if (localValue instanceof VirtualObject) {
- throw GraalInternalError.unimplemented();
+ valueNode = getNodeForVirtualObjectFromFrame((VirtualObject) localValue, virtualObjects, hostGraph);
} else if (localValue instanceof StackSlot) {
StackSlot slot = (StackSlot) localValue;
valueNode = getNodeForStackSlotFromFrame(slot, localValue.getKind(), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs);
} else if (localValue instanceof HotSpotMonitorValue) {
HotSpotMonitorValue hotSpotMonitorValue = (HotSpotMonitorValue) localValue;
- return getNodeForValueFromFrame(hotSpotMonitorValue.getOwner(), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs);
+ return getNodeForValueFromFrame(hotSpotMonitorValue.getOwner(), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs, virtualObjects);
} else if (localValue instanceof RegisterValue) {
RegisterValue registerValue = (RegisterValue) localValue;
int regNumber = registerValue.getRegister().number;
@@ -1146,6 +1189,16 @@
return valueNode;
}
+ private static ValueNode getNodeForVirtualObjectFromFrame(VirtualObject virtualObject, Map virtualObjects, StructuredGraph hostGraph) {
+ return virtualObjects.computeIfAbsent(virtualObject, vo -> {
+ if (vo.getType().isArray()) {
+ return hostGraph.add(new VirtualArrayNode(vo.getType().getComponentType(), vo.getValues().length));
+ } else {
+ return hostGraph.add(new VirtualInstanceNode(vo.getType(), true));
+ }
+ });
+ }
+
private static ValueNode getNodeForRegisterFromFrame(int regNumber, Kind valueKind, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config,
int numSRegs) {
ValueNode valueNode;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot.jfr/src/com/oracle/graal/hotspot/jfr/events/JFREventProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.jfr/src/com/oracle/graal/hotspot/jfr/events/JFREventProvider.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.jfr.events;
+
+import java.net.*;
+
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.hotspot.events.*;
+import com.oracle.jrockit.jfr.*;
+
+/**
+ * A JFR implementation for {@link EventProvider}. This implementation is used when Flight Recorder
+ * is turned on.
+ */
+@ServiceProvider(EventProvider.class)
+public final class JFREventProvider implements EventProvider {
+
+ @SuppressWarnings("deprecation") private final Producer producer;
+
+ @SuppressWarnings("deprecation")
+ public JFREventProvider() {
+ try {
+ /*
+ * The "HotSpot JVM" producer is a native producer and we cannot use it. So we create
+ * our own. This has the downside that Mission Control is confused and doesn't show
+ * Graal's events in the "Code" tab. There are plans to revise the JFR code for JDK 9.
+ */
+ producer = new Producer("HotSpot JVM", "Oracle Hotspot JVM", "http://www.oracle.com/hotspot/jvm/");
+ producer.register();
+ } catch (URISyntaxException e) {
+ throw new InternalError(e);
+ }
+
+ // Register event classes with Producer.
+ for (Class> c : JFREventProvider.class.getDeclaredClasses()) {
+ if (c.isAnnotationPresent(EventDefinition.class)) {
+ assert com.oracle.jrockit.jfr.InstantEvent.class.isAssignableFrom(c) : c;
+ registerEvent(c);
+ }
+ }
+ }
+
+ /**
+ * Register an event class with the {@link Producer}.
+ *
+ * @param c event class
+ * @return the {@link EventToken event token}
+ */
+ @SuppressWarnings({"deprecation", "javadoc", "unchecked"})
+ private final EventToken registerEvent(Class> c) {
+ try {
+ return producer.addEvent((Class extends com.oracle.jrockit.jfr.InstantEvent>) c);
+ } catch (InvalidEventDefinitionException | InvalidValueException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ public CompilationEvent newCompilationEvent() {
+ return new JFRCompilationEvent();
+ }
+
+ /**
+ * A JFR compilation event.
+ *
+ *
+ * See: event {@code Compilation} in {@code src/share/vm/trace/trace.xml}
+ */
+ @SuppressWarnings("deprecation")
+ @EventDefinition(name = "Compilation", path = "vm/compiler/compilation")
+ public static class JFRCompilationEvent extends com.oracle.jrockit.jfr.DurationEvent implements CompilationEvent {
+
+ /*
+ * FIXME method should be a Method* but we can't express that in Java.
+ */
+ @ValueDefinition(name = "Java Method") public String method;
+ @ValueDefinition(name = "Compilation ID", relationKey = "COMP_ID") public int compileId;
+ @ValueDefinition(name = "Compilation Level") public short compileLevel;
+ @ValueDefinition(name = "Succeeded") public boolean succeeded;
+ @ValueDefinition(name = "On Stack Replacement") public boolean isOsr;
+ @ValueDefinition(name = "Compiled Code Size", contentType = ContentType.Bytes) public int codeSize;
+ @ValueDefinition(name = "Inlined Code Size", contentType = ContentType.Bytes) public int inlinedBytes;
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public void setCompileId(int id) {
+ this.compileId = id;
+ }
+
+ public void setCompileLevel(int compileLevel) {
+ this.compileLevel = (short) compileLevel;
+ }
+
+ public void setSucceeded(boolean succeeded) {
+ this.succeeded = succeeded;
+ }
+
+ public void setIsOsr(boolean isOsr) {
+ this.isOsr = isOsr;
+ }
+
+ public void setCodeSize(int codeSize) {
+ this.codeSize = codeSize;
+ }
+
+ public void setInlinedBytes(int inlinedBytes) {
+ this.inlinedBytes = inlinedBytes;
+ }
+ }
+
+ public CompilerFailureEvent newCompilerFailureEvent() {
+ return new JFRCompilerFailureEvent();
+ }
+
+ /**
+ * A JFR compiler failure event.
+ *
+ *
+ * See: event {@code CompilerFailure} in {@code src/share/vm/trace/trace.xml}
+ */
+ @SuppressWarnings("deprecation")
+ @EventDefinition(name = "Compilation Failure", path = "vm/compiler/failure")
+ public static class JFRCompilerFailureEvent extends com.oracle.jrockit.jfr.InstantEvent implements CompilerFailureEvent {
+
+ @ValueDefinition(name = "Compilation ID", relationKey = "COMP_ID") public int compileId;
+ @ValueDefinition(name = "Message", description = "The failure message") public String failure;
+
+ public void setCompileId(int id) {
+ this.compileId = id;
+ }
+
+ public void setMessage(String message) {
+ this.failure = message;
+ }
+ }
+
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Wed May 21 11:45:50 2014 +0200
@@ -66,19 +66,19 @@
@Test
public void testStaticFinalObjectAOT() {
StructuredGraph result = compile("getStaticFinalObject", true);
- assertEquals(1, getConstantNodes(result).count());
- assertEquals(getCodeCache().getTarget().wordKind, getConstantNodes(result).first().getKind());
- assertEquals(2, result.getNodes(FloatingReadNode.class).count());
- assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+ assertDeepEquals(1, getConstantNodes(result).count());
+ assertDeepEquals(getCodeCache().getTarget().wordKind, getConstantNodes(result).first().getKind());
+ assertDeepEquals(2, result.getNodes(FloatingReadNode.class).count());
+ assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
}
@Test
public void testStaticFinalObject() {
StructuredGraph result = compile("getStaticFinalObject", false);
- assertEquals(1, getConstantNodes(result).count());
- assertEquals(Kind.Object, getConstantNodes(result).first().getKind());
- assertEquals(0, result.getNodes(FloatingReadNode.class).count());
- assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+ assertDeepEquals(1, getConstantNodes(result).count());
+ assertDeepEquals(Kind.Object, getConstantNodes(result).first().getKind());
+ assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+ assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
}
public static Class getClassObject() {
@@ -90,12 +90,12 @@
StructuredGraph result = compile("getClassObject", true);
NodeIterable filter = getConstantNodes(result);
- assertEquals(1, filter.count());
+ assertDeepEquals(1, filter.count());
HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(AheadOfTimeCompilationTest.class);
- assertEquals(type.klass(), filter.first().asConstant());
+ assertDeepEquals(type.klass(), filter.first().asConstant());
- assertEquals(1, result.getNodes(FloatingReadNode.class).count());
- assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+ assertDeepEquals(1, result.getNodes(FloatingReadNode.class).count());
+ assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
}
@Test
@@ -103,13 +103,13 @@
StructuredGraph result = compile("getClassObject", false);
NodeIterable filter = getConstantNodes(result);
- assertEquals(1, filter.count());
+ assertDeepEquals(1, filter.count());
Object mirror = HotSpotObjectConstant.asObject(filter.first().asConstant());
- assertEquals(Class.class, mirror.getClass());
- assertEquals(AheadOfTimeCompilationTest.class, mirror);
+ assertDeepEquals(Class.class, mirror.getClass());
+ assertDeepEquals(AheadOfTimeCompilationTest.class, mirror);
- assertEquals(0, result.getNodes(FloatingReadNode.class).count());
- assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+ assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+ assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
}
public static Class getPrimitiveClassObject() {
@@ -120,24 +120,24 @@
public void testPrimitiveClassObjectAOT() {
StructuredGraph result = compile("getPrimitiveClassObject", true);
NodeIterable filter = getConstantNodes(result);
- assertEquals(1, filter.count());
- assertEquals(getCodeCache().getTarget().wordKind, filter.first().getKind());
+ assertDeepEquals(1, filter.count());
+ assertDeepEquals(getCodeCache().getTarget().wordKind, filter.first().getKind());
- assertEquals(2, result.getNodes(FloatingReadNode.class).count());
- assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+ assertDeepEquals(2, result.getNodes(FloatingReadNode.class).count());
+ assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
}
@Test
public void testPrimitiveClassObject() {
StructuredGraph result = compile("getPrimitiveClassObject", false);
NodeIterable filter = getConstantNodes(result);
- assertEquals(1, filter.count());
+ assertDeepEquals(1, filter.count());
Object mirror = HotSpotObjectConstant.asObject(filter.first().asConstant());
- assertEquals(Class.class, mirror.getClass());
- assertEquals(Integer.TYPE, mirror);
+ assertDeepEquals(Class.class, mirror.getClass());
+ assertDeepEquals(Integer.TYPE, mirror);
- assertEquals(0, result.getNodes(FloatingReadNode.class).count());
- assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+ assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+ assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
}
public static String getStringObject() {
@@ -159,13 +159,13 @@
StructuredGraph result = compile("getStringObject", compileAOT);
NodeIterable filter = getConstantNodes(result);
- assertEquals(1, filter.count());
+ assertDeepEquals(1, filter.count());
Object mirror = HotSpotObjectConstant.asObject(filter.first().asConstant());
- assertEquals(String.class, mirror.getClass());
- assertEquals("test string", mirror);
+ assertDeepEquals(String.class, mirror.getClass());
+ assertDeepEquals("test string", mirror);
- assertEquals(0, result.getNodes(FloatingReadNode.class).count());
- assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+ assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+ assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
}
public static Boolean getBoxedBoolean() {
@@ -177,23 +177,23 @@
public void testBoxedBooleanAOT() {
StructuredGraph result = compile("getBoxedBoolean", true);
- assertEquals(2, result.getNodes(FloatingReadNode.class).count());
- assertEquals(1, result.getNodes(PiNode.class).count());
- assertEquals(1, getConstantNodes(result).count());
+ assertDeepEquals(2, result.getNodes(FloatingReadNode.class).count());
+ assertDeepEquals(1, result.getNodes(PiNode.class).count());
+ assertDeepEquals(1, getConstantNodes(result).count());
ConstantNode constant = getConstantNodes(result).first();
- assertEquals(Kind.Long, constant.getKind());
- assertEquals(((HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(Boolean.class)).klass(), constant.asConstant());
+ assertDeepEquals(Kind.Long, constant.getKind());
+ assertDeepEquals(((HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(Boolean.class)).klass(), constant.asConstant());
}
@Test
public void testBoxedBoolean() {
StructuredGraph result = compile("getBoxedBoolean", false);
- assertEquals(0, result.getNodes(FloatingReadNode.class).count());
- assertEquals(0, result.getNodes(PiNode.class).count());
- assertEquals(1, getConstantNodes(result).count());
+ assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+ assertDeepEquals(0, result.getNodes(PiNode.class).count());
+ assertDeepEquals(1, getConstantNodes(result).count());
ConstantNode constant = getConstantNodes(result).first();
- assertEquals(Kind.Object, constant.getKind());
- assertEquals(Boolean.TRUE, HotSpotObjectConstant.asObject(constant.asConstant()));
+ assertDeepEquals(Kind.Object, constant.getKind());
+ assertDeepEquals(Boolean.TRUE, HotSpotObjectConstant.asObject(constant.asConstant()));
}
private StructuredGraph compile(String test, boolean compileAOT) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ExplicitExceptionTest.java
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ExplicitExceptionTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ExplicitExceptionTest.java Wed May 21 11:45:50 2014 +0200
@@ -37,7 +37,7 @@
@Override
protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) {
InstalledCode installedCode = super.getCode(method, graph);
- assertEquals(expectedForeignCallCount, graph.getNodes().filter(ForeignCallNode.class).count());
+ assertDeepEquals(expectedForeignCallCount, graph.getNodes().filter(ForeignCallNode.class).count());
return installedCode;
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java Wed May 21 11:45:50 2014 +0200
@@ -45,8 +45,8 @@
Object obj = new Object();
- assertEquals("a string".getClass(), ObjectSubstitutions.getClass("a string"));
- assertEquals(obj.hashCode(), ObjectSubstitutions.hashCode(obj));
+ assertDeepEquals("a string".getClass(), ObjectSubstitutions.getClass("a string"));
+ assertDeepEquals(obj.hashCode(), ObjectSubstitutions.hashCode(obj));
}
@SuppressWarnings("all")
@@ -75,14 +75,14 @@
test("getComponentType");
for (Class> c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
- assertEquals(c.getModifiers(), ClassSubstitutions.getModifiers(c));
- assertEquals(c.isInterface(), ClassSubstitutions.isInterface(c));
- assertEquals(c.isArray(), ClassSubstitutions.isArray(c));
- assertEquals(c.isPrimitive(), ClassSubstitutions.isPrimitive(c));
- assertEquals(c.getSuperclass(), ClassSubstitutions.getSuperclass(c));
- assertEquals(c.getComponentType(), ClassSubstitutions.getComponentType(c));
+ assertDeepEquals(c.getModifiers(), ClassSubstitutions.getModifiers(c));
+ assertDeepEquals(c.isInterface(), ClassSubstitutions.isInterface(c));
+ assertDeepEquals(c.isArray(), ClassSubstitutions.isArray(c));
+ assertDeepEquals(c.isPrimitive(), ClassSubstitutions.isPrimitive(c));
+ assertDeepEquals(c.getSuperclass(), ClassSubstitutions.getSuperclass(c));
+ assertDeepEquals(c.getComponentType(), ClassSubstitutions.getComponentType(c));
for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
- assertEquals(c.isInstance(o), ClassSubstitutions.isInstance(c, o));
+ assertDeepEquals(c.isInstance(o), ClassSubstitutions.isInstance(c, o));
}
}
}
@@ -134,8 +134,8 @@
test("threadInterrupted");
Thread currentThread = Thread.currentThread();
- assertEquals(currentThread, ThreadSubstitutions.currentThread());
- assertEquals(currentThread.isInterrupted(), ThreadSubstitutions.isInterrupted(currentThread, false));
+ assertDeepEquals(currentThread, ThreadSubstitutions.currentThread());
+ assertDeepEquals(currentThread.isInterrupted(), ThreadSubstitutions.isInterrupted(currentThread, false));
}
@SuppressWarnings("all")
@@ -161,7 +161,7 @@
SystemSubstitutions.currentTimeMillis();
SystemSubstitutions.nanoTime();
for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
- assertEquals(System.identityHashCode(o), SystemSubstitutions.identityHashCode(o));
+ assertDeepEquals(System.identityHashCode(o), SystemSubstitutions.identityHashCode(o));
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMonitorValueTest.java
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMonitorValueTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMonitorValueTest.java Wed May 21 11:45:50 2014 +0200
@@ -51,8 +51,8 @@
BytecodeFrame caller = frame.caller();
assertNotNull(caller);
assertNull(caller.caller());
- assertEquals(2, frame.numLocks);
- assertEquals(2, caller.numLocks);
+ assertDeepEquals(2, frame.numLocks);
+ assertDeepEquals(2, caller.numLocks);
HotSpotMonitorValue lock1 = (HotSpotMonitorValue) frame.getLockValue(0);
HotSpotMonitorValue lock2 = (HotSpotMonitorValue) frame.getLockValue(1);
HotSpotMonitorValue lock3 = (HotSpotMonitorValue) caller.getLockValue(0);
@@ -67,7 +67,7 @@
}
}
}
- assertEquals(lock3.getOwner(), lock4.getOwner());
+ assertDeepEquals(lock3.getOwner(), lock4.getOwner());
assertThat(lock1.getOwner(), not(lock2.getOwner()));
return super.addMethod(method, compResult);
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java Wed May 21 11:45:50 2014 +0200
@@ -43,7 +43,7 @@
Object result;
try {
result = nmethod.executeVarargs(null, "b", "c");
- assertEquals(43, result);
+ assertDeepEquals(43, result);
} catch (InvalidInstalledCodeException e) {
Assert.fail("Code was invalidated");
}
@@ -66,7 +66,7 @@
Object result;
try {
result = nmethod.executeVarargs(nmethod, null, null);
- assertEquals(43, result);
+ assertDeepEquals(43, result);
} catch (InvalidInstalledCodeException e) {
Assert.fail("Code was invalidated");
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java Wed May 21 11:45:50 2014 +0200
@@ -26,6 +26,7 @@
import java.lang.ref.*;
import java.lang.reflect.*;
+import com.oracle.graal.phases.common.inlining.policy.InlineEverythingPolicy;
import org.junit.*;
import com.oracle.graal.api.code.*;
@@ -249,7 +250,7 @@
StructuredGraph graph = parse(snippet);
HighTierContext highContext = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
MidTierContext midContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
- new InliningPhase(new InliningPhase.InlineEverythingPolicy(), new CanonicalizerPhase(true)).apply(graph, highContext);
+ new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase(true)).apply(graph, highContext);
new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
new GuardLoweringPhase().apply(graph, midContext);
new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed May 21 11:45:50 2014 +0200
@@ -40,6 +40,7 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.code.CallingConvention.Type;
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
import com.oracle.graal.baseline.*;
import com.oracle.graal.compiler.*;
import com.oracle.graal.compiler.common.*;
@@ -47,6 +48,9 @@
import com.oracle.graal.debug.Debug.Scope;
import com.oracle.graal.debug.internal.*;
import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.events.*;
+import com.oracle.graal.hotspot.events.EventProvider.CompilationEvent;
+import com.oracle.graal.hotspot.events.EventProvider.CompilerFailureEvent;
import com.oracle.graal.hotspot.meta.*;
import com.oracle.graal.hotspot.phases.*;
import com.oracle.graal.java.*;
@@ -103,6 +107,13 @@
private final int id;
private final AtomicReference status;
+ /**
+ * The executor processing the Graal compilation queue this task was placed on. This will be
+ * null for blocking compilations or if compilations are scheduled as native HotSpot
+ * {@linkplain #ctask CompileTask}s.
+ */
+ private final ExecutorService executor;
+
private StructuredGraph graph;
/**
@@ -116,7 +127,7 @@
* A {@link com.sun.management.ThreadMXBean} to be able to query some information about the
* current compiler thread, e.g. total allocated bytes.
*/
- private final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
+ private static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
/**
* The address of the native CompileTask associated with this compilation. If 0L, then this
@@ -125,7 +136,8 @@
*/
private final long ctask;
- public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, long ctask, boolean blocking) {
+ public CompilationTask(ExecutorService executor, HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, long ctask, boolean blocking) {
+ this.executor = executor;
this.backend = backend;
this.method = method;
this.entryBCI = entryBCI;
@@ -144,6 +156,11 @@
return method;
}
+ /**
+ * Returns the compilation id of this task.
+ *
+ * @return compile id
+ */
public int getId() {
return id;
}
@@ -156,7 +173,7 @@
public void run() {
withinEnqueue.set(Boolean.FALSE);
try {
- runCompilation(true);
+ runCompilation();
} finally {
withinEnqueue.set(Boolean.TRUE);
status.set(CompilationStatus.Finished);
@@ -226,7 +243,14 @@
return method.getCompilationProfilingInfo(osrCompilation);
}
- public void runCompilation(boolean clearFromCompilationQueue) {
+ public void runCompilation() {
+ if (executor != null && executor.isShutdown()) {
+ // We don't want to do any unnecessary compilation if the Graal compilation
+ // queue has been shutdown. Note that we leave the JVM_ACC_QUEUED bit set
+ // for the method so that it won't be re-scheduled for compilation.
+ return;
+ }
+
/*
* no code must be outside this try/finally because it could happen otherwise that
* clearQueuedForCompilation() is not executed
@@ -237,12 +261,16 @@
long previousInlinedBytecodes = InlinedBytecodes.getCurrentValue();
long previousCompilationTime = CompilationTime.getCurrentValue();
HotSpotInstalledCode installedCode = null;
+ final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
+
+ // Log a compilation event.
+ EventProvider eventProvider = Graal.getRequiredCapability(EventProvider.class);
+ CompilationEvent compilationEvent = eventProvider.newCompilationEvent();
try (TimerCloseable a = CompilationTime.start()) {
if (!tryToChangeStatus(CompilationStatus.Queued, CompilationStatus.Running)) {
return;
}
- boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
// If there is already compiled code for this method on our level we simply return.
// Graal compiles are always at the highest compile level, even in non-tiered mode so we
@@ -266,6 +294,8 @@
final long allocatedBytesBefore = threadMXBean.getThreadAllocatedBytes(threadId);
try (Scope s = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) {
+ // Begin the compilation event.
+ compilationEvent.begin();
if (UseBaselineCompiler.getValue() == true) {
HotSpotProviders providers = backend.getProviders();
@@ -307,6 +337,9 @@
} catch (Throwable e) {
throw Debug.handle(e);
} finally {
+ // End the compilation event.
+ compilationEvent.end();
+
filter.remove();
final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed();
@@ -346,16 +379,37 @@
if (PrintStackTraceOnException.getValue() || ExitVMOnException.getValue()) {
t.printStackTrace(TTY.cachedOut);
}
+
+ // Log a failure event.
+ CompilerFailureEvent event = eventProvider.newCompilerFailureEvent();
+ if (event.shouldWrite()) {
+ event.setCompileId(getId());
+ event.setMessage(t.getMessage());
+ event.commit();
+ }
+
if (ExitVMOnException.getValue()) {
System.exit(-1);
}
} finally {
- int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
+ final int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
+
+ // Log a compilation event.
+ if (compilationEvent.shouldWrite()) {
+ compilationEvent.setMethod(MetaUtil.format("%H.%n(%p)", method));
+ compilationEvent.setCompileId(getId());
+ compilationEvent.setCompileLevel(config.compilationLevelFullOptimization);
+ compilationEvent.setSucceeded(true);
+ compilationEvent.setIsOsr(isOSR);
+ compilationEvent.setCodeSize(installedCode.getSize());
+ compilationEvent.setInlinedBytes(processedBytes);
+ compilationEvent.commit();
+ }
+
if (ctask != 0L) {
unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes);
}
if ((config.ciTime || config.ciTimeEach || PrintCompRate.getValue() != 0) && installedCode != null) {
-
long time = CompilationTime.getCurrentValue() - previousCompilationTime;
TimeUnit timeUnit = CompilationTime.getTimeUnit();
long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS);
@@ -363,7 +417,7 @@
c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, processedBytes, time, timeUnitsPerSecond, installedCode);
}
- if (clearFromCompilationQueue) {
+ if (executor != null) {
assert method.isQueuedForCompilation();
method.clearQueuedForCompilation();
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Wed May 21 11:45:50 2014 +0200
@@ -317,7 +317,7 @@
class CTWCompilationTask extends CompilationTask {
CTWCompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method) {
- super(backend, method, INVOCATION_ENTRY_BCI, 0L, false);
+ super(null, backend, method, INVOCATION_ENTRY_BCI, 0L, false);
}
/**
@@ -349,7 +349,7 @@
HotSpotBackend backend = runtime.getHostBackend();
CompilationTask task = new CTWCompilationTask(backend, method);
- task.runCompilation(false);
+ task.runCompilation();
compileTime += (System.currentTimeMillis() - start);
compiledMethodsCounter++;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Wed May 21 11:45:50 2014 +0200
@@ -43,6 +43,7 @@
import com.oracle.graal.compiler.target.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.events.*;
import com.oracle.graal.hotspot.logging.*;
import com.oracle.graal.hotspot.meta.*;
import com.oracle.graal.options.*;
@@ -274,6 +275,8 @@
}
registerBackend(factory.createBackend(this, hostBackend));
}
+
+ eventProvider = createEventProvider();
}
private HotSpotBackend registerBackend(HotSpotBackend backend) {
@@ -379,6 +382,22 @@
private final NodeCollectionsProvider nodeCollectionsProvider = new DefaultNodeCollectionsProvider();
+ private final EventProvider eventProvider;
+
+ private EventProvider createEventProvider() {
+ if (config.flightRecorder) {
+ ServiceLoader sl = ServiceLoader.loadInstalled(EventProvider.class);
+ EventProvider singleProvider = null;
+ for (EventProvider ep : sl) {
+ assert singleProvider == null : String.format("multiple %s service implementations found: %s and %s", EventProvider.class.getName(), singleProvider.getClass().getName(),
+ ep.getClass().getName());
+ singleProvider = ep;
+ }
+ return singleProvider;
+ }
+ return new EmptyEventProvider();
+ }
+
@SuppressWarnings("unchecked")
@Override
public T getCapability(Class clazz) {
@@ -392,6 +411,8 @@
return (T) getHostProviders().getSnippetReflection();
} else if (clazz == MethodHandleAccessProvider.class) {
return (T) getHostProviders().getMethodHandleAccess();
+ } else if (clazz == EventProvider.class) {
+ return (T) eventProvider;
}
return null;
}
diff -r a43ff5d18350 -r a6eeb3750238 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 Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed May 21 11:45:50 2014 +0200
@@ -30,6 +30,7 @@
import com.oracle.graal.compiler.common.*;
import com.oracle.graal.hotspot.bridge.*;
import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspotvmconfig.*;
/**
* Used to access native configuration details.
@@ -65,14 +66,21 @@
public final int maxFrameSize = 16 * 1024;
HotSpotVMConfig(CompilerToVM compilerToVm) {
+ compilerToVm.initializeConfiguration(this);
+ assert verifyInitialization();
+
+ oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment());
+ klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment);
+
+ assert check();
+ }
+
+ /**
+ * Check that the initialization produces the same result as the values captured through
+ * vmStructs.
+ */
+ private boolean verifyInitialization() {
/** These fields are set in {@link CompilerToVM#initializeConfiguration}. */
- gHotSpotVMStructs = 0;
- gHotSpotVMTypes = 0;
- gHotSpotVMIntConstants = 0;
- gHotSpotVMLongConstants = 0;
-
- compilerToVm.initializeConfiguration(this);
-
assert gHotSpotVMStructs != 0;
assert gHotSpotVMTypes != 0;
assert gHotSpotVMIntConstants != 0;
@@ -114,7 +122,7 @@
String type = annotation.type();
VMFields.Field entry = vmFields.get(name);
if (entry == null) {
- if (annotation.optional() || !isRequired(currentArch, annotation.archs())) {
+ if (!isRequired(currentArch, annotation.archs())) {
continue;
}
throw new IllegalArgumentException("field not found: " + name);
@@ -129,13 +137,13 @@
switch (annotation.get()) {
case OFFSET:
- setField(f, entry.getOffset());
+ checkField(f, entry.getOffset());
break;
case ADDRESS:
- setField(f, entry.getAddress());
+ checkField(f, entry.getAddress());
break;
case VALUE:
- setField(f, entry.getValue());
+ checkField(f, entry.getValue());
break;
default:
throw GraalInternalError.shouldNotReachHere("unknown kind " + annotation.get());
@@ -149,7 +157,7 @@
}
switch (annotation.get()) {
case SIZE:
- setField(f, entry.getSize());
+ checkField(f, entry.getSize());
break;
default:
throw GraalInternalError.shouldNotReachHere("unknown kind " + annotation.get());
@@ -164,7 +172,7 @@
}
throw new IllegalArgumentException("constant not found: " + name);
}
- setField(f, entry.getValue());
+ checkField(f, entry.getValue());
} else if (f.isAnnotationPresent(HotSpotVMFlag.class)) {
HotSpotVMFlag annotation = f.getAnnotation(HotSpotVMFlag.class);
String name = annotation.name();
@@ -176,14 +184,10 @@
throw new IllegalArgumentException("flag not found: " + name);
}
- setField(f, entry.getValue());
+ checkField(f, entry.getValue());
}
}
-
- oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment());
- klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment);
-
- assert check();
+ return true;
}
private final CompressEncoding oopEncoding;
@@ -197,29 +201,29 @@
return klassEncoding;
}
- private void setField(Field field, Object value) {
+ private void checkField(Field field, Object value) {
try {
Class> fieldType = field.getType();
if (fieldType == boolean.class) {
if (value instanceof String) {
- field.setBoolean(this, Boolean.valueOf((String) value));
+ assert field.getBoolean(this) == Boolean.valueOf((String) value) : field + " " + value + " " + field.getBoolean(this);
} else if (value instanceof Boolean) {
- field.setBoolean(this, (boolean) value);
+ assert field.getBoolean(this) == (boolean) value : field + " " + value + " " + field.getBoolean(this);
} else if (value instanceof Long) {
- field.setBoolean(this, ((long) value) != 0);
+ assert field.getBoolean(this) == (((long) value) != 0) : field + " " + value + " " + field.getBoolean(this);
} else {
GraalInternalError.shouldNotReachHere(value.getClass().getSimpleName());
}
} else if (fieldType == int.class) {
if (value instanceof Integer) {
- field.setInt(this, (int) value);
+ assert field.getInt(this) == (int) value : field + " " + value + " " + field.getInt(this);
} else if (value instanceof Long) {
- field.setInt(this, (int) (long) value);
+ assert field.getInt(this) == (int) (long) value : field + " " + value + " " + field.getInt(this);
} else {
GraalInternalError.shouldNotReachHere(value.getClass().getSimpleName());
}
} else if (fieldType == long.class) {
- field.setLong(this, (long) value);
+ assert field.getLong(this) == (long) value : field + " " + value + " " + field.getLong(this);
} else {
GraalInternalError.shouldNotReachHere(field.toString());
}
@@ -248,14 +252,14 @@
/**
* VMStructEntry (see vmStructs.hpp).
*/
- private long gHotSpotVMStructs;
- private long gHotSpotVMStructEntryTypeNameOffset;
- private long gHotSpotVMStructEntryFieldNameOffset;
- private long gHotSpotVMStructEntryTypeStringOffset;
- private long gHotSpotVMStructEntryIsStaticOffset;
- private long gHotSpotVMStructEntryOffsetOffset;
- private long gHotSpotVMStructEntryAddressOffset;
- private long gHotSpotVMStructEntryArrayStride;
+ @HotSpotVMValue(expression = "gHotSpotVMStructs", get = HotSpotVMValue.Type.ADDRESS) @Stable private long gHotSpotVMStructs;
+ @HotSpotVMValue(expression = "gHotSpotVMStructEntryTypeNameOffset") @Stable private long gHotSpotVMStructEntryTypeNameOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMStructEntryFieldNameOffset") @Stable private long gHotSpotVMStructEntryFieldNameOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMStructEntryTypeStringOffset") @Stable private long gHotSpotVMStructEntryTypeStringOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMStructEntryIsStaticOffset") @Stable private long gHotSpotVMStructEntryIsStaticOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMStructEntryOffsetOffset") @Stable private long gHotSpotVMStructEntryOffsetOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMStructEntryAddressOffset") @Stable private long gHotSpotVMStructEntryAddressOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMStructEntryArrayStride") @Stable private long gHotSpotVMStructEntryArrayStride;
class VMFields implements Iterable {
@@ -364,14 +368,14 @@
/**
* VMTypeEntry (see vmStructs.hpp).
*/
- private long gHotSpotVMTypes;
- private long gHotSpotVMTypeEntryTypeNameOffset;
- private long gHotSpotVMTypeEntrySuperclassNameOffset;
- private long gHotSpotVMTypeEntryIsOopTypeOffset;
- private long gHotSpotVMTypeEntryIsIntegerTypeOffset;
- private long gHotSpotVMTypeEntryIsUnsignedOffset;
- private long gHotSpotVMTypeEntrySizeOffset;
- private long gHotSpotVMTypeEntryArrayStride;
+ @HotSpotVMValue(expression = "gHotSpotVMTypes", get = HotSpotVMValue.Type.ADDRESS) @Stable private long gHotSpotVMTypes;
+ @HotSpotVMValue(expression = "gHotSpotVMTypeEntryTypeNameOffset") @Stable private long gHotSpotVMTypeEntryTypeNameOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMTypeEntrySuperclassNameOffset") @Stable private long gHotSpotVMTypeEntrySuperclassNameOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMTypeEntryIsOopTypeOffset") @Stable private long gHotSpotVMTypeEntryIsOopTypeOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMTypeEntryIsIntegerTypeOffset") @Stable private long gHotSpotVMTypeEntryIsIntegerTypeOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMTypeEntryIsUnsignedOffset") @Stable private long gHotSpotVMTypeEntryIsUnsignedOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMTypeEntrySizeOffset") @Stable private long gHotSpotVMTypeEntrySizeOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMTypeEntryArrayStride") @Stable private long gHotSpotVMTypeEntryArrayStride;
class VMTypes implements Iterable {
@@ -476,10 +480,10 @@
/**
* VMIntConstantEntry (see vmStructs.hpp).
*/
- private long gHotSpotVMIntConstants;
- private long gHotSpotVMIntConstantEntryNameOffset;
- private long gHotSpotVMIntConstantEntryValueOffset;
- private long gHotSpotVMIntConstantEntryArrayStride;
+ @HotSpotVMValue(expression = "gHotSpotVMIntConstants", get = HotSpotVMValue.Type.ADDRESS) @Stable private long gHotSpotVMIntConstants;
+ @HotSpotVMValue(expression = "gHotSpotVMIntConstantEntryNameOffset") @Stable private long gHotSpotVMIntConstantEntryNameOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMIntConstantEntryValueOffset") @Stable private long gHotSpotVMIntConstantEntryValueOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMIntConstantEntryArrayStride") @Stable private long gHotSpotVMIntConstantEntryArrayStride;
class VMIntConstants implements Iterable {
@@ -540,10 +544,10 @@
/**
* VMLongConstantEntry (see vmStructs.hpp).
*/
- private long gHotSpotVMLongConstants;
- private long gHotSpotVMLongConstantEntryNameOffset;
- private long gHotSpotVMLongConstantEntryValueOffset;
- private long gHotSpotVMLongConstantEntryArrayStride;
+ @HotSpotVMValue(expression = "gHotSpotVMLongConstants", get = HotSpotVMValue.Type.ADDRESS) @Stable private long gHotSpotVMLongConstants;
+ @HotSpotVMValue(expression = "gHotSpotVMLongConstantEntryNameOffset") @Stable private long gHotSpotVMLongConstantEntryNameOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMLongConstantEntryValueOffset") @Stable private long gHotSpotVMLongConstantEntryValueOffset;
+ @HotSpotVMValue(expression = "gHotSpotVMLongConstantEntryArrayStride") @Stable private long gHotSpotVMLongConstantEntryArrayStride;
class VMLongConstants implements Iterable {
@@ -699,7 +703,7 @@
}
// os information, register layout, code generation, ...
- @HotSpotVMConstant(name = "ASSERT") @Stable public boolean cAssertions;
+ @HotSpotVMValue(expression = "DEBUG_ONLY(1) NOT_DEBUG(0)") @Stable public boolean cAssertions;
public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows");
@HotSpotVMFlag(name = "CodeEntryAlignment") @Stable public int codeEntryAlignment;
@@ -708,8 +712,8 @@
@HotSpotVMFlag(name = "CITimeEach") @Stable public boolean ciTimeEach;
@HotSpotVMFlag(name = "CompileThreshold") @Stable public long compileThreshold;
@HotSpotVMFlag(name = "CompileTheWorld") @Stable public boolean compileTheWorld;
- @HotSpotVMFlag(name = "CompileTheWorldStartAt") @Stable public int compileTheWorldStartAt;
- @HotSpotVMFlag(name = "CompileTheWorldStopAt") @Stable public int compileTheWorldStopAt;
+ @HotSpotVMFlag(name = "CompileTheWorldStartAt", optional = true) @Stable public int compileTheWorldStartAt;
+ @HotSpotVMFlag(name = "CompileTheWorldStopAt", optional = true) @Stable public int compileTheWorldStopAt;
@HotSpotVMFlag(name = "DontCompileHugeMethods") @Stable public boolean dontCompileHugeMethods;
@HotSpotVMFlag(name = "HugeMethodLimit") @Stable public int hugeMethodLimit;
@HotSpotVMFlag(name = "PrintCompilation") @Stable public boolean printCompilation;
@@ -737,6 +741,8 @@
@HotSpotVMFlag(name = "AllocatePrefetchStepSize") @Stable public int allocatePrefetchStepSize;
@HotSpotVMFlag(name = "AllocatePrefetchDistance") @Stable public int allocatePrefetchDistance;
+ @HotSpotVMFlag(name = "FlightRecorder", optional = true) @Stable public boolean flightRecorder;
+
@HotSpotVMField(name = "Universe::_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap;
@HotSpotVMField(name = "CollectedHeap::_total_collections", type = "unsigned int", get = HotSpotVMField.Type.OFFSET) @Stable private int collectedHeapTotalCollectionsOffset;
@@ -846,12 +852,12 @@
@HotSpotVMType(name = "vtableEntry", get = HotSpotVMType.Type.SIZE) @Stable public int vtableEntrySize;
@HotSpotVMField(name = "vtableEntry::_method", type = "Method*", get = HotSpotVMField.Type.OFFSET) @Stable public int vtableEntryMethodOffset;
- @Stable public int instanceKlassVtableStartOffset;
+ @HotSpotVMValue(expression = "InstanceKlass::vtable_start_offset() * HeapWordSize") @Stable public int instanceKlassVtableStartOffset;
/**
* The offset of the array length word in an array object's header.
*/
- @Stable public int arrayLengthOffset;
+ @HotSpotVMValue(expression = "arrayOopDesc::length_offset_in_bytes()") @Stable public int arrayLengthOffset;
@HotSpotVMField(name = "Array::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1LengthOffset;
@HotSpotVMField(name = "Array::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1DataOffset;
@@ -893,7 +899,7 @@
@HotSpotVMField(name = "JavaThread::_is_method_handle_return", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int threadIsMethodHandleReturnOffset;
@HotSpotVMField(name = "JavaThread::_satb_mark_queue", type = "ObjPtrQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadSatbMarkQueueOffset;
@HotSpotVMField(name = "JavaThread::_vm_result", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectResultOffset;
- @HotSpotVMField(name = "JavaThread::_graal_counters[0]", type = "jlong", get = HotSpotVMField.Type.OFFSET, optional = true) @Stable public int graalCountersThreadOffset;
+ @HotSpotVMValue(expression = "in_bytes(JavaThread::graal_counters_offset())") @Stable public int graalCountersThreadOffset;
/**
* An invalid value for {@link #rtldDefault}.
@@ -907,7 +913,7 @@
* void* (const char *filename, char *ebuf, int ebuflen)
*
*/
- @Stable public long dllLoad;
+ @HotSpotVMValue(expression = "os::dll_load", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dllLoad;
/**
* Address of the library lookup routine. The C signature of this routine is:
@@ -916,7 +922,7 @@
* void* (void* handle, const char* name)
*
*/
- @Stable public long dllLookup;
+ @HotSpotVMValue(expression = "os::dll_lookup", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dllLookup;
/**
* A pseudo-handle which when used as the first argument to {@link #dllLookup} means lookup will
@@ -924,7 +930,7 @@
* this field is {@value #INVALID_RTLD_DEFAULT_HANDLE}, then this capability is not supported on
* the current platform.
*/
- @Stable public long rtldDefault = INVALID_RTLD_DEFAULT_HANDLE;
+ @HotSpotVMValue(expression = "RTLD_DEFAULT", defines = {"TARGET_OS_FAMILY_bsd", "TARGET_OS_FAMILY_linux"}, get = HotSpotVMValue.Type.ADDRESS) @Stable public long rtldDefault = INVALID_RTLD_DEFAULT_HANDLE;
/**
* This field is used to pass exception objects into and out of the runtime system during
@@ -1033,9 +1039,9 @@
@HotSpotVMField(name = "HSAILFrame::_pc_offset", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFramePcOffset;
@HotSpotVMField(name = "HSAILFrame::_num_s_regs", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameNumSRegOffset;
@HotSpotVMField(name = "HSAILFrame::_num_d_regs", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameNumDRegOffset;
- @HotSpotVMConstant(name = "sizeof(HSAILFrame)") @Stable public int hsailFrameHeaderSize;
- @HotSpotVMConstant(name = "sizeof(Hsail::HSAILKernelDeoptimization)") @Stable public int hsailKernelDeoptimizationHeaderSize;
- @HotSpotVMConstant(name = "sizeof(Hsail::HSAILDeoptimizationInfo)") @Stable public int hsailDeoptimizationInfoHeaderSize;
+ @HotSpotVMType(name = "HSAILFrame", get = HotSpotVMType.Type.SIZE) @Stable public int hsailFrameHeaderSize;
+ @HotSpotVMType(name = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMType.Type.SIZE) @Stable public int hsailKernelDeoptimizationHeaderSize;
+ @HotSpotVMType(name = "Hsail::HSAILDeoptimizationInfo", get = HotSpotVMType.Type.SIZE) @Stable public int hsailDeoptimizationInfoHeaderSize;
/**
* Mark word right shift to get identity hash code.
@@ -1064,6 +1070,7 @@
@HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline;
@HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden;
@HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex;
+ @HotSpotVMConstant(name = "Method::invalid_vtable_index") @Stable public int invalidVtableIndex;
@HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch;
@HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes;
@@ -1074,7 +1081,7 @@
/**
* Value of Method::extra_stack_entries().
*/
- @Stable public int extraStackEntries;
+ @HotSpotVMValue(expression = "Method::extra_stack_entries()") @Stable public int extraStackEntries;
@HotSpotVMField(name = "ConstMethod::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodConstantsOffset;
@HotSpotVMField(name = "ConstMethod::_flags", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodFlagsOffset;
@@ -1155,8 +1162,8 @@
@HotSpotVMField(name = "Universe::_non_oop_bits", type = "intptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long nonOopBits;
@HotSpotVMField(name = "StubRoutines::_verify_oop_count", type = "jint", get = HotSpotVMField.Type.ADDRESS) @Stable public long verifyOopCounterAddress;
- @Stable public long verifyOopMask;
- @Stable public long verifyOopBits;
+ @HotSpotVMValue(expression = "Universe::verify_oop_mask()") @Stable public long verifyOopMask;
+ @HotSpotVMValue(expression = "Universe::verify_oop_bits()") @Stable public long verifyOopBits;
@HotSpotVMField(name = "CollectedHeap::_barrier_set", type = "BarrierSet*", get = HotSpotVMField.Type.OFFSET) @Stable public int collectedHeapBarrierSetOffset;
@@ -1246,13 +1253,13 @@
@HotSpotVMType(name = "BasicLock", get = HotSpotVMType.Type.SIZE) @Stable public int basicLockSize;
@HotSpotVMField(name = "BasicLock::_displaced_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int basicLockDisplacedHeaderOffset;
- @Stable public long heapEndAddress;
- @Stable public long heapTopAddress;
+ @HotSpotVMValue(expression = "Universe::heap()->end_addr()", get = HotSpotVMValue.Type.ADDRESS) @Stable public long heapEndAddress;
+ @HotSpotVMValue(expression = "Universe::heap()->top_addr()", get = HotSpotVMValue.Type.ADDRESS) @Stable public long heapTopAddress;
@HotSpotVMField(name = "Thread::_allocated_bytes", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int threadAllocatedBytesOffset;
@HotSpotVMFlag(name = "TLABWasteIncrement") @Stable public int tlabRefillWasteIncrement;
- @Stable public int tlabAlignmentReserve;
+ @HotSpotVMValue(expression = "ThreadLocalAllocBuffer::alignment_reserve()") @Stable public int tlabAlignmentReserve;
@HotSpotVMField(name = "ThreadLocalAllocBuffer::_start", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferStartOffset;
@HotSpotVMField(name = "ThreadLocalAllocBuffer::_end", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferEndOffset;
@@ -1301,7 +1308,7 @@
}
@HotSpotVMFlag(name = "TLABStats") @Stable public boolean tlabStats;
- @Stable public boolean inlineContiguousAllocationSupported;
+ @HotSpotVMValue(expression = " !CMSIncrementalMode && Universe::heap()->supports_inline_contig_alloc()") @Stable public boolean inlineContiguousAllocationSupported;
/**
* The DataLayout header size is the same as the cell size.
@@ -1393,41 +1400,43 @@
@HotSpotVMField(name = "StubRoutines::_unsafe_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long unsafeArraycopy;
@HotSpotVMField(name = "StubRoutines::_generic_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long genericArraycopy;
- @Stable public long newInstanceAddress;
- @Stable public long newArrayAddress;
- @Stable public long newMultiArrayAddress;
- @Stable public long dynamicNewArrayAddress;
- @Stable public long dynamicNewInstanceAddress;
- @Stable public long registerFinalizerAddress;
- @Stable public long threadIsInterruptedAddress;
- @Stable public long vmMessageAddress;
- @Stable public long identityHashCodeAddress;
- @Stable public long exceptionHandlerForPcAddress;
- @Stable public long exceptionHandlerForReturnAddressAddress;
- @Stable public long osrMigrationEndAddress;
- @Stable public long monitorenterAddress;
- @Stable public long monitorexitAddress;
- @Stable public long createNullPointerExceptionAddress;
- @Stable public long createOutOfBoundsExceptionAddress;
- @Stable public long logPrimitiveAddress;
- @Stable public long logObjectAddress;
- @Stable public long logPrintfAddress;
- @Stable public long vmErrorAddress;
- @Stable public long writeBarrierPreAddress;
- @Stable public long writeBarrierPostAddress;
- @Stable public long validateObject;
- @Stable public long javaTimeMillisAddress;
- @Stable public long javaTimeNanosAddress;
- @Stable public long arithmeticSinAddress;
- @Stable public long arithmeticCosAddress;
- @Stable public long arithmeticTanAddress;
- @Stable public long loadAndClearExceptionAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::new_instance", get = HotSpotVMValue.Type.ADDRESS) @Stable public long newInstanceAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::new_array", get = HotSpotVMValue.Type.ADDRESS) @Stable public long newArrayAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::new_multi_array", get = HotSpotVMValue.Type.ADDRESS) @Stable public long newMultiArrayAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::dynamic_new_array", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dynamicNewArrayAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::dynamic_new_instance", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dynamicNewInstanceAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::thread_is_interrupted", get = HotSpotVMValue.Type.ADDRESS) @Stable public long threadIsInterruptedAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::vm_message", get = HotSpotVMValue.Type.ADDRESS) @Stable public long vmMessageAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::identity_hash_code", get = HotSpotVMValue.Type.ADDRESS) @Stable public long identityHashCodeAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::exception_handler_for_pc", get = HotSpotVMValue.Type.ADDRESS) @Stable public long exceptionHandlerForPcAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::monitorenter", get = HotSpotVMValue.Type.ADDRESS) @Stable public long monitorenterAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::monitorexit", get = HotSpotVMValue.Type.ADDRESS) @Stable public long monitorexitAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::create_null_exception", get = HotSpotVMValue.Type.ADDRESS) @Stable public long createNullPointerExceptionAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::create_out_of_bounds_exception", get = HotSpotVMValue.Type.ADDRESS) @Stable public long createOutOfBoundsExceptionAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::log_primitive", get = HotSpotVMValue.Type.ADDRESS) @Stable public long logPrimitiveAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::log_object", get = HotSpotVMValue.Type.ADDRESS) @Stable public long logObjectAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::log_printf", get = HotSpotVMValue.Type.ADDRESS) @Stable public long logPrintfAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::vm_error", get = HotSpotVMValue.Type.ADDRESS) @Stable public long vmErrorAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::load_and_clear_exception", get = HotSpotVMValue.Type.ADDRESS) @Stable public long loadAndClearExceptionAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::write_barrier_pre", get = HotSpotVMValue.Type.ADDRESS) @Stable public long writeBarrierPreAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::write_barrier_post", get = HotSpotVMValue.Type.ADDRESS) @Stable public long writeBarrierPostAddress;
+ @HotSpotVMValue(expression = "GraalRuntime::validate_object", get = HotSpotVMValue.Type.ADDRESS) @Stable public long validateObject;
- @Stable public int graalCountersSize;
+ @HotSpotVMValue(expression = "SharedRuntime::register_finalizer", get = HotSpotVMValue.Type.ADDRESS) @Stable public long registerFinalizerAddress;
+ @HotSpotVMValue(expression = "SharedRuntime::exception_handler_for_return_address", get = HotSpotVMValue.Type.ADDRESS) @Stable public long exceptionHandlerForReturnAddressAddress;
+ @HotSpotVMValue(expression = "SharedRuntime::OSR_migration_end", get = HotSpotVMValue.Type.ADDRESS) @Stable public long osrMigrationEndAddress;
- @Stable public long deoptimizationFetchUnrollInfo;
- @Stable public long deoptimizationUncommonTrap;
- @Stable public long deoptimizationUnpackFrames;
+ @HotSpotVMValue(expression = "os::javaTimeMillis", get = HotSpotVMValue.Type.ADDRESS) @Stable public long javaTimeMillisAddress;
+ @HotSpotVMValue(expression = "os::javaTimeNanos", get = HotSpotVMValue.Type.ADDRESS) @Stable public long javaTimeNanosAddress;
+ @HotSpotVMValue(expression = "SharedRuntime::dsin", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticSinAddress;
+ @HotSpotVMValue(expression = "SharedRuntime::dcos", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticCosAddress;
+ @HotSpotVMValue(expression = "SharedRuntime::dtan", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticTanAddress;
+
+ @HotSpotVMValue(expression = "(jint) GraalCounterSize") @Stable public int graalCountersSize;
+
+ @HotSpotVMValue(expression = "Deoptimization::fetch_unroll_info", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationFetchUnrollInfo;
+ @HotSpotVMValue(expression = "Deoptimization::uncommon_trap", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUncommonTrap;
+ @HotSpotVMValue(expression = "Deoptimization::unpack_frames", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUnpackFrames;
@HotSpotVMConstant(name = "Deoptimization::Reason_none") @Stable public int deoptReasonNone;
@HotSpotVMConstant(name = "Deoptimization::Reason_null_check") @Stable public int deoptReasonNullCheck;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConstant.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConstant.java Tue May 13 19:19:27 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * 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;
-
-import java.lang.annotation.*;
-
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface HotSpotVMConstant {
-
- String name();
-
- /**
- * List of architectures where this constant is required. Names are derived from
- * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
- * required on all architectures.
- */
- String[] archs() default {};
-
-}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMField.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMField.java Tue May 13 19:19:27 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * 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;
-
-import java.lang.annotation.*;
-
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface HotSpotVMField {
-
- enum Type {
- OFFSET,
- ADDRESS,
- VALUE;
- }
-
- String name();
-
- String type();
-
- Type get();
-
- /**
- * List of architectures where this constant is required. Names are derived from
- * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
- * required on all architectures.
- */
- String[] archs() default {};
-
- boolean optional() default false;
-}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java Tue May 13 19:19:27 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * 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;
-
-import java.lang.annotation.*;
-
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface HotSpotVMFlag {
-
- String name();
-
- /**
- * List of architectures where this constant is required. Names are derived from
- * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
- * required on all architectures.
- */
- String[] archs() default {};
-
- boolean optional() default false;
-}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMType.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMType.java Tue May 13 19:19:27 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * 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;
-
-import java.lang.annotation.*;
-
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface HotSpotVMType {
-
- enum Type {
- SIZE;
- }
-
- String name();
-
- Type get();
-}
diff -r a43ff5d18350 -r a6eeb3750238 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 Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed May 21 11:45:50 2014 +0200
@@ -35,13 +35,12 @@
public interface CompilerToVM {
/**
- * Copies the original bytecode of a given method into a given byte array.
+ * Copies the original bytecode of a given method into a new byte array and returns it.
*
* @param metaspaceMethod the metaspace Method object
- * @param code the array into which to copy the original bytecode
- * @return the value of {@code code}
+ * @return a new byte array containing the original bytecode
*/
- byte[] initializeBytecode(long metaspaceMethod, byte[] code);
+ byte[] initializeBytecode(long metaspaceMethod);
int exceptionTableLength(long metaspaceMethod);
@@ -248,7 +247,7 @@
void initializeConfiguration(HotSpotVMConfig config);
- long resolveMethod(long metaspaceKlass, String name, String signature);
+ long resolveMethod(long metaspaceKlassExactReceiver, long metaspaceMethod, long metaspaceKlassCaller);
long getClassInitializer(long metaspaceKlass);
@@ -353,4 +352,6 @@
void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
void resolveInvokeDynamic(long metaspaceConstantPool, int index);
+
+ int getVtableIndexForInterface(long metaspaceKlass, long metaspaceMethod);
}
diff -r a43ff5d18350 -r a6eeb3750238 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 Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed May 21 11:45:50 2014 +0200
@@ -43,7 +43,7 @@
public native long getMetaspaceMethod(Class> holder, int slot);
@Override
- public native byte[] initializeBytecode(long metaspaceMethod, byte[] code);
+ public native byte[] initializeBytecode(long metaspaceMethod);
@Override
public native int exceptionTableLength(long metaspaceMethod);
@@ -99,7 +99,7 @@
public native void initializeConfiguration(HotSpotVMConfig config);
@Override
- public native long resolveMethod(long metaspaceKlass, String name, String signature);
+ public native long resolveMethod(long metaspaceKlassExactReceiver, long metaspaceMethod, long metaspaceKlassCaller);
@Override
public native boolean hasFinalizableSubclass(long metaspaceKlass);
@@ -182,4 +182,6 @@
public native long getTimeStamp();
public native void resolveInvokeDynamic(long metaspaceConstantPool, int index);
+
+ public native int getVtableIndexForInterface(long metaspaceKlass, long metaspaceMethod);
}
diff -r a43ff5d18350 -r a6eeb3750238 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 Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed May 21 11:45:50 2014 +0200
@@ -91,7 +91,7 @@
* is in the proper state.
*/
static class Queue {
- private ThreadPoolExecutor executor;
+ private final ThreadPoolExecutor executor;
Queue(CompilerThreadFactory factory) {
executor = new ThreadPoolExecutor(Threads.getValue(), Threads.getValue(), 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue(), factory);
@@ -117,11 +117,19 @@
executor.execute(task);
}
+ /**
+ * @see ExecutorService#isShutdown()
+ */
+ public boolean isShutdown() {
+ return executor.isShutdown();
+ }
+
public void shutdown() throws InterruptedException {
assert CompilationTask.isWithinEnqueue();
- executor.shutdown();
- if (Debug.isEnabled() && Dump.getValue() != null) {
- // Wait 2 seconds to flush out all graph dumps that may be of interest
+ executor.shutdownNow();
+ if (Debug.isEnabled() && (Dump.getValue() != null || areMetricsOrTimersEnabled())) {
+ // Wait up to 2 seconds to flush out all graph dumps and stop metrics/timers
+ // being updated.
executor.awaitTermination(2, TimeUnit.SECONDS);
}
}
@@ -472,18 +480,6 @@
printMap(new DebugValueScope(null, result), debugValues);
}
- static long collectTotal(DebugValue value) {
- List maps = DebugValueMap.getTopLevelMaps();
- long total = 0;
- for (int i = 0; i < maps.size(); i++) {
- DebugValueMap map = maps.get(i);
- int index = value.getIndex();
- total += map.getCurrentValue(index);
- total += collectTotal(map.getChildren(), index);
- }
- return total;
- }
-
private static long collectTotal(List maps, int index) {
long total = 0;
for (int i = 0; i < maps.size(); i++) {
@@ -570,8 +566,8 @@
void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, long ctask, final boolean blocking) {
if (ctask != 0L) {
HotSpotBackend backend = runtime.getHostBackend();
- CompilationTask task = new CompilationTask(backend, method, entryBCI, ctask, false);
- task.runCompilation(false);
+ CompilationTask task = new CompilationTask(null, backend, method, entryBCI, ctask, false);
+ task.runCompilation();
return;
}
@@ -596,13 +592,14 @@
if (method.tryToQueueForCompilation()) {
assert method.isQueuedForCompilation();
- HotSpotBackend backend = runtime.getHostBackend();
- CompilationTask task = new CompilationTask(backend, method, entryBCI, ctask, block);
-
try {
- compileQueue.execute(task);
- if (block) {
- task.block();
+ if (!compileQueue.executor.isShutdown()) {
+ HotSpotBackend backend = runtime.getHostBackend();
+ CompilationTask task = new CompilationTask(compileQueue.executor, backend, method, entryBCI, ctask, block);
+ compileQueue.execute(task);
+ if (block) {
+ task.block();
+ }
}
} catch (RejectedExecutionException e) {
// The compile queue was already shut down.
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/events/EmptyEventProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/events/EmptyEventProvider.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.events;
+
+import com.oracle.graal.compiler.common.*;
+
+/**
+ * An empty implementation for {@link EventProvider}. This implementation is used when no logging is
+ * requested.
+ */
+public final class EmptyEventProvider implements EventProvider {
+
+ public CompilationEvent newCompilationEvent() {
+ return new EmptyCompilationEvent();
+ }
+
+ class EmptyCompilationEvent implements CompilationEvent {
+ public void commit() {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ public boolean shouldWrite() {
+ // Events of this class should never been written.
+ return false;
+ }
+
+ public void begin() {
+ }
+
+ public void end() {
+ }
+
+ public void setMethod(String method) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ public void setCompileId(int compileId) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ public void setCompileLevel(int compileLevel) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ public void setSucceeded(boolean succeeded) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ public void setIsOsr(boolean isOsr) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ public void setCodeSize(int codeSize) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ public void setInlinedBytes(int inlinedBytes) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ }
+
+ public CompilerFailureEvent newCompilerFailureEvent() {
+ return new EmptyCompilerFailureEvent();
+ }
+
+ class EmptyCompilerFailureEvent implements CompilerFailureEvent {
+ public void commit() {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ public boolean shouldWrite() {
+ // Events of this class should never been written.
+ return false;
+ }
+
+ public void setCompileId(int compileId) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ public void setMessage(String message) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ }
+
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/events/EventProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/events/EventProvider.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.events;
+
+/**
+ * A provider that provides a specific implementation for events that can be logged in the compiler.
+ */
+public interface EventProvider {
+
+ /**
+ * An instant event is an event that is not considered to have taken any time.
+ */
+ interface InstantEvent {
+ /**
+ * Commits the event.
+ */
+ void commit();
+
+ /**
+ * Determines if this particular event instance would be committed to the data stream right
+ * now if application called {@link #commit()}. This in turn depends on whether the event is
+ * enabled and possible other factors.
+ *
+ * @return if this event would be committed on a call to {@link #commit()}.
+ */
+ boolean shouldWrite();
+ }
+
+ /**
+ * Timed events describe an operation that somehow consumes time.
+ */
+ interface TimedEvent extends InstantEvent {
+ /**
+ * Starts the timing for this event.
+ */
+ void begin();
+
+ /**
+ * Ends the timing period for this event.
+ */
+ void end();
+ }
+
+ /**
+ * Creates a new {@link CompilationEvent}.
+ *
+ * @return a compilation event
+ */
+ CompilationEvent newCompilationEvent();
+
+ /**
+ * A compilation event.
+ */
+ interface CompilationEvent extends TimedEvent {
+ void setMethod(String method);
+
+ void setCompileId(int compileId);
+
+ void setCompileLevel(int compileLevel);
+
+ void setSucceeded(boolean succeeded);
+
+ void setIsOsr(boolean isOsr);
+
+ void setCodeSize(int codeSize);
+
+ void setInlinedBytes(int inlinedBytes);
+ }
+
+ /**
+ * Creates a new {@link CompilerFailureEvent}.
+ *
+ * @return a compiler failure event
+ */
+ CompilerFailureEvent newCompilerFailureEvent();
+
+ /**
+ * A compiler failure event.
+ */
+ interface CompilerFailureEvent extends InstantEvent {
+ void setCompileId(int compileId);
+
+ void setMessage(String message);
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Wed May 21 11:45:50 2014 +0200
@@ -230,29 +230,26 @@
JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
LoweredCallTargetNode loweredCallTarget = null;
- if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
-
+ boolean isVirtualOrInterface = callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface;
+ if (InlineVTableStubs.getValue() && isVirtualOrInterface && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
- if (!hsMethod.getDeclaringClass().isInterface()) {
- if (hsMethod.isInVirtualMethodTable()) {
- int vtableEntryOffset = hsMethod.vtableEntryOffset();
- assert vtableEntryOffset > 0;
- Kind wordKind = runtime.getTarget().wordKind;
- ValueNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
+ ResolvedJavaType receiverType = invoke.getReceiverType();
+ if (hsMethod.isInVirtualMethodTable(receiverType)) {
+ Kind wordKind = runtime.getTarget().wordKind;
+ ValueNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
- ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
- // We use LocationNode.ANY_LOCATION for the reads that access the
- // compiled code entry as HotSpot does not guarantee they are final
- // values.
- ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
- StampFactory.forKind(wordKind), BarrierType.NONE, false));
+ ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod, receiverType);
+ // We use LocationNode.ANY_LOCATION for the reads that access the
+ // compiled code entry as HotSpot does not guarantee they are final
+ // values.
+ ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
+ StampFactory.forKind(wordKind), BarrierType.NONE, false));
- loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
- CallingConvention.Type.JavaCall));
+ loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
+ CallingConvention.Type.JavaCall));
- graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
- graph.addAfterFixed(metaspaceMethod, compiledEntry);
- }
+ graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
+ graph.addAfterFixed(metaspaceMethod, compiledEntry);
}
}
@@ -554,8 +551,8 @@
private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
StructuredGraph graph = loadMethodNode.graph();
- ResolvedJavaMethod method = loadMethodNode.getMethod();
- ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method);
+ HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) loadMethodNode.getMethod();
+ ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method, loadMethodNode.getReceiverType());
graph.replaceFixed(loadMethodNode, metaspaceMethod);
}
@@ -816,12 +813,11 @@
return false;
}
- private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
- HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
- assert !hsMethod.getDeclaringClass().isInterface();
- assert hsMethod.isInVirtualMethodTable();
+ private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, HotSpotResolvedJavaMethod method, ResolvedJavaType receiverType) {
+ return createReadVirtualMethod(graph, wordKind, hub, method.vtableEntryOffset(receiverType));
+ }
- int vtableEntryOffset = hsMethod.vtableEntryOffset();
+ private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, int vtableEntryOffset) {
assert vtableEntryOffset > 0;
// We use LocationNode.ANY_LOCATION for the reads that access the vtable
// entry as HotSpot does not guarantee that this is a final value.
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Wed May 21 11:45:50 2014 +0200
@@ -416,7 +416,7 @@
if ((metaspacePointer & config.compilerToVMSymbolTag) != 0) {
final long metaspaceSymbol = metaspacePointer & ~config.compilerToVMSymbolTag;
String name = new HotSpotSymbol(metaspaceSymbol).asString();
- return HotSpotUnresolvedJavaType.create(name);
+ return HotSpotUnresolvedJavaType.create("L" + name + ";");
} else {
assert (metaspacePointer & config.compilerToVMKlassTag) == 0;
return HotSpotResolvedObjectType.fromMetaspaceKlass(metaspacePointer);
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Wed May 21 11:45:50 2014 +0200
@@ -22,6 +22,7 @@
*/
package com.oracle.graal.hotspot.meta;
+import static com.oracle.graal.compiler.common.GraalInternalError.*;
import static com.oracle.graal.compiler.common.GraalOptions.*;
import static com.oracle.graal.compiler.common.UnsafeAccess.*;
import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
@@ -33,7 +34,6 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.api.meta.ProfilingInfo.TriState;
-import com.oracle.graal.compiler.common.*;
import com.oracle.graal.debug.*;
import com.oracle.graal.hotspot.*;
import com.oracle.graal.hotspot.debug.*;
@@ -195,7 +195,7 @@
return null;
}
if (code == null && holder.isLinked()) {
- code = runtime().getCompilerToVM().initializeBytecode(metaspaceMethod, new byte[getCodeSize()]);
+ code = runtime().getCompilerToVM().initializeBytecode(metaspaceMethod);
assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length;
}
return code;
@@ -589,22 +589,34 @@
/**
* Returns the offset of this method into the v-table. The method must have a v-table entry as
- * indicated by {@link #isInVirtualMethodTable()}, otherwise an exception is thrown.
+ * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is
+ * thrown.
*
* @return the offset of this method into the v-table
*/
- public int vtableEntryOffset() {
- if (!isInVirtualMethodTable() || !holder.isInitialized()) {
- throw new GraalInternalError("%s does not have a vtable entry", this);
- }
+ public int vtableEntryOffset(ResolvedJavaType resolved) {
+ guarantee(isInVirtualMethodTable(resolved), "%s does not have a vtable entry", this);
HotSpotVMConfig config = runtime().getConfig();
- final int vtableIndex = getVtableIndex();
+ final int vtableIndex = getVtableIndex(resolved);
return config.instanceKlassVtableStartOffset + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset;
}
@Override
- public boolean isInVirtualMethodTable() {
- return getVtableIndex() >= 0;
+ public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
+ return getVtableIndex(resolved) >= 0;
+ }
+
+ private int getVtableIndex(ResolvedJavaType resolved) {
+ if (!holder.isLinked()) {
+ return runtime().getConfig().invalidVtableIndex;
+ }
+ if (holder.isInterface()) {
+ if (resolved.isArray() || resolved.isInterface()) {
+ return runtime().getConfig().invalidVtableIndex;
+ }
+ return getVtableIndexForInterface(resolved);
+ }
+ return getVtableIndex();
}
/**
@@ -620,6 +632,11 @@
return result;
}
+ private int getVtableIndexForInterface(ResolvedJavaType resolved) {
+ HotSpotResolvedObjectType hotspotType = (HotSpotResolvedObjectType) resolved;
+ return runtime().getCompilerToVM().getVtableIndexForInterface(hotspotType.getMetaspaceKlass(), getMetaspaceMethod());
+ }
+
/**
* The {@link SpeculationLog} for methods compiled by Graal hang off this per-declaring-type
* {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Wed May 21 11:45:50 2014 +0200
@@ -25,6 +25,7 @@
import static com.oracle.graal.api.meta.MetaUtil.*;
import static com.oracle.graal.compiler.common.UnsafeAccess.*;
import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.net.*;
@@ -107,7 +108,7 @@
/**
* Gets the metaspace Klass for this type.
*/
- private long metaspaceKlass() {
+ public long getMetaspaceKlass() {
return HotSpotGraalRuntime.unsafeReadWord(javaClass, runtime().getConfig().klassOffset);
}
@@ -118,7 +119,7 @@
public int getAccessFlags() {
HotSpotVMConfig config = runtime().getConfig();
- return unsafe.getInt(metaspaceKlass() + config.klassAccessFlagsOffset);
+ return unsafe.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset);
}
@Override
@@ -141,7 +142,7 @@
if (isArray()) {
return getElementalType(this).isFinal() ? this : null;
} else if (isInterface()) {
- final long implementorMetaspaceKlass = runtime().getCompilerToVM().getKlassImplementor(metaspaceKlass());
+ final long implementorMetaspaceKlass = runtime().getCompilerToVM().getKlassImplementor(getMetaspaceKlass());
// No implementor.
if (implementorMetaspaceKlass == 0) {
@@ -192,7 +193,7 @@
* @return value of the subklass field as metaspace klass pointer
*/
private long getSubklass() {
- return unsafeReadWord(metaspaceKlass() + runtime().getConfig().subklassOffset);
+ return unsafeReadWord(getMetaspaceKlass() + runtime().getConfig().subklassOffset);
}
@Override
@@ -271,7 +272,7 @@
@Override
public boolean hasFinalizableSubclass() {
assert !isArray();
- return runtime().getCompilerToVM().hasFinalizableSubclass(metaspaceKlass());
+ return runtime().getCompilerToVM().hasFinalizableSubclass(getMetaspaceKlass());
}
@Override
@@ -309,7 +310,7 @@
* @return state field value of this type
*/
private int getState() {
- return unsafe.getByte(metaspaceKlass() + runtime().getConfig().klassStateOffset) & 0xFF;
+ return unsafe.getByte(getMetaspaceKlass() + runtime().getConfig().klassStateOffset) & 0xFF;
}
@Override
@@ -354,13 +355,17 @@
}
@Override
- public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
- assert method instanceof HotSpotMethod;
- if (!method.isAbstract() && method.getDeclaringClass().equals(this)) {
+ public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
+ assert !callerType.isArray();
+ if (!method.isAbstract() && method.getDeclaringClass().equals(this) && method.isPublic()) {
return method;
}
-
- final long resolvedMetaspaceMethod = runtime().getCompilerToVM().resolveMethod(metaspaceKlass(), method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor());
+ if (!method.getDeclaringClass().isAssignableFrom(this)) {
+ return null;
+ }
+ HotSpotResolvedJavaMethod hotSpotMethod = (HotSpotResolvedJavaMethod) method;
+ HotSpotResolvedObjectType hotSpotCallerType = (HotSpotResolvedObjectType) callerType;
+ final long resolvedMetaspaceMethod = runtime().getCompilerToVM().resolveMethod(getMetaspaceKlass(), hotSpotMethod.getMetaspaceMethod(), hotSpotCallerType.getMetaspaceKlass());
if (resolvedMetaspaceMethod == 0) {
return null;
}
@@ -373,7 +378,7 @@
public ConstantPool constantPool() {
if (constantPool == null) {
- final long metaspaceConstantPool = unsafe.getAddress(metaspaceKlass() + runtime().getConfig().instanceKlassConstantsOffset);
+ final long metaspaceConstantPool = unsafe.getAddress(getMetaspaceKlass() + runtime().getConfig().instanceKlassConstantsOffset);
constantPool = new HotSpotConstantPool(metaspaceConstantPool);
}
return constantPool;
@@ -389,7 +394,7 @@
assert !isInterface();
HotSpotVMConfig config = runtime().getConfig();
- final int layoutHelper = unsafe.getInt(metaspaceKlass() + config.klassLayoutHelperOffset);
+ final int layoutHelper = unsafe.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset);
assert layoutHelper > config.klassLayoutHelperNeutralValue : "must be instance";
// See: Klass::layout_helper_size_in_bytes
@@ -475,7 +480,7 @@
public FieldInfo(int index) {
HotSpotVMConfig config = runtime().getConfig();
// Get Klass::_fields
- final long metaspaceFields = unsafe.getAddress(metaspaceKlass() + config.instanceKlassFieldsOffset);
+ final long metaspaceFields = unsafe.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset);
assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code";
metaspaceData = metaspaceFields + config.arrayU2DataOffset + config.fieldInfoFieldSlots * Short.BYTES * index;
}
@@ -611,7 +616,7 @@
*/
private int getFieldCount() {
HotSpotVMConfig config = runtime().getConfig();
- final long metaspaceFields = unsafe.getAddress(metaspaceKlass() + config.instanceKlassFieldsOffset);
+ final long metaspaceFields = unsafe.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset);
int metaspaceFieldsLength = unsafe.getInt(metaspaceFields + config.arrayU1LengthOffset);
int fieldCount = 0;
@@ -633,7 +638,7 @@
@Override
public String getSourceFileName() {
HotSpotVMConfig config = runtime().getConfig();
- final int sourceFileNameIndex = unsafe.getChar(metaspaceKlass() + config.klassSourceFileNameIndexOffset);
+ final int sourceFileNameIndex = unsafe.getChar(getMetaspaceKlass() + config.klassSourceFileNameIndexOffset);
if (sourceFileNameIndex == 0) {
return null;
}
@@ -654,7 +659,7 @@
* Gets the metaspace Klass boxed in a {@link Constant}.
*/
public Constant klass() {
- return HotSpotMetaspaceConstant.forMetaspaceObject(runtime().getTarget().wordKind, metaspaceKlass(), this);
+ return HotSpotMetaspaceConstant.forMetaspaceObject(runtime().getTarget().wordKind, getMetaspaceKlass(), this);
}
public boolean isPrimaryType() {
@@ -663,7 +668,7 @@
public int superCheckOffset() {
HotSpotVMConfig config = runtime().getConfig();
- return unsafe.getInt(metaspaceKlass() + config.superCheckOffsetOffset);
+ return unsafe.getInt(getMetaspaceKlass() + config.superCheckOffsetOffset);
}
public long prototypeMarkWord() {
@@ -671,7 +676,7 @@
if (isArray()) {
return config.arrayPrototypeMarkWord();
} else {
- return unsafeReadWord(metaspaceKlass() + config.prototypeMarkWordOffset);
+ return unsafeReadWord(getMetaspaceKlass() + config.prototypeMarkWordOffset);
}
}
@@ -731,7 +736,7 @@
}
public ResolvedJavaMethod getClassInitializer() {
- final long metaspaceMethod = runtime().getCompilerToVM().getClassInitializer(metaspaceKlass());
+ final long metaspaceMethod = runtime().getCompilerToVM().getClassInitializer(getMetaspaceKlass());
if (metaspaceMethod != 0L) {
return createMethod(metaspaceMethod);
}
@@ -745,12 +750,6 @@
@Override
public String toString() {
- String simpleName;
- if (isArray() || isInterface()) {
- simpleName = getName();
- } else {
- simpleName = getName().substring(1, getName().length() - 1);
- }
- return "HotSpotType<" + simpleName + ", resolved>";
+ return "HotSpotType<" + getName() + ", resolved>";
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java Wed May 21 11:45:50 2014 +0200
@@ -163,7 +163,7 @@
}
@Override
- public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
+ public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
return null;
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java Wed May 21 11:45:50 2014 +0200
@@ -32,56 +32,28 @@
public class HotSpotUnresolvedJavaType extends HotSpotJavaType {
private static final long serialVersionUID = -2320936267633521314L;
- public final String simpleName;
- public final int dimensions;
- public HotSpotUnresolvedJavaType(String name, String simpleName, int dimensions) {
+ public HotSpotUnresolvedJavaType(String name) {
super(name);
- assert dimensions >= 0;
- this.simpleName = simpleName;
- this.dimensions = dimensions;
}
/**
* Creates an unresolved type for a valid {@link JavaType#getName() type name}.
*/
public static HotSpotUnresolvedJavaType create(String name) {
- int dims = 0;
- int startIndex = 0;
- while (name.charAt(startIndex) == '[') {
- startIndex++;
- dims++;
- }
-
- // Decode name if necessary.
- if (name.charAt(name.length() - 1) == ';') {
- assert name.charAt(startIndex) == 'L';
- return new HotSpotUnresolvedJavaType(name, name.substring(startIndex + 1, name.length() - 1), dims);
- } else {
- return new HotSpotUnresolvedJavaType(HotSpotUnresolvedJavaType.getFullName(name, dims), name, dims);
- }
- }
-
- public static String getFullName(String name, int dimensions) {
- StringBuilder str = new StringBuilder(name.length() + dimensions + 2);
- for (int i = 0; i < dimensions; i++) {
- str.append('[');
- }
- str.append('L').append(name).append(';');
- return str.toString();
+ assert name.charAt(name.length() - 1) == ';' : name;
+ return new HotSpotUnresolvedJavaType(name);
}
@Override
public JavaType getComponentType() {
- assert dimensions > 0 : "no array class" + getName();
- String name = getFullName(getName(), dimensions - 1);
- return new HotSpotUnresolvedJavaType(name, simpleName, dimensions - 1);
+ assert getName().charAt(0) == '[' : "no array class" + getName();
+ return new HotSpotUnresolvedJavaType(getName().substring(1));
}
@Override
public JavaType getArrayClass() {
- String name = getFullName(getName(), dimensions + 1);
- return new HotSpotUnresolvedJavaType(name, simpleName, dimensions + 1);
+ return new HotSpotUnresolvedJavaType('[' + getName());
}
@Override
@@ -91,7 +63,7 @@
@Override
public int hashCode() {
- return simpleName.hashCode();
+ return getName().hashCode();
}
@Override
@@ -103,12 +75,12 @@
return false;
}
HotSpotUnresolvedJavaType that = (HotSpotUnresolvedJavaType) obj;
- return this.simpleName.equals(that.simpleName) && this.dimensions == that.dimensions;
+ return this.getName().equals(that.getName());
}
@Override
public String toString() {
- return "HotSpotType<" + simpleName + ", unresolved>";
+ return "HotSpotType<" + getName() + ", unresolved>";
}
@Override
diff -r a43ff5d18350 -r a6eeb3750238 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 Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed May 21 11:45:50 2014 +0200
@@ -179,15 +179,11 @@
@Snippet
public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
@ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @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, threadRegister, maybeUnroll, typeContext);
+ return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false);
}
private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, @ConstantParameter Register threadRegister,
- @ConstantParameter boolean maybeUnroll, String typeContext) {
+ @ConstantParameter boolean maybeUnroll, String typeContext, boolean skipNegativeCheck) {
Object result;
int alignment = wordSize();
int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
@@ -195,7 +191,7 @@
Word top = readTlabTop(thread);
Word end = readTlabEnd(thread);
Word newTop = top.add(allocationSize);
- if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+ if ((skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
writeTlabTop(thread, newTop);
emitPrefetchAllocate(newTop, true);
newarray_loopInit.inc();
@@ -246,7 +242,7 @@
int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
- return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type");
+ return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", true);
}
/**
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Wed May 21 11:45:50 2014 +0200
@@ -97,7 +97,7 @@
// check that array length is small enough for fast path.
Word thread = registerAsWord(threadRegister);
- if (length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
+ if (length >= 0 && length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging());
if (memory.notEqual(0)) {
if (logging()) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Wed May 21 11:45:50 2014 +0200
@@ -22,7 +22,6 @@
*/
package com.oracle.graal.hotspot.stubs;
-import static com.oracle.graal.api.meta.DeoptimizationAction.*;
import static com.oracle.graal.api.meta.DeoptimizationReason.*;
import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
import static com.oracle.graal.hotspot.nodes.CStringNode.*;
@@ -78,7 +77,7 @@
if (isObjectResult) {
getAndClearObjectResult(thread);
}
- DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+ DeoptimizeCallerNode.deopt(DeoptimizationAction.None, RuntimeConstraint);
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspotvmconfig/src/META-INF/services/javax.annotation.processing.Processor
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/META-INF/services/javax.annotation.processing.Processor Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,1 @@
+com.oracle.graal.hotspotvmconfig.HotSpotVMConfigProcessor
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConfigProcessor.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConfigProcessor.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.hotspotvmconfig;
+
+import java.io.*;
+import java.lang.annotation.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.*;
+
+import com.oracle.graal.compiler.common.*;
+
+@SupportedAnnotationTypes({"com.oracle.graal.hotspotvmconfig.HotSpotVMConstant", "com.oracle.graal.hotspotvmconfig.HotSpotVMFlag", "com.oracle.graal.hotspotvmconfig.HotSpotVMField",
+ "com.oracle.graal.hotspotvmconfig.HotSpotVMType", "com.oracle.graal.hotspotvmconfig.HotSpotVMValue"})
+public class HotSpotVMConfigProcessor extends AbstractProcessor {
+
+ public HotSpotVMConfigProcessor() {
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latest();
+ }
+
+ /**
+ * Set to true to enable logging to a local file during annotation processing. There's no normal
+ * channel for any debug messages and debugging annotation processors requires some special
+ * setup.
+ */
+ private static final boolean DEBUG = true;
+
+ private static final String LOGFILE = "/tmp/hotspotvmconfigprocessor.log";
+
+ private static PrintWriter log;
+
+ /**
+ * Logging facility for the debugging the annotation processor.
+ */
+
+ private static synchronized PrintWriter getLog() {
+ if (log == null) {
+ try {
+ log = new PrintWriter(new FileWriter(LOGFILE, true));
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ return log;
+ }
+
+ private static synchronized void logMessage(String format, Object... args) {
+ if (!DEBUG) {
+ return;
+ }
+ PrintWriter bw = getLog();
+ if (bw != null) {
+ bw.printf(format, args);
+ bw.flush();
+ }
+ }
+
+ private static synchronized void logException(Throwable t) {
+ if (!DEBUG) {
+ return;
+ }
+ PrintWriter bw = getLog();
+ if (bw != null) {
+ t.printStackTrace(bw);
+ bw.flush();
+ }
+ }
+
+ /**
+ * Bugs in an annotation processor can cause silent failure so try to report any exception
+ * throws as errors.
+ */
+ private void reportExceptionThrow(Element element, Throwable t) {
+ if (element != null) {
+ logMessage("throw for %s:\n", element);
+ }
+ logException(t);
+ processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 8)), element);
+ }
+
+ //@formatter:off
+ String[] prologue = new String[]{
+ "// The normal wrappers boolAt and intxAt skip constant flags",
+ "static bool boolAt(char* name, bool* value) {",
+ " Flag* result = Flag::find_flag(name, strlen(name), true, true);",
+ " if (result == NULL) return false;",
+ " if (!result->is_bool()) return false;",
+ " *value = result->get_bool();",
+ " return true;",
+ "}",
+ "",
+ "static bool intxAt(char* name, intx* value) {",
+ " Flag* result = Flag::find_flag(name, strlen(name), true, true);",
+ " if (result == NULL) return false;",
+ " if (!result->is_intx()) return false;",
+ " *value = result->get_intx();",
+ " return true;",
+ "}",
+ "",
+ "#define set_boolean(name, value) vmconfig_oop->bool_field_put(fs.offset(), value)",
+ "#define set_int(name, value) vmconfig_oop->int_field_put(fs.offset(), (int)value)",
+ "#define set_long(name, value) vmconfig_oop->long_field_put(fs.offset(), value)",
+ "#define set_address(name, value) do { set_long(name, (jlong) value); } while (0)",
+ "",
+ "#define set_optional_boolean_flag(varName, flagName) do { bool flagValue; if (boolAt((char*) flagName, &flagValue)) { set_boolean(varName, flagValue); } } while (0)",
+ "#define set_optional_int_flag(varName, flagName) do { intx flagValue; if (intxAt((char*) flagName, &flagValue)) { set_int(varName, flagValue); } } while (0)",
+ "#define set_optional_long_flag(varName, flagName) do { intx flagValue; if (intxAt((char*) flagName, &flagValue)) { set_long(varName, flagValue); } } while (0)",
+ "",
+ "void VMStructs::initHotSpotVMConfig(oop vmconfig_oop) {",
+ " InstanceKlass* vmconfig_klass = InstanceKlass::cast(vmconfig_oop->klass());",
+ "",
+ " for (JavaFieldStream fs(vmconfig_klass); !fs.done(); fs.next()) {",
+ };
+ //@formatter:on
+
+ String outputName = "HotSpotVMConfig.inline.hpp";
+ String outputDirectory = "hotspot";
+
+ private void createFiles(Map annotations, Element element) {
+
+ Filer filer = processingEnv.getFiler();
+ try (PrintWriter out = createSourceFile(outputDirectory, outputName, filer, element)) {
+
+ for (String line : prologue) {
+ out.println(line);
+ }
+
+ out.println();
+
+ Set fieldTypes = new HashSet<>();
+ for (String key : annotations.keySet()) {
+ fieldTypes.add(annotations.get(key).getType());
+ }
+ // For each type of field, generate a switch on the length of the symbol and then do a
+ // direct compare. In general this reduces each operation to 2 tests plus a string
+ // compare. Being more prefect than that is probably not worth it.
+ for (String type : fieldTypes) {
+ String sigtype = type.equals("boolean") ? "bool" : type;
+ out.println(" if (fs.signature() == vmSymbols::" + sigtype + "_signature()) {");
+ Set lengths = new HashSet<>();
+ for (Entry entry : annotations.entrySet()) {
+ if (entry.getValue().getType().equals(type)) {
+ lengths.add(entry.getKey().length());
+ }
+ }
+ out.println(" switch (fs.name()->utf8_length()) {");
+ for (int len : lengths) {
+ out.println(" case " + len + ":");
+ for (Entry entry : annotations.entrySet()) {
+ if (entry.getValue().getType().equals(type) && entry.getKey().length() == len) {
+ out.println(" if (fs.name()->equals(\"" + entry.getKey() + "\")) {");
+ entry.getValue().emit(out);
+ out.println(" continue;");
+ out.println(" }");
+ }
+ }
+ out.println(" continue;");
+ }
+ out.println(" } // switch");
+ out.println(" continue;");
+ out.println(" } // if");
+ }
+ out.println(" } // for");
+ out.println("}");
+ }
+ }
+
+ protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
+ try {
+ // Ensure Unix line endings to comply with Graal code style guide checked by Checkstyle
+ FileObject sourceFile = filer.createResource(StandardLocation.SOURCE_OUTPUT, pkg, relativeName, originatingElements);
+ logMessage("%s\n", sourceFile);
+ return new PrintWriter(sourceFile.openWriter()) {
+
+ @Override
+ public void println() {
+ print("\n");
+ }
+ };
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ class VMConfigField {
+ final VariableElement field;
+ final Annotation annotation;
+
+ public VMConfigField(VariableElement field, Annotation value) {
+ super();
+ this.field = field;
+ this.annotation = value;
+ }
+
+ public String getType() {
+ return field.asType().toString();
+ }
+
+ private String archDefine(String arch) {
+ switch (arch) {
+ case "amd64":
+ return "defined(AMD64)";
+ case "sparcv9":
+ return "(defined(SPARC) && defined(_LP64))";
+ case "sparc":
+ return "defined(SPARC)";
+ default:
+ throw new GraalInternalError("unexpected arch: " + arch);
+ }
+ }
+
+ private String archDefines(String[] archs) {
+ if (archs.length == 0) {
+ return null;
+ }
+ if (archs.length == 1) {
+ return archDefine(archs[0]);
+ }
+ String[] defs = new String[archs.length];
+ int i = 0;
+ for (String arch : archs) {
+ defs[i++] = archDefine(arch);
+ }
+ return String.join(" ||", defs);
+ }
+
+ public void emit(PrintWriter out) {
+ if (annotation instanceof HotSpotVMField) {
+ emitField(out, (HotSpotVMField) annotation);
+ } else if (annotation instanceof HotSpotVMType) {
+ emitType(out, (HotSpotVMType) annotation);
+ } else if (annotation instanceof HotSpotVMFlag) {
+ emitFlag(out, (HotSpotVMFlag) annotation);
+ } else if (annotation instanceof HotSpotVMConstant) {
+ emitConstant(out, (HotSpotVMConstant) annotation);
+ } else if (annotation instanceof HotSpotVMValue) {
+ emitValue(out, (HotSpotVMValue) annotation);
+ } else {
+ throw new InternalError(annotation.toString());
+ }
+
+ }
+
+ private void emitField(PrintWriter out, HotSpotVMField value) {
+ String type = field.asType().toString();
+ String define = archDefines(value.archs());
+ if (define != null) {
+ out.printf("#if %s\n", define);
+ }
+
+ String name = value.name();
+ int i = name.lastIndexOf("::");
+ switch (value.get()) {
+ case OFFSET:
+ out.printf(" set_%s(\"%s\", offset_of(%s, %s));\n", type, field.getSimpleName(), name.substring(0, i), name.substring(i + 2));
+ break;
+ case ADDRESS:
+ out.printf(" set_address(\"%s\", &%s);\n", field.getSimpleName(), name);
+ break;
+ case VALUE:
+ out.printf(" set_%s(\"%s\", (%s) (intptr_t) %s);\n", type, field.getSimpleName(), type, name);
+ break;
+ }
+ if (define != null) {
+ out.printf("#endif\n");
+ }
+ }
+
+ private void emitType(PrintWriter out, HotSpotVMType value) {
+ String type = field.asType().toString();
+ out.printf(" set_%s(\"%s\", sizeof(%s));\n", type, field.getSimpleName(), value.name());
+ }
+
+ private void emitValue(PrintWriter out, HotSpotVMValue value) {
+ String type = field.asType().toString();
+ int length = value.defines().length;
+ if (length != 0) {
+ out.printf("#if ");
+ for (int i = 0; i < length; i++) {
+ out.printf("defined(%s)", value.defines()[i]);
+ if (i + 1 < length) {
+ out.printf(" || ");
+ }
+ }
+ out.println();
+ }
+ if (value.get() == HotSpotVMValue.Type.ADDRESS) {
+ out.printf(" set_address(\"%s\", %s);\n", field.getSimpleName(), value.expression());
+ } else {
+ out.printf(" set_%s(\"%s\", %s);\n", type, field.getSimpleName(), value.expression());
+ }
+ if (length != 0) {
+ out.println("#endif");
+ }
+ }
+
+ private void emitConstant(PrintWriter out, HotSpotVMConstant value) {
+ String define = archDefines(value.archs());
+ if (define != null) {
+ out.printf("#if %s\n", define);
+ }
+ String type = field.asType().toString();
+ out.printf(" set_%s(\"%s\", %s);\n", type, field.getSimpleName(), value.name());
+ if (define != null) {
+ out.printf("#endif\n");
+ }
+ }
+
+ private void emitFlag(PrintWriter out, HotSpotVMFlag value) {
+ String type = field.asType().toString();
+
+ String define = archDefines(value.archs());
+ if (define != null) {
+ out.printf("#if %s\n", define);
+ }
+ if (value.optional()) {
+ out.printf(" set_optional_%s_flag(\"%s\", \"%s\");\n", type, field.getSimpleName(), value.name());
+ } else {
+ out.printf(" set_%s(\"%s\", %s);\n", type, field.getSimpleName(), value.name());
+ }
+ if (define != null) {
+ out.printf("#endif\n");
+ }
+ }
+
+ }
+
+ private void collectAnnotations(RoundEnvironment roundEnv, Map annotationMap, Class extends Annotation> annotationClass) {
+ for (Element element : roundEnv.getElementsAnnotatedWith(annotationClass)) {
+ Annotation constant = element.getAnnotation(annotationClass);
+ if (element.getKind() != ElementKind.FIELD) {
+ errorMessage(element, "%s annotations may only be on fields", annotationClass.getSimpleName());
+ }
+ if (annotationClass == HotSpotVMValue.class) {
+ HotSpotVMValue value = (HotSpotVMValue) constant;
+ if (value.get() == HotSpotVMValue.Type.ADDRESS && !element.asType().toString().equals("long")) {
+ errorMessage(element, "HotSpotVMValue with get == ADDRESS must be of type long, but found %s", element.asType());
+ }
+ }
+ if (currentTypeElement == null) {
+ currentTypeElement = element.getEnclosingElement();
+ } else {
+ if (!currentTypeElement.equals(element.getEnclosingElement())) {
+ errorMessage(element, "Multiple types encountered. Only HotSpotVMConfig is supported");
+ }
+ }
+ annotationMap.put(element.getSimpleName().toString(), new VMConfigField((VariableElement) element, constant));
+ }
+ }
+
+ private void errorMessage(Element element, String format, Object... args) {
+ processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element);
+ }
+
+ Element currentTypeElement = null;
+
+ @Override
+ public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (roundEnv.processingOver()) {
+ return true;
+ }
+ logMessage("Starting round %s %s\n", roundEnv, annotations);
+ try {
+
+ currentTypeElement = null;
+
+ // First collect all the annotations.
+ Map annotationMap = new HashMap<>();
+ collectAnnotations(roundEnv, annotationMap, HotSpotVMConstant.class);
+ collectAnnotations(roundEnv, annotationMap, HotSpotVMFlag.class);
+ collectAnnotations(roundEnv, annotationMap, HotSpotVMField.class);
+ collectAnnotations(roundEnv, annotationMap, HotSpotVMType.class);
+ collectAnnotations(roundEnv, annotationMap, HotSpotVMValue.class);
+
+ if (annotationMap.isEmpty()) {
+ return true;
+ }
+
+ logMessage("type element %s\n", currentTypeElement);
+ createFiles(annotationMap, currentTypeElement);
+
+ } catch (Throwable t) {
+ reportExceptionThrow(null, t);
+ }
+
+ return true;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConstant.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConstant.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Refers to a C++ constant in the VM.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMConstant {
+
+ /**
+ * Returns the name of the constant.
+ *
+ * @return name of constant
+ */
+ String name();
+
+ /**
+ * List of architectures where this constant is required. Names are derived from
+ * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
+ * required on all architectures.
+ */
+ @SuppressWarnings("javadoc")
+ String[] archs() default {};
+
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMField.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMField.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Refers to a C++ field in the VM.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMField {
+
+ /**
+ * Types of information this annotation can return.
+ */
+ enum Type {
+ /**
+ * Returns the offset of this field within the type. Only valid for instance fields.
+ */
+ OFFSET,
+
+ /**
+ * Returns the absolute address of this field. Only valid for static fields.
+ */
+ ADDRESS,
+
+ /**
+ * Returns the value of this field. Only valid for static fields.
+ */
+ VALUE;
+ }
+
+ /**
+ * Specifies what type of information to return.
+ *
+ * @see Type
+ */
+ Type get();
+
+ /**
+ * Returns the type name containing this field.
+ *
+ * @return name of containing type
+ */
+ String type();
+
+ /**
+ * Returns the name of this field.
+ *
+ * @return name of field
+ */
+ String name();
+
+ /**
+ * List of architectures where this constant is required. Names are derived from
+ * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
+ * required on all architectures.
+ */
+ @SuppressWarnings("javadoc")
+ String[] archs() default {};
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMFlag.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMFlag.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Refers to a C++ flag in the VM.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMFlag {
+
+ /**
+ * Returns the name of this flag.
+ *
+ * @return name of flag.
+ */
+ String name();
+
+ /**
+ * List of architectures where this constant is required. Names are derived from
+ * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
+ * required on all architectures.
+ */
+ @SuppressWarnings("javadoc")
+ String[] archs() default {};
+
+ boolean optional() default false;
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMType.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMType.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.*;
+
+/**
+ * Refers to a C++ type in the VM.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMType {
+
+ /**
+ * Types of information this annotation can return.
+ */
+ enum Type {
+ /**
+ * Returns the size of the type (C++ {@code sizeof()}).
+ */
+ SIZE;
+ }
+
+ /**
+ * Specifies what type of information to return.
+ *
+ * @see Type
+ */
+ Type get();
+
+ /**
+ * Returns the name of the type.
+ *
+ * @return name of type
+ */
+ String name();
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMValue.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMValue.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMValue {
+
+ /**
+ * A C++ expression to be evaluated and assigned to the field.
+ */
+ String expression();
+
+ enum Type {
+ /**
+ * A C++ address which might require extra casts to be safely assigned to a Java field.
+ */
+ ADDRESS,
+
+ /**
+ * A simple value which can be assigned to a regular Java field.
+ */
+ VALUE
+ }
+
+ Type get() default Type.VALUE;
+
+ /**
+ * List of preprocessor symbols that should guard initialization of this value.
+ */
+ String[] defines() default {};
+
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java Wed May 21 11:45:50 2014 +0200
@@ -80,11 +80,11 @@
Double delta;
@Override
- protected void assertEquals(Object expected, Object actual) {
+ protected void assertDeepEquals(Object expected, Object actual) {
if (delta != null) {
Assert.assertEquals(((Number) expected).doubleValue(), ((Number) actual).doubleValue(), delta);
} else {
- super.assertEquals(expected, actual);
+ super.assertDeepEquals(expected, actual);
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java Wed May 21 11:45:50 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,36 +30,8 @@
*/
public final class Class_getInterfaces01 extends JTTTest {
- public static String test(int i) {
- switch (i) {
- case 0:
- return toString(I1.class);
- case 1:
- return toString(I2.class);
- case 2:
- return toString(C1.class);
- case 3:
- return toString(C2.class);
- case 4:
- return toString(C12.class);
- default:
- return null;
- }
- }
-
- private static String toString(Class> klass) {
- final Class>[] classes = klass.getInterfaces();
- final StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (Class> c : classes) {
- if (!first) {
- sb.append(' ');
- } else {
- first = false;
- }
- sb.append(c.getName());
- }
- return sb.toString();
+ public static Class>[] test(Class> clazz) {
+ return clazz.getInterfaces();
}
interface I1 {
@@ -84,27 +56,26 @@
@Test
public void run0() throws Throwable {
- runTest("test", 0);
+ runTest("test", I1.class);
}
@Test
public void run1() throws Throwable {
- runTest("test", 1);
+ runTest("test", I2.class);
}
@Test
public void run2() throws Throwable {
- runTest("test", 2);
+ runTest("test", C1.class);
}
@Test
public void run3() throws Throwable {
- runTest("test", 3);
+ runTest("test", C2.class);
}
@Test
public void run4() throws Throwable {
- runTest("test", 4);
+ runTest("test", C12.class);
}
-
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Wed May 21 11:45:50 2014 +0200
@@ -39,8 +39,8 @@
// @formatter:off
- IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, IROL, IROR,
- LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, LROL, LROR,
+ IADD, ISUB, IMUL, IUMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, IROL, IROR,
+ LADD, LSUB, LMUL, LUMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, LROL, LROR,
FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
INEG, LNEG, INOT, LNOT,
@@ -342,6 +342,64 @@
}
}
+ public static class MulHighOp extends AMD64LIRInstruction {
+
+ @Opcode private final AMD64Arithmetic opcode;
+ @Def({REG}) public AllocatableValue lowResult;
+ @Def({REG}) public AllocatableValue highResult;
+ @Use({REG}) public AllocatableValue x;
+ @Use({REG, STACK}) public AllocatableValue y;
+
+ public MulHighOp(AMD64Arithmetic opcode, AllocatableValue y) {
+ PlatformKind kind = y.getPlatformKind();
+
+ this.opcode = opcode;
+ this.x = AMD64.rax.asValue(kind);
+ this.y = y;
+ this.lowResult = AMD64.rax.asValue(kind);
+ this.highResult = AMD64.rdx.asValue(kind);
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+ if (isRegister(y)) {
+ switch (opcode) {
+ case IMUL:
+ masm.imull(asRegister(y));
+ break;
+ case IUMUL:
+ masm.mull(asRegister(y));
+ break;
+ case LMUL:
+ masm.imulq(asRegister(y));
+ break;
+ case LUMUL:
+ masm.mulq(asRegister(y));
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ } else {
+ switch (opcode) {
+ case IMUL:
+ masm.imull((AMD64Address) crb.asAddress(y));
+ break;
+ case IUMUL:
+ masm.mull((AMD64Address) crb.asAddress(y));
+ break;
+ case LMUL:
+ masm.imulq((AMD64Address) crb.asAddress(y));
+ break;
+ case LUMUL:
+ masm.mulq((AMD64Address) crb.asAddress(y));
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ }
+ }
+ }
+
public static class DivRemOp extends AMD64LIRInstruction {
@Opcode private final AMD64Arithmetic opcode;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Wed May 21 11:45:50 2014 +0200
@@ -142,6 +142,7 @@
protected void verify() {
super.verify();
assert y instanceof Variable || y instanceof Constant;
+ assert kind != Kind.Long || !(y instanceof Constant) || NumUtil.isInt(((Constant) y).asLong());
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Wed May 21 11:45:50 2014 +0200
@@ -84,11 +84,6 @@
/**
* Generates the code for this switch op.
*
- * The keys for switch statements in Java bytecode for of type int. However, Graal also
- * generates a TypeSwitchNode (for method dispatch) which triggers the invocation of these
- * routines with keys of type Long or Object. Currently we only support the
- * IntegerSwitchNode so we throw an exception if the key isn't of type int.
- *
* @param crb the CompilationResultBuilder
* @param masm the HSAIL assembler
*/
@@ -100,13 +95,13 @@
switch (key.getKind()) {
case Int:
case Long:
+ case Object:
// Generate cascading compare and branches for each case.
masm.emitCompare(key.getKind(), key, keyConstants[index], HSAILCompare.conditionToString(condition), false, false);
masm.cbr(masm.nameOf(target));
break;
- case Object:
default:
- throw new GraalInternalError("switch only supported for int");
+ throw new GraalInternalError("switch not supported for kind " + key.getKind());
}
}
};
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/ArithmeticLIRGenerator.java
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/ArithmeticLIRGenerator.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/ArithmeticLIRGenerator.java Wed May 21 11:45:50 2014 +0200
@@ -42,6 +42,10 @@
Value emitMul(Value a, Value b);
+ Value emitMulHigh(Value a, Value b);
+
+ Value emitUMulHigh(Value a, Value b);
+
Value emitDiv(Value a, Value b, LIRFrameState state);
Value emitRem(Value a, Value b, LIRFrameState state);
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampJoinTest.java
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampJoinTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampJoinTest.java Wed May 21 11:45:50 2014 +0200
@@ -26,34 +26,16 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.test.*;
import com.oracle.graal.nodes.type.*;
-public class ObjectStampJoinTest extends GraalCompilerTest {
-
- private static class A {
-
- }
-
- private static class B extends A {
-
- }
-
- private static class C extends B implements I {
+public class ObjectStampJoinTest extends ObjectStampTest {
- }
-
- private static class D extends A {
-
- }
-
- private abstract static class E extends A {
-
- }
-
- private interface I {
-
- }
+ // class A
+ // class B extends A
+ // class C extends B implements I
+ // class D extends A
+ // abstract class E extends A
+ // interface I
@Test
public void testJoin0() {
@@ -142,8 +124,8 @@
@Test
public void testJoinInterface0() {
Stamp a = StampFactory.declared(getType(A.class));
- Stamp b = StampFactory.declared(getType(I.class));
- Assert.assertNotSame(StampFactory.illegal(Kind.Object), join(a, b));
+ Stamp i = StampFactory.declared(getType(I.class));
+ Assert.assertNotSame(StampFactory.illegal(Kind.Object), join(a, i));
}
@Test
@@ -163,14 +145,4 @@
Assert.assertEquals(StampFactory.illegal(Kind.Object), join);
}
- private static Stamp join(Stamp a, Stamp b) {
- Stamp ab = a.join(b);
- Stamp ba = b.join(a);
- Assert.assertEquals(ab, ba);
- return ab;
- }
-
- private ResolvedJavaType getType(Class> clazz) {
- return getMetaAccess().lookupJavaType(clazz);
- }
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampMeetTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampMeetTest.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+
+public class ObjectStampMeetTest extends ObjectStampTest {
+
+ // class A
+ // class B extends A
+ // class C extends B implements I
+ // class D extends A
+ // abstract class E extends A
+ // interface I
+
+ @Test
+ public void testMeet0() {
+ Stamp a = StampFactory.declared(getType(A.class));
+ Stamp b = StampFactory.declared(getType(B.class));
+ Assert.assertEquals(a, meet(a, b));
+ }
+
+ @Test
+ public void testMeet1() {
+ Stamp a = StampFactory.declared(getType(A.class));
+ Stamp aNonNull = StampFactory.declaredNonNull(getType(A.class));
+ Stamp b = StampFactory.declared(getType(B.class));
+ Stamp bNonNull = StampFactory.declaredNonNull(getType(B.class));
+ Assert.assertEquals(a, meet(aNonNull, b));
+ Assert.assertEquals(aNonNull, meet(aNonNull, bNonNull));
+ }
+
+ @Test
+ public void testMeet2() {
+ Stamp a = StampFactory.declared(getType(A.class));
+ Stamp aExact = StampFactory.exactNonNull(getType(A.class));
+ Stamp b = StampFactory.declared(getType(B.class));
+ Assert.assertEquals(a, meet(aExact, b));
+ }
+
+ @Test
+ public void testMeet3() {
+ Stamp a = StampFactory.declared(getType(A.class));
+ Stamp d = StampFactory.declared(getType(D.class));
+ Stamp c = StampFactory.declared(getType(C.class));
+ Assert.assertEquals(a, meet(c, d));
+ }
+
+ @Test
+ public void testMeet4() {
+ Stamp dExactNonNull = StampFactory.exactNonNull(getType(D.class));
+ Stamp cExactNonNull = StampFactory.exactNonNull(getType(C.class));
+ Stamp aNonNull = StampFactory.declaredNonNull(getType(A.class));
+ Assert.assertEquals(aNonNull, meet(cExactNonNull, dExactNonNull));
+ }
+
+ @Test
+ public void testMeet() {
+ Stamp dExact = StampFactory.exact(getType(D.class));
+ Stamp c = StampFactory.declared(getType(C.class));
+ Stamp a = StampFactory.declared(getType(A.class));
+ Assert.assertEquals(a, meet(dExact, c));
+ }
+
+ @Test
+ public void testMeet6() {
+ Stamp dExactNonNull = StampFactory.exactNonNull(getType(D.class));
+ Stamp alwaysNull = StampFactory.alwaysNull();
+ Stamp dExact = StampFactory.exact(getType(D.class));
+ Assert.assertEquals(dExact, meet(dExactNonNull, alwaysNull));
+ }
+
+ @Test
+ public void testMeet7() {
+ Stamp aExact = StampFactory.exact(getType(A.class));
+ Stamp e = StampFactory.declared(getType(E.class));
+ Stamp a = StampFactory.declared(getType(A.class));
+ Assert.assertEquals(a, meet(aExact, e));
+ }
+
+ @Test
+ public void testMeetInterface0() {
+ Stamp a = StampFactory.declared(getType(A.class));
+ Stamp i = StampFactory.declared(getType(I.class));
+ Assert.assertEquals(StampFactory.declared(getType(Object.class)), meet(a, i));
+ }
+
+ @Test
+ public void testMeetIllegal1() {
+ for (Class> clazz : new Class>[]{A.class, B.class, C.class, D.class, E.class, I.class, Object.class}) {
+ ResolvedJavaType type = getType(clazz);
+ for (Stamp test : new Stamp[]{StampFactory.declared(type), StampFactory.declaredNonNull(type), StampFactory.exact(type), StampFactory.exactNonNull(type)}) {
+ if (!type.isAbstract() || !((ObjectStamp) test).isExactType()) {
+ Assert.assertEquals("meeting illegal and " + test, test, meet(StampFactory.illegal(Kind.Object), test));
+ }
+ }
+ }
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampTest.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.test.*;
+
+public class ObjectStampTest extends GraalCompilerTest {
+
+ protected static class A {
+
+ }
+
+ protected static class B extends A {
+
+ }
+
+ protected static class C extends B implements I {
+
+ }
+
+ protected static class D extends A {
+
+ }
+
+ protected abstract static class E extends A {
+
+ }
+
+ protected interface I {
+
+ }
+
+ protected static Stamp join(Stamp a, Stamp b) {
+ Stamp ab = a.join(b);
+ Stamp ba = b.join(a);
+ Assert.assertEquals(ab, ba);
+ return ab;
+ }
+
+ protected static Stamp meet(Stamp a, Stamp b) {
+ Stamp ab = a.meet(b);
+ Stamp ba = b.meet(a);
+ Assert.assertEquals(ab, ba);
+ return ab;
+ }
+
+ protected ResolvedJavaType getType(Class> clazz) {
+ return getMetaAccess().lookupJavaType(clazz);
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Wed May 21 11:45:50 2014 +0200
@@ -38,10 +38,12 @@
public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
@Input private ValueNode object;
+ private final Stamp piStamp;
public GuardedValueNode(ValueNode object, GuardingNode guard, Stamp stamp) {
super(stamp, guard);
this.object = object;
+ this.piStamp = stamp;
}
public GuardedValueNode(ValueNode object, GuardingNode guard) {
@@ -61,10 +63,10 @@
@Override
public boolean inferStamp() {
- if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
- return updateStamp(((ObjectStamp) object().stamp()).castTo((ObjectStamp) stamp()));
+ if (piStamp instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
+ return updateStamp(((ObjectStamp) object().stamp()).castTo((ObjectStamp) piStamp));
}
- return updateStamp(object().stamp().join(stamp()));
+ return updateStamp(object().stamp().join(piStamp));
}
@Override
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Wed May 21 11:45:50 2014 +0200
@@ -41,6 +41,7 @@
@Input(InputType.Condition) private LogicNode condition;
private final DeoptimizationReason reason;
private final DeoptimizationAction action;
+ private final Stamp piStamp;
private boolean negated;
public ValueNode object() {
@@ -81,6 +82,7 @@
public GuardingPiNode(ValueNode object, ValueNode condition, boolean negateCondition, DeoptimizationReason reason, DeoptimizationAction action, Stamp stamp) {
super(stamp);
assert stamp != null;
+ this.piStamp = stamp;
this.object = object;
this.condition = (LogicNode) condition;
this.reason = reason;
@@ -107,7 +109,7 @@
@Override
public boolean inferStamp() {
- return updateStamp(stamp().join(object().stamp()));
+ return updateStamp(piStamp.join(object().stamp()));
}
@Override
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Wed May 21 11:45:50 2014 +0200
@@ -188,6 +188,10 @@
} while (false);
}
+ if (checkForUnsignedCompare(tool)) {
+ return;
+ }
+
if (condition() instanceof LogicConstantNode) {
LogicConstantNode c = (LogicConstantNode) condition();
if (c.getValue()) {
@@ -220,7 +224,7 @@
// Reordering of those two if statements is beneficial from the point of view of
// their probabilities.
if (prepareForSwap(tool.getConstantReflection(), condition(), nextIf.condition(), this.trueSuccessorProbability, probabilityB)) {
- // Reording is allowed from (if1 => begin => if2) to (if2 => begin => if1).
+ // Reordering is allowed from (if1 => begin => if2) to (if2 => begin => if1).
assert intermediateBegin.next() == nextIf;
BeginNode bothFalseBegin = nextIf.falseSuccessor();
nextIf.setFalseSuccessor(null);
@@ -244,6 +248,106 @@
}
}
+ /**
+ * Recognize a couple patterns that can be merged into an unsigned compare.
+ *
+ * @param tool
+ * @return true if a replacement was done.
+ */
+ private boolean checkForUnsignedCompare(SimplifierTool tool) {
+ if (condition() instanceof IntegerLessThanNode && trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
+ IntegerLessThanNode lessThan = (IntegerLessThanNode) condition();
+ Constant y = lessThan.y().stamp().asConstant();
+ if (y != null && y.asLong() == 0 && falseSuccessor().next() instanceof IfNode) {
+ IfNode ifNode2 = (IfNode) falseSuccessor().next();
+ if (ifNode2.condition() instanceof IntegerLessThanNode) {
+ IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition();
+ BeginNode falseSucc = ifNode2.falseSuccessor();
+ BeginNode trueSucc = ifNode2.trueSuccessor();
+ IntegerBelowThanNode below = null;
+ /*
+ * Convert x >= 0 && x < positive which is represented as !(x < 0) && x <
+ * into an unsigned compare.
+ */
+ if (lessThan2.x() == lessThan.x() && lessThan2.y().stamp() instanceof IntegerStamp && ((IntegerStamp) lessThan2.y().stamp()).isPositive() &&
+ sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
+ below = graph().unique(new IntegerBelowThanNode(lessThan2.x(), lessThan2.y()));
+ // swap direction
+ BeginNode tmp = falseSucc;
+ falseSucc = trueSucc;
+ trueSucc = tmp;
+ } else if (lessThan2.y() == lessThan.x() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) {
+ /*
+ * Convert x >= 0 && x <= positive which is represented as !(x < 0) &&
+ * !( > x), into x <| positive + 1. This can only be done for
+ * constants since there isn't a IntegerBelowEqualThanNode but that doesn't
+ * appear to be interesting.
+ */
+ Constant positive = lessThan2.x().asConstant();
+ if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getKind().getMaxValue()) {
+ ConstantNode newLimit = ConstantNode.forIntegerKind(positive.getKind(), positive.asLong() + 1, graph());
+ below = graph().unique(new IntegerBelowThanNode(lessThan.x(), newLimit));
+ }
+ }
+ if (below != null) {
+ ifNode2.setTrueSuccessor(null);
+ ifNode2.setFalseSuccessor(null);
+
+ IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability));
+ // Remove the < 0 test.
+ tool.deleteBranch(trueSuccessor);
+ graph().removeSplit(this, falseSuccessor);
+
+ // Replace the second test with the new one.
+ ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
+ ifNode2.safeDelete();
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check it these two blocks end up at the same place. Meeting at the same merge, or
+ * deoptimizing in the same way.
+ */
+ private static boolean sameDestination(BeginNode succ1, BeginNode succ2) {
+ Node next1 = succ1.next();
+ Node next2 = succ2.next();
+ if (next1 instanceof EndNode && next2 instanceof EndNode) {
+ EndNode end1 = (EndNode) next1;
+ EndNode end2 = (EndNode) next2;
+ if (end1.merge() == end2.merge()) {
+ // They go to the same MergeNode
+ return true;
+ }
+ } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) {
+ DeoptimizeNode deopt1 = (DeoptimizeNode) next1;
+ DeoptimizeNode deopt2 = (DeoptimizeNode) next2;
+ if (deopt1.reason() == deopt2.reason() && deopt1.action() == deopt2.action()) {
+ // Same deoptimization reason and action.
+ return true;
+ }
+ } else if (next1 instanceof LoopExitNode && next2 instanceof LoopExitNode) {
+ LoopExitNode exit1 = (LoopExitNode) next1;
+ LoopExitNode exit2 = (LoopExitNode) next2;
+ if (exit1.loopBegin() == exit2.loopBegin() && exit1.stateAfter() == exit2.stateAfter() && exit1.stateAfter() == null && sameDestination(exit1, exit2)) {
+ // Exit the same loop and end up at the same place.
+ return true;
+ }
+ } else if (next1 instanceof ReturnNode && next2 instanceof ReturnNode) {
+ ReturnNode exit1 = (ReturnNode) next1;
+ ReturnNode exit2 = (ReturnNode) next2;
+ if (exit1.result() == exit2.result()) {
+ // Exit the same loop and end up at the same place.
+ return true;
+ }
+ }
+ return false;
+ }
+
private static boolean prepareForSwap(ConstantReflectionProvider constantReflection, LogicNode a, LogicNode b, double probabilityA, double probabilityB) {
if (a instanceof InstanceOfNode) {
InstanceOfNode instanceOfA = (InstanceOfNode) a;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Wed May 21 11:45:50 2014 +0200
@@ -25,7 +25,9 @@
import com.oracle.graal.api.meta.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, GuardedNode {
@@ -85,4 +87,16 @@
newStateDuring.setDuringCall(true);
setStateDuring(newStateDuring);
}
+
+ default ValueNode getReceiver() {
+ return callTarget().arguments().get(0);
+ }
+
+ default ResolvedJavaType getReceiverType() {
+ ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver());
+ if (receiverType == null) {
+ receiverType = ((MethodCallTargetNode) callTarget()).targetMethod().getDeclaringClass();
+ }
+ return receiverType;
+ }
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Wed May 21 11:45:50 2014 +0200
@@ -43,6 +43,7 @@
public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
@Input private ValueNode object;
+ private final Stamp piStamp;
public ValueNode object() {
return object;
@@ -50,12 +51,14 @@
public PiNode(ValueNode object, Stamp stamp) {
super(stamp);
+ this.piStamp = stamp;
this.object = object;
}
public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) {
super(stamp, (GuardingNode) anchor);
this.object = object;
+ this.piStamp = stamp;
}
public PiNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
@@ -71,13 +74,13 @@
@Override
public boolean inferStamp() {
- if (stamp() == StampFactory.forNodeIntrinsic()) {
+ if (piStamp == StampFactory.forNodeIntrinsic()) {
return false;
}
- if (stamp() instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) {
- return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) stamp()));
+ if (piStamp instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) {
+ return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) piStamp));
}
- return updateStamp(stamp().join(object().stamp()));
+ return updateStamp(piStamp.join(object().stamp()));
}
@Override
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Wed May 21 11:45:50 2014 +0200
@@ -54,10 +54,6 @@
@Override
public boolean inferStamp() {
- return inferPhiStamp();
- }
-
- public boolean inferPhiStamp() {
return updateStamp(StampTool.meet(values()));
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Wed May 21 11:45:50 2014 +0200
@@ -82,7 +82,7 @@
IntegerStamp equalsXStamp = (IntegerStamp) equals.x().stamp();
if (equalsXStamp.upMask() == 1) {
if (x().asConstant().equals(Constant.INT_0) && y().asConstant().equals(Constant.INT_1)) {
- return equals.x();
+ return IntegerConvertNode.convertUnsigned(equals.x(), stamp());
}
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Wed May 21 11:45:50 2014 +0200
@@ -75,6 +75,14 @@
}
public static ValueNode convert(ValueNode input, Stamp stamp) {
+ return convert(input, stamp, false);
+ }
+
+ public static ValueNode convertUnsigned(ValueNode input, Stamp stamp) {
+ return convert(input, stamp, true);
+ }
+
+ public static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend) {
StructuredGraph graph = input.graph();
IntegerStamp fromStamp = (IntegerStamp) input.stamp();
IntegerStamp toStamp = (IntegerStamp) stamp;
@@ -84,6 +92,9 @@
result = input;
} else if (toStamp.getBits() < fromStamp.getBits()) {
result = graph.unique(new NarrowNode(input, toStamp.getBits()));
+ } else if (zeroExtend) {
+ // toStamp.getBits() > fromStamp.getBits()
+ result = graph.unique(new ZeroExtendNode(input, toStamp.getBits()));
} else {
// toStamp.getBits() > fromStamp.getBits()
result = graph.unique(new SignExtendNode(input, toStamp.getBits()));
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Wed May 21 11:45:50 2014 +0200
@@ -28,6 +28,7 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
@NodeInfo(shortName = "%")
public class IntegerRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
@@ -37,6 +38,11 @@
}
@Override
+ public boolean inferStamp() {
+ return updateStamp(StampTool.rem(x().stamp(), y().stamp()));
+ }
+
+ @Override
public Node canonical(CanonicalizerTool tool) {
if (x().isConstant() && y().isConstant()) {
long y = y().asConstant().asLong();
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java Wed May 21 11:45:50 2014 +0200
@@ -34,18 +34,20 @@
@Input private ValueNode hub;
private final ResolvedJavaMethod method;
+ private final ResolvedJavaType receiverType;
public ValueNode getHub() {
return hub;
}
- public LoadMethodNode(ResolvedJavaMethod method, ValueNode hub, Kind kind) {
+ public LoadMethodNode(ResolvedJavaMethod method, ResolvedJavaType receiverType, ValueNode hub, Kind kind) {
super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind));
+ this.receiverType = receiverType;
this.hub = hub;
this.method = method;
assert !method.isAbstract() : "Cannot load abstract method from a hub";
assert !method.isStatic() : "Cannot load a static method from a hub";
- assert method.isInVirtualMethodTable();
+ assert method.isInVirtualMethodTable(receiverType);
}
@Override
@@ -56,4 +58,8 @@
public ResolvedJavaMethod getMethod() {
return method;
}
+
+ public ResolvedJavaType getReceiverType() {
+ return receiverType;
+ }
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Wed May 21 11:45:50 2014 +0200
@@ -23,10 +23,12 @@
package com.oracle.graal.nodes.extended;
import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.spi.*;
-public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable {
+@NodeInfo(allowedUsageTypes = {InputType.Guard})
+public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, GuardingNode {
@Input private ValueNode object;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Wed May 21 11:45:50 2014 +0200
@@ -132,8 +132,9 @@
@Override
public boolean inferStamp() {
- if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
- return updateStamp(((ObjectStamp) object().stamp()).castTo((ObjectStamp) stamp()));
+ if (object().stamp() instanceof ObjectStamp) {
+ ObjectStamp castStamp = (ObjectStamp) StampFactory.declared(type);
+ return updateStamp(((ObjectStamp) object().stamp()).castTo(castStamp));
}
return false;
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Wed May 21 11:45:50 2014 +0200
@@ -144,12 +144,32 @@
ResolvedJavaType type = StampTool.typeOrNull(receiver);
if (type != null) {
// either the holder class is exact, or the receiver object has an exact type
- ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod);
+ ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod, invoke().getContextType());
if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiver))) {
invokeKind = InvokeKind.Special;
targetMethod = resolvedMethod;
return this;
}
+ if (tool.assumptions() != null && tool.assumptions().useOptimisticAssumptions()) {
+ ResolvedJavaType uniqueConcreteType = type.findUniqueConcreteSubtype();
+ if (uniqueConcreteType != null) {
+ ResolvedJavaMethod methodFromUniqueType = uniqueConcreteType.resolveMethod(targetMethod, invoke().getContextType());
+ if (methodFromUniqueType != null) {
+ tool.assumptions().recordConcreteSubtype(type, uniqueConcreteType);
+ invokeKind = InvokeKind.Special;
+ targetMethod = methodFromUniqueType;
+ return this;
+ }
+ }
+
+ ResolvedJavaMethod uniqueConcreteMethod = type.findUniqueConcreteMethod(targetMethod);
+ if (uniqueConcreteMethod != null) {
+ tool.assumptions().recordConcreteMethod(targetMethod, type, uniqueConcreteMethod);
+ invokeKind = InvokeKind.Special;
+ targetMethod = uniqueConcreteMethod;
+ return this;
+ }
+ }
}
}
return this;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Wed May 21 11:45:50 2014 +0200
@@ -105,6 +105,37 @@
return stamp1.unrestricted();
}
+ public static Stamp rem(Stamp stamp1, Stamp stamp2) {
+ if (stamp1 instanceof IntegerStamp && stamp2 instanceof IntegerStamp) {
+ return rem((IntegerStamp) stamp1, (IntegerStamp) stamp2);
+ }
+ return StampFactory.illegal();
+ }
+
+ public static Stamp rem(IntegerStamp stamp1, IntegerStamp stamp2) {
+ assert stamp1.getBits() == stamp2.getBits();
+ long magnitude; // the maximum absolute value of the result
+ if (stamp2.lowerBound() == IntegerStamp.defaultMinValue(stamp2.getBits())) {
+ // Math.abs(...) - 1 does not work in this case
+ magnitude = IntegerStamp.defaultMaxValue(stamp2.getBits());
+ } else {
+ magnitude = Math.max(Math.abs(stamp2.lowerBound()), Math.abs(stamp2.upperBound())) - 1;
+ }
+ long lowerBound = Math.max(stamp1.lowerBound(), -magnitude);
+ if (stamp1.upperBound() > magnitude) {
+ // if the result can wrap around at the upper bound, it can reach any value between 0
+ // and magnitude
+ lowerBound = Math.min(lowerBound, 0);
+ }
+ long upperBound = Math.min(stamp1.upperBound(), magnitude);
+ if (stamp1.lowerBound() < -magnitude) {
+ // if the result can wrap around at the lower bound, it can reach any value between
+ // -magnitude and 0
+ upperBound = Math.max(upperBound, 0);
+ }
+ return StampFactory.forInteger(stamp1.getBits(), lowerBound, upperBound);
+ }
+
private static boolean addOverflowsPositively(long x, long y, int bits) {
long result = x + y;
if (bits == 64) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Wed May 21 11:45:50 2014 +0200
@@ -815,7 +815,7 @@
if (receiver != null && (callTarget.invokeKind() == InvokeKind.Interface || callTarget.invokeKind() == InvokeKind.Virtual)) {
ResolvedJavaType type = state.getNodeType(receiver);
if (!Objects.equals(type, StampTool.typeOrNull(receiver))) {
- ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod());
+ ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod(), invoke.getContextType());
if (method != null) {
if (method.canBeStaticallyBound() || type.isFinal()) {
callTarget.setInvokeKind(InvokeKind.Special);
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java Wed May 21 11:45:50 2014 +0200
@@ -62,7 +62,7 @@
merge.addForwardEnd(firstEnd);
reasonActionPhi.addInput(((AbstractDeoptimizeNode) target).getActionAndReason(context.getMetaAccess()));
speculationPhi.addInput(((AbstractDeoptimizeNode) target).getSpeculation(context.getMetaAccess()));
- target.predecessor().replaceFirstSuccessor(target, firstEnd);
+ target.replaceAtPredecessor(firstEnd);
exitLoops((AbstractDeoptimizeNode) target, firstEnd, cfg);
@@ -77,7 +77,7 @@
merge.addForwardEnd(newEnd);
reasonActionPhi.addInput(deopt.getActionAndReason(context.getMetaAccess()));
speculationPhi.addInput(deopt.getSpeculation(context.getMetaAccess()));
- deopt.predecessor().replaceFirstSuccessor(deopt, newEnd);
+ deopt.replaceAtPredecessor(newEnd);
exitLoops(deopt, newEnd, cfg);
obsoletes.add(deopt);
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java Wed May 21 11:45:50 2014 +0200
@@ -22,7 +22,10 @@
*/
package com.oracle.graal.phases.common;
+import java.util.*;
+
import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
@@ -34,6 +37,10 @@
public class UseTrappingNullChecksPhase extends BasePhase {
+ private static final DebugMetric metricTrappingNullCheck = Debug.metric("TrappingNullCheck");
+ private static final DebugMetric metricTrappingNullCheckUnreached = Debug.metric("TrappingNullCheckUnreached");
+ private static final DebugMetric metricTrappingNullCheckDynamicDeoptimize = Debug.metric("TrappingNullCheckDynamicDeoptimize");
+
@Override
protected void run(StructuredGraph graph, LowTierContext context) {
if (context.getTarget().implicitNullCheckLimit <= 0) {
@@ -42,36 +49,111 @@
assert graph.getGuardsStage().ordinal() >= GuardsStage.AFTER_FSA.ordinal();
for (DeoptimizeNode deopt : graph.getNodes(DeoptimizeNode.class)) {
- tryUseTrappingNullCheck(deopt);
+ tryUseTrappingNullCheck(deopt, deopt.predecessor(), deopt.reason(), deopt.getSpeculation());
+ }
+ for (DynamicDeoptimizeNode deopt : graph.getNodes(DynamicDeoptimizeNode.class)) {
+ tryUseTrappingNullCheck(context.getMetaAccess(), deopt);
}
}
- private static void tryUseTrappingNullCheck(DeoptimizeNode deopt) {
- if (deopt.reason() != DeoptimizationReason.NullCheckException) {
- return;
+ private static void tryUseTrappingNullCheck(MetaAccessProvider metaAccessProvider, DynamicDeoptimizeNode deopt) {
+ Node predecessor = deopt.predecessor();
+ if (predecessor instanceof MergeNode) {
+ MergeNode merge = (MergeNode) predecessor;
+
+ // Process each predecessor at the merge, unpacking the reasons and speculations as
+ // needed.
+ ValueNode reason = deopt.getActionAndReason();
+ ValuePhiNode reasonPhi = null;
+ List reasons = null;
+ int expectedPhis = 0;
+
+ if (reason instanceof ValuePhiNode) {
+ reasonPhi = (ValuePhiNode) reason;
+ if (reasonPhi.merge() != merge) {
+ return;
+ }
+ reasons = reasonPhi.values().snapshot();
+ expectedPhis++;
+ } else if (!reason.isConstant()) {
+ return;
+ }
+
+ ValueNode speculation = deopt.getSpeculation();
+ ValuePhiNode speculationPhi = null;
+ List speculations = null;
+ if (speculation instanceof ValuePhiNode) {
+ speculationPhi = (ValuePhiNode) speculation;
+ if (speculationPhi.merge() != merge) {
+ return;
+ }
+ speculations = speculationPhi.values().snapshot();
+ expectedPhis++;
+ }
+
+ if (merge.phis().count() != expectedPhis) {
+ return;
+ }
+
+ int index = 0;
+ for (AbstractEndNode end : merge.cfgPredecessors().snapshot()) {
+ ValueNode thisReason = reasons != null ? reasons.get(index) : reason;
+ ValueNode thisSpeculation = speculations != null ? speculations.get(index++) : speculation;
+ if (!thisReason.isConstant() || !thisSpeculation.isConstant() || !thisSpeculation.asConstant().equals(Constant.NULL_OBJECT)) {
+ continue;
+ }
+ DeoptimizationReason deoptimizationReason = metaAccessProvider.decodeDeoptReason(thisReason.asConstant());
+ tryUseTrappingNullCheck(deopt, end.predecessor(), deoptimizationReason, null);
+ }
}
- if (deopt.getSpeculation() != null && !deopt.getSpeculation().equals(Constant.NULL_OBJECT)) {
+ }
+
+ private static void tryUseTrappingNullCheck(AbstractDeoptimizeNode deopt, Node predecessor, DeoptimizationReason deoptimizationReason, Constant speculation) {
+ if (deoptimizationReason != DeoptimizationReason.NullCheckException && deoptimizationReason != DeoptimizationReason.UnreachedCode) {
return;
}
- Node predecessor = deopt.predecessor();
+ if (speculation != null && !speculation.equals(Constant.NULL_OBJECT)) {
+ return;
+ }
+ if (predecessor instanceof MergeNode) {
+ MergeNode merge = (MergeNode) predecessor;
+ if (merge.phis().isEmpty()) {
+ for (AbstractEndNode end : merge.cfgPredecessors().snapshot()) {
+ checkPredecessor(deopt, end.predecessor(), deoptimizationReason);
+ }
+ }
+ } else if (predecessor instanceof BeginNode) {
+ checkPredecessor(deopt, predecessor, deoptimizationReason);
+ }
+ }
+
+ private static void checkPredecessor(AbstractDeoptimizeNode deopt, Node predecessor, DeoptimizationReason deoptimizationReason) {
+ Node current = predecessor;
Node branch = null;
- while (predecessor instanceof BeginNode) {
- branch = predecessor;
- predecessor = predecessor.predecessor();
+ while (current instanceof BeginNode) {
+ branch = current;
+ current = current.predecessor();
}
- if (predecessor instanceof IfNode) {
- IfNode ifNode = (IfNode) predecessor;
+ if (current instanceof IfNode) {
+ IfNode ifNode = (IfNode) current;
if (branch != ifNode.trueSuccessor()) {
return;
}
LogicNode condition = ifNode.condition();
if (condition instanceof IsNullNode) {
- replaceWithTrappingNullCheck(deopt, ifNode, condition);
+ replaceWithTrappingNullCheck(deopt, ifNode, condition, deoptimizationReason);
}
}
}
- private static void replaceWithTrappingNullCheck(DeoptimizeNode deopt, IfNode ifNode, LogicNode condition) {
+ private static void replaceWithTrappingNullCheck(AbstractDeoptimizeNode deopt, IfNode ifNode, LogicNode condition, DeoptimizationReason deoptimizationReason) {
+ metricTrappingNullCheck.increment();
+ if (deopt instanceof DynamicDeoptimizeNode) {
+ metricTrappingNullCheckDynamicDeoptimize.increment();
+ }
+ if (deoptimizationReason == DeoptimizationReason.UnreachedCode) {
+ metricTrappingNullCheckUnreached.increment();
+ }
IsNullNode isNullNode = (IsNullNode) condition;
BeginNode nonTrappingContinuation = ifNode.falseSuccessor();
BeginNode trappingContinuation = ifNode.trueSuccessor();
@@ -79,6 +161,17 @@
trappingNullCheck.setStateBefore(deopt.stateBefore());
deopt.graph().replaceSplit(ifNode, trappingNullCheck, nonTrappingContinuation);
+ /*
+ * We now have the pattern NullCheck/BeginNode/... It's possible some node is using the
+ * BeginNode as a guard input, so replace guard users of the Begin with the NullCheck and
+ * then remove the Begin from the graph.
+ */
+ nonTrappingContinuation.replaceAtUsages(InputType.Guard, trappingNullCheck);
+ FixedNode next = nonTrappingContinuation.next();
+ nonTrappingContinuation.clearSuccessors();
+ trappingNullCheck.setNext(next);
+ nonTrappingContinuation.safeDelete();
+
GraphUtil.killCFG(trappingContinuation);
if (isNullNode.usages().isEmpty()) {
GraphUtil.killWithUnusedFloatingInputs(isNullNode);
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Wed May 21 11:45:50 2014 +0200
@@ -594,7 +594,7 @@
if (type == null) {
return;
}
- ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod());
+ ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod(), invoke.getContextType());
if (method == null) {
return;
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java Wed May 21 11:45:50 2014 +0200
@@ -191,8 +191,8 @@
* {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction} determined to be
* unreachable will be eliminated by canonicalization and dead code elimination. For now they
* still exist, thus polluting the result of
- * {@link com.oracle.graal.nodes.ValuePhiNode#inferPhiStamp()} but we are careful to skip them
- * when merging type-witnesses and known-null maps.
+ * {@link com.oracle.graal.nodes.ValuePhiNode#inferStamp()} but we are careful to skip them when
+ * merging type-witnesses and known-null maps.
*
*/
private void mergePhis(MergeNode merge, List withStates, Map newKnownPhiTypes) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/ComputeInliningRelevance.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/ComputeInliningRelevance.java Tue May 13 19:19:27 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,324 +0,0 @@
-/*
- * 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.phases.common.inlining;
-
-import static com.oracle.graal.graph.util.CollectionsAccess.*;
-
-import java.util.*;
-import java.util.function.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-
-import edu.umd.cs.findbugs.annotations.*;
-
-public class ComputeInliningRelevance {
-
- private static final double EPSILON = 1d / Integer.MAX_VALUE;
- private static final double UNINITIALIZED = -1D;
-
- private static final int EXPECTED_MIN_INVOKE_COUNT = 3;
- private static final int EXPECTED_INVOKE_RATIO = 20;
- private static final int EXPECTED_LOOP_COUNT = 3;
-
- private final StructuredGraph graph;
- private final ToDoubleFunction nodeProbabilities;
-
- /**
- * Node relevances are pre-computed for all invokes if the graph contains loops. If there are no
- * loops, the computation happens lazily based on {@link #rootScope}.
- */
- private Map nodeRelevances;
- /**
- * This scope is non-null if (and only if) there are no loops in the graph. In this case, the
- * root scope is used to compute invoke relevances on the fly.
- */
- private Scope rootScope;
-
- public ComputeInliningRelevance(StructuredGraph graph, ToDoubleFunction nodeProbabilities) {
- this.graph = graph;
- this.nodeProbabilities = nodeProbabilities;
- }
-
- /**
- * Initializes or updates the relevance computation. If there are no loops within the graph,
- * most computation happens lazily.
- */
- public void compute() {
- rootScope = null;
- if (!graph.hasLoops()) {
- // fast path for the frequent case of no loops
- rootScope = new Scope(graph.start(), null);
- } else {
- if (nodeRelevances == null) {
- nodeRelevances = newNodeIdentityMap(EXPECTED_MIN_INVOKE_COUNT + graph.getNodeCount() / EXPECTED_INVOKE_RATIO);
- }
- NodeWorkList workList = graph.createNodeWorkList();
- Map loops = newNodeIdentityMap(EXPECTED_LOOP_COUNT);
-
- loops.put(null, new Scope(graph.start(), null));
- for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.class)) {
- createLoopScope(loopBegin, loops);
- }
-
- for (Scope scope : loops.values()) {
- scope.process(workList);
- }
- }
- }
-
- public double getRelevance(Invoke invoke) {
- if (rootScope != null) {
- return rootScope.computeInvokeRelevance(invoke);
- }
- assert nodeRelevances != null : "uninitialized relevance";
- return nodeRelevances.get(invoke);
- }
-
- /**
- * Determines the parent of the given loop and creates a {@link Scope} object for each one. This
- * method will call itself recursively if no {@link Scope} for the parent loop exists.
- */
- private Scope createLoopScope(LoopBeginNode loopBegin, Map loops) {
- Scope scope = loops.get(loopBegin);
- if (scope == null) {
- final Scope parent;
- // look for the parent scope
- FixedNode current = loopBegin.forwardEnd();
- while (true) {
- if (current.predecessor() == null) {
- if (current instanceof LoopBeginNode) {
- // if we reach a LoopBeginNode then we're within this loop
- parent = createLoopScope((LoopBeginNode) current, loops);
- break;
- } else if (current instanceof StartNode) {
- // we're within the outermost scope
- parent = loops.get(null);
- break;
- } else {
- assert current.getClass() == MergeNode.class : current;
- // follow any path upwards - it doesn't matter which one
- current = ((MergeNode) current).forwardEndAt(0);
- }
- } else if (current instanceof LoopExitNode) {
- // if we reach a loop exit then we follow this loop and have the same parent
- parent = createLoopScope(((LoopExitNode) current).loopBegin(), loops).parent;
- break;
- } else {
- current = (FixedNode) current.predecessor();
- }
- }
- scope = new Scope(loopBegin, parent);
- loops.put(loopBegin, scope);
- }
- return scope;
- }
-
- /**
- * A scope holds information for the contents of one loop or of the root of the method. It does
- * not include child loops, i.e., the iteration in {@link #process(NodeWorkList)} explicitly
- * excludes the nodes of child loops.
- */
- private class Scope {
- public final FixedNode start;
- public final Scope parent; // can be null for the outermost scope
-
- /**
- * The minimum probability along the most probable path in this scope. Computed lazily.
- */
- private double fastPathMinProbability = UNINITIALIZED;
- /**
- * A measure of how important this scope is within its parent scope. Computed lazily.
- */
- private double scopeRelevanceWithinParent = UNINITIALIZED;
-
- public Scope(FixedNode start, Scope parent) {
- this.start = start;
- this.parent = parent;
- }
-
- @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
- public double getFastPathMinProbability() {
- if (fastPathMinProbability == UNINITIALIZED) {
- fastPathMinProbability = Math.max(EPSILON, computeFastPathMinProbability(start));
- }
- return fastPathMinProbability;
- }
-
- /**
- * Computes the ratio between the probabilities of the current scope's entry point and the
- * parent scope's fastPathMinProbability.
- */
- @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
- public double getScopeRelevanceWithinParent() {
- if (scopeRelevanceWithinParent == UNINITIALIZED) {
- if (start instanceof LoopBeginNode) {
- assert parent != null;
- double scopeEntryProbability = nodeProbabilities.applyAsDouble(((LoopBeginNode) start).forwardEnd());
-
- scopeRelevanceWithinParent = scopeEntryProbability / parent.getFastPathMinProbability();
- } else {
- scopeRelevanceWithinParent = 1D;
- }
- }
- return scopeRelevanceWithinParent;
- }
-
- /**
- * Processes all invokes in this scope by starting at the scope's start node and iterating
- * all fixed nodes. Child loops are skipped by going from loop entries directly to the loop
- * exits. Processing stops at loop exits of the current loop.
- */
- public void process(NodeWorkList workList) {
- assert !(start instanceof Invoke);
- workList.addAll(start.successors());
-
- for (Node current : workList) {
- assert current.isAlive();
-
- if (current instanceof Invoke) {
- // process the invoke and queue its successors
- nodeRelevances.put((FixedNode) current, computeInvokeRelevance((Invoke) current));
- workList.addAll(current.successors());
- } else if (current instanceof LoopBeginNode) {
- // skip child loops by advancing over the loop exits
- ((LoopBeginNode) current).loopExits().forEach(exit -> workList.add(exit.next()));
- } else if (current instanceof LoopEndNode) {
- // nothing to do
- } else if (current instanceof LoopExitNode) {
- // nothing to do
- } else if (current instanceof FixedWithNextNode) {
- workList.add(((FixedWithNextNode) current).next());
- } else if (current instanceof EndNode) {
- workList.add(((EndNode) current).merge());
- } else if (current instanceof ControlSinkNode) {
- // nothing to do
- } else if (current instanceof ControlSplitNode) {
- workList.addAll(current.successors());
- } else {
- assert false : current;
- }
- }
- }
-
- /**
- * The relevance of an invoke is the ratio between the invoke's probability and the current
- * scope's fastPathMinProbability, adjusted by scopeRelevanceWithinParent.
- */
- public double computeInvokeRelevance(Invoke invoke) {
- double invokeProbability = nodeProbabilities.applyAsDouble(invoke.asNode());
- assert !Double.isNaN(invokeProbability);
-
- double relevance = (invokeProbability / getFastPathMinProbability()) * Math.min(1.0, getScopeRelevanceWithinParent());
- assert !Double.isNaN(relevance) : invoke + ": " + relevance + " / " + invokeProbability + " / " + getFastPathMinProbability() + " / " + getScopeRelevanceWithinParent();
- return relevance;
- }
- }
-
- /**
- * Computes the minimum probability along the most probable path within the scope. During
- * iteration, the method returns immediately once a loop exit is discovered.
- */
- private double computeFastPathMinProbability(FixedNode scopeStart) {
- ArrayList pathBeginNodes = new ArrayList<>();
- pathBeginNodes.add(scopeStart);
- double minPathProbability = nodeProbabilities.applyAsDouble(scopeStart);
- boolean isLoopScope = scopeStart instanceof LoopBeginNode;
-
- do {
- Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1);
- do {
- if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) {
- return minPathProbability;
- } else if (current instanceof LoopBeginNode && current != scopeStart) {
- current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes);
- minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
- } else if (current instanceof ControlSplitNode) {
- current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes);
- minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
- } else {
- assert current.successors().count() <= 1;
- current = current.successors().first();
- }
- } while (current != null);
- } while (!pathBeginNodes.isEmpty());
-
- return minPathProbability;
- }
-
- private double getMinPathProbability(FixedNode current, double minPathProbability) {
- return current == null ? minPathProbability : Math.min(minPathProbability, nodeProbabilities.applyAsDouble(current));
- }
-
- /**
- * Returns the most probable successor. If multiple successors share the maximum probability,
- * one is returned and the others are enqueued in pathBeginNodes.
- */
- private static Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList pathBeginNodes) {
- Node maxSux = null;
- double maxProbability = 0.0;
- int pathBeginCount = pathBeginNodes.size();
-
- for (Node sux : controlSplit.successors()) {
- double probability = controlSplit.probability((BeginNode) sux);
- if (probability > maxProbability) {
- maxProbability = probability;
- maxSux = sux;
- truncate(pathBeginNodes, pathBeginCount);
- } else if (probability == maxProbability) {
- pathBeginNodes.add((FixedNode) sux);
- }
- }
-
- return maxSux;
- }
-
- /**
- * Returns the most probable loop exit. If multiple successors share the maximum probability,
- * one is returned and the others are enqueued in pathBeginNodes.
- */
- private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList pathBeginNodes) {
- Node maxSux = null;
- double maxProbability = 0.0;
- int pathBeginCount = pathBeginNodes.size();
-
- for (LoopExitNode sux : loopBegin.loopExits()) {
- double probability = nodeProbabilities.applyAsDouble(sux);
- if (probability > maxProbability) {
- maxProbability = probability;
- maxSux = sux;
- truncate(pathBeginNodes, pathBeginCount);
- } else if (probability == maxProbability) {
- pathBeginNodes.add(sux);
- }
- }
-
- return maxSux;
- }
-
- private static void truncate(ArrayList pathBeginNodes, int pathBeginCount) {
- for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) {
- pathBeginNodes.remove(pathBeginNodes.size() - 1);
- }
- }
-}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningIterator.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningIterator.java Tue May 13 19:19:27 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2011, 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.phases.common.inlining;
-
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.graph.NodeBitMap;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode;
-
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.LinkedList;
-
-/**
- * Given a graph, visit all fixed nodes in dominator-based order, collecting in the process the
- * {@link Invoke} nodes with {@link MethodCallTargetNode}. Such list of callsites is returned by
- * {@link #apply()}
- */
-class InliningIterator {
-
- private final StartNode start;
- private final Deque nodeQueue;
- private final NodeBitMap queuedNodes;
-
- public InliningIterator(StructuredGraph graph) {
- this.start = graph.start();
- this.nodeQueue = new ArrayDeque<>();
- this.queuedNodes = graph.createNodeBitMap();
- assert start.isAlive();
- }
-
- public LinkedList apply() {
- LinkedList invokes = new LinkedList<>();
- FixedNode current;
- forcedQueue(start);
-
- while ((current = nextQueuedNode()) != null) {
- assert current.isAlive();
-
- if (current instanceof Invoke && ((Invoke) current).callTarget() instanceof MethodCallTargetNode) {
- if (current != start) {
- invokes.addLast((Invoke) current);
- }
- queueSuccessors(current);
- } else if (current instanceof LoopBeginNode) {
- queueSuccessors(current);
- } else if (current instanceof LoopEndNode) {
- // nothing to do
- } else if (current instanceof MergeNode) {
- queueSuccessors(current);
- } else if (current instanceof FixedWithNextNode) {
- queueSuccessors(current);
- } else if (current instanceof EndNode) {
- queueMerge((EndNode) current);
- } else if (current instanceof ControlSinkNode) {
- // nothing to do
- } else if (current instanceof ControlSplitNode) {
- queueSuccessors(current);
- } else {
- assert false : current;
- }
- }
-
- return invokes;
- }
-
- private void queueSuccessors(FixedNode x) {
- for (Node node : x.successors()) {
- queue(node);
- }
- }
-
- private void queue(Node node) {
- if (node != null && !queuedNodes.isMarked(node)) {
- forcedQueue(node);
- }
- }
-
- private void forcedQueue(Node node) {
- queuedNodes.mark(node);
- nodeQueue.addFirst((FixedNode) node);
- }
-
- private FixedNode nextQueuedNode() {
- if (nodeQueue.isEmpty()) {
- return null;
- }
-
- FixedNode result = nodeQueue.removeFirst();
- assert queuedNodes.isMarked(result);
- return result;
- }
-
- private void queueMerge(AbstractEndNode end) {
- MergeNode merge = end.merge();
- if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
- queuedNodes.mark(merge);
- nodeQueue.add(merge);
- }
- }
-
- private boolean visitedAllEnds(MergeNode merge) {
- for (int i = 0; i < merge.forwardEndCount(); i++) {
- if (!queuedNodes.isMarked(merge.forwardEndAt(i))) {
- return false;
- }
- }
- return true;
- }
-}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java Wed May 21 11:45:50 2014 +0200
@@ -22,37 +22,21 @@
*/
package com.oracle.graal.phases.common.inlining;
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.phases.common.inlining.InliningPhase.Options.*;
-
import java.util.*;
-import java.util.function.*;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.Graph.Mark;
-import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.options.*;
import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.common.inlining.InliningUtil.InlineInfo;
-import com.oracle.graal.phases.common.inlining.InliningUtil.Inlineable;
-import com.oracle.graal.phases.common.inlining.InliningUtil.InlineableGraph;
-import com.oracle.graal.phases.common.inlining.InliningUtil.InlineableMacroNode;
-import com.oracle.graal.phases.common.inlining.InliningUtil.InliningPolicy;
-import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.common.inlining.policy.GreedyInliningPolicy;
+import com.oracle.graal.phases.common.inlining.policy.InliningPolicy;
+import com.oracle.graal.phases.common.inlining.walker.CallsiteHolder;
+import com.oracle.graal.phases.common.inlining.walker.InliningData;
+import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
public class InliningPhase extends AbstractInliningPhase {
- static class Options {
+ public static class Options {
// @formatter:off
@Option(help = "Unconditionally inline intrinsics")
@@ -66,12 +50,6 @@
private int inliningCount;
private int maxMethodPerInlining = Integer.MAX_VALUE;
- // Metrics
- private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
- private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
- private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
- private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
-
public InliningPhase(CanonicalizerPhase canonicalizer) {
this(new GreedyInliningPolicy(null), canonicalizer);
}
@@ -93,38 +71,79 @@
return inliningCount;
}
+ /**
+ *
+ * The space of inlining decisions is explored depth-first with the help of a stack realized by
+ * {@link com.oracle.graal.phases.common.inlining.walker.InliningData}. At any point in time,
+ * its topmost element consist of:
+ *
+ * -
+ * one or more {@link CallsiteHolder}s of inlining candidates, all of them corresponding to a
+ * single callsite (details below). For example, "exact inline" leads to a single candidate.
+ * -
+ * the callsite (for the targets above) is tracked as a {@link MethodInvocation}. The difference
+ * between {@link com.oracle.graal.phases.common.inlining.walker.MethodInvocation#totalGraphs()}
+ * and {@link MethodInvocation#processedGraphs()} indicates the topmost {@link CallsiteHolder}s
+ * that might be delved-into to explore inlining opportunities.
+ *
+ *
+ *
+ *
+ * The bottom-most element in the stack consists of:
+ *
+ * -
+ * a single {@link CallsiteHolder} (the root one, for the method on which inlining was called)
+ * -
+ * a single {@link MethodInvocation} (the
+ * {@link com.oracle.graal.phases.common.inlining.walker.MethodInvocation#isRoot} one, ie the
+ * unknown caller of the root graph)
+ *
+ *
+ *
+ *
+ *
+ * The stack grows and shrinks as choices are made among the alternatives below:
+ *
+ * -
+ * not worth inlining: pop any remaining graphs not yet delved into, pop the current invocation.
+ *
+ * -
+ * process next invoke: delve into one of the callsites hosted in the current candidate graph,
+ * determine whether any inlining should be performed in it
+ * -
+ * try to inline: move past the current inlining candidate (remove it from the topmost element).
+ * If that was the last one then try to inline the callsite that is (still) in the topmost
+ * element of {@link com.oracle.graal.phases.common.inlining.walker.InliningData}, and then
+ * remove such callsite.
+ *
+ *
+ *
+ *
+ * Some facts about the alternatives above:
+ *
+ * -
+ * the first step amounts to backtracking, the 2nd one to delving, and the 3rd one also involves
+ * backtracking (however after may-be inlining).
+ * -
+ * the choice of abandon-and-backtrack or delve-into is depends on
+ * {@link InliningPolicy#isWorthInlining} and {@link InliningPolicy#continueInlining}.
+ * -
+ * the 3rd choice is picked when both of the previous ones aren't picked
+ * -
+ * as part of trying-to-inline, {@link InliningPolicy#isWorthInlining} again sees use, but
+ * that's another story.
+ *
+ *
+ *
+ */
@Override
protected void run(final StructuredGraph graph, final HighTierContext context) {
- final InliningData data = new InliningData(graph, context.getAssumptions());
- ToDoubleFunction probabilities = new FixedNodeProbabilityCache();
+ final InliningData data = new InliningData(graph, context, maxMethodPerInlining, canonicalizer, inliningPolicy);
while (data.hasUnprocessedGraphs()) {
- final MethodInvocation currentInvocation = data.currentInvocation();
- GraphInfo graphInfo = data.currentGraph();
- if (!currentInvocation.isRoot() &&
- !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation.callee(), data.inliningDepth(), currentInvocation.probability(),
- currentInvocation.relevance(), false)) {
- int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
- assert remainingGraphs > 0;
- data.popGraphs(remainingGraphs);
- data.popInvocation();
- } else if (graphInfo.hasRemainingInvokes() && inliningPolicy.continueInlining(graphInfo.graph())) {
- processNextInvoke(data, graphInfo, context);
- } else {
- data.popGraph();
- if (!currentInvocation.isRoot()) {
- assert currentInvocation.callee().invoke().asNode().isAlive();
- currentInvocation.incrementProcessedGraphs();
- if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
- data.popInvocation();
- final MethodInvocation parentInvoke = data.currentInvocation();
- try (Scope s = Debug.scope("Inlining", data.inliningContext())) {
- tryToInline(probabilities, data.currentGraph(), currentInvocation, parentInvoke, data.inliningDepth() + 1, context);
- } catch (Throwable e) {
- throw Debug.handle(e);
- }
- }
- }
+ boolean wasInlined = data.moveForward();
+ if (wasInlined) {
+ inliningCount++;
}
}
@@ -132,645 +151,4 @@
assert data.graphCount() == 0;
}
- /**
- * Process the next invoke and enqueue all its graphs for processing.
- */
- private void processNextInvoke(InliningData data, GraphInfo graphInfo, HighTierContext context) {
- Invoke invoke = graphInfo.popInvoke();
- MethodInvocation callerInvocation = data.currentInvocation();
- Assumptions parentAssumptions = callerInvocation.assumptions();
- InlineInfo info = InliningUtil.getInlineInfo(data, invoke, maxMethodPerInlining, context.getReplacements(), parentAssumptions, context.getOptimisticOptimizations());
-
- if (info != null) {
- double invokeProbability = graphInfo.invokeProbability(invoke);
- double invokeRelevance = graphInfo.invokeRelevance(invoke);
- MethodInvocation calleeInvocation = data.pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance);
-
- for (int i = 0; i < info.numberOfMethods(); i++) {
- Inlineable elem = getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeInvocation.assumptions()));
- info.setInlinableElement(i, elem);
- if (elem instanceof InlineableGraph) {
- data.pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
- } else {
- assert elem instanceof InlineableMacroNode;
- data.pushDummyGraph();
- }
- }
- }
- }
-
- private void tryToInline(ToDoubleFunction probabilities, GraphInfo callerGraphInfo, MethodInvocation calleeInfo, MethodInvocation parentInvocation, int inliningDepth,
- HighTierContext context) {
- InlineInfo callee = calleeInfo.callee();
- Assumptions callerAssumptions = parentInvocation.assumptions();
-
- if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), callee, inliningDepth, calleeInfo.probability(), calleeInfo.relevance(), true)) {
- doInline(callerGraphInfo, calleeInfo, callerAssumptions, context);
- } else if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
- callee.tryToDevirtualizeInvoke(context.getMetaAccess(), callerAssumptions);
- }
- metricInliningConsidered.increment();
- }
-
- private void doInline(GraphInfo callerGraphInfo, MethodInvocation calleeInfo, Assumptions callerAssumptions, HighTierContext context) {
- StructuredGraph callerGraph = callerGraphInfo.graph();
- Mark markBeforeInlining = callerGraph.getMark();
- InlineInfo callee = calleeInfo.callee();
- try {
- try (Scope scope = Debug.scope("doInline", callerGraph)) {
- List invokeUsages = callee.invoke().asNode().usages().snapshot();
- callee.inline(new Providers(context), callerAssumptions);
- callerAssumptions.record(calleeInfo.assumptions());
- metricInliningRuns.increment();
- Debug.dump(callerGraph, "after %s", callee);
-
- if (OptCanonicalizer.getValue()) {
- Mark markBeforeCanonicalization = callerGraph.getMark();
- canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
-
- // process invokes that are possibly created during canonicalization
- for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
- if (newNode instanceof Invoke) {
- callerGraphInfo.pushInvoke((Invoke) newNode);
- }
- }
- }
-
- callerGraphInfo.computeProbabilities();
-
- inliningCount++;
- metricInliningPerformed.increment();
- }
- } catch (BailoutException bailout) {
- throw bailout;
- } catch (AssertionError | RuntimeException e) {
- throw new GraalInternalError(e).addContext(callee.toString());
- } catch (GraalInternalError e) {
- throw e.addContext(callee.toString());
- }
- }
-
- private Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context) {
- Class extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
- if (macroNodeClass != null) {
- return new InlineableMacroNode(macroNodeClass);
- } else {
- return new InlineableGraph(buildGraph(method, invoke, context));
- }
- }
-
- private StructuredGraph buildGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context) {
- final StructuredGraph newGraph;
- final boolean parseBytecodes;
-
- // TODO (chaeubl): copying the graph is only necessary if it is modified or if it contains
- // any invokes
- StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(context.getReplacements(), method);
- if (intrinsicGraph != null) {
- newGraph = intrinsicGraph.copy();
- parseBytecodes = false;
- } else {
- StructuredGraph cachedGraph = getCachedGraph(method, context);
- if (cachedGraph != null) {
- newGraph = cachedGraph.copy();
- parseBytecodes = false;
- } else {
- newGraph = new StructuredGraph(method);
- parseBytecodes = true;
- }
- }
-
- try (Scope s = Debug.scope("InlineGraph", newGraph)) {
- if (parseBytecodes) {
- parseBytecodes(newGraph, context);
- }
-
- boolean callerHasMoreInformationAboutArguments = false;
- NodeInputList args = invoke.callTarget().arguments();
- for (ParameterNode param : newGraph.getNodes(ParameterNode.class).snapshot()) {
- ValueNode arg = args.get(param.index());
- if (arg.isConstant()) {
- Constant constant = arg.asConstant();
- newGraph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph));
- callerHasMoreInformationAboutArguments = true;
- } else {
- Stamp joinedStamp = param.stamp().join(arg.stamp());
- if (joinedStamp != null && !joinedStamp.equals(param.stamp())) {
- param.setStamp(joinedStamp);
- callerHasMoreInformationAboutArguments = true;
- }
- }
- }
-
- if (!callerHasMoreInformationAboutArguments) {
- // TODO (chaeubl): if args are not more concrete, inlining should be avoided
- // in most cases or we could at least use the previous graph size + invoke
- // probability to check the inlining
- }
-
- if (OptCanonicalizer.getValue()) {
- canonicalizer.apply(newGraph, context);
- }
-
- return newGraph;
- } catch (Throwable e) {
- throw Debug.handle(e);
- }
- }
-
- private static StructuredGraph getCachedGraph(ResolvedJavaMethod method, HighTierContext context) {
- if (context.getGraphCache() != null) {
- StructuredGraph cachedGraph = context.getGraphCache().get(method);
- if (cachedGraph != null) {
- return cachedGraph;
- }
- }
- return null;
- }
-
- private StructuredGraph parseBytecodes(StructuredGraph newGraph, HighTierContext context) {
- boolean hasMatureProfilingInfo = newGraph.method().getProfilingInfo().isMature();
-
- if (context.getGraphBuilderSuite() != null) {
- context.getGraphBuilderSuite().apply(newGraph, context);
- }
- assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
-
- new DeadCodeEliminationPhase().apply(newGraph);
-
- if (OptCanonicalizer.getValue()) {
- canonicalizer.apply(newGraph, context);
- }
-
- if (hasMatureProfilingInfo && context.getGraphCache() != null) {
- context.getGraphCache().put(newGraph.method(), newGraph.copy());
- }
- return newGraph;
- }
-
- private abstract static class AbstractInliningPolicy implements InliningPolicy {
-
- protected final Map hints;
-
- public AbstractInliningPolicy(Map hints) {
- this.hints = hints;
- }
-
- protected double computeMaximumSize(double relevance, int configuredMaximum) {
- double inlineRatio = Math.min(RelevanceCapForInlining.getValue(), relevance);
- return configuredMaximum * inlineRatio;
- }
-
- protected double getInliningBonus(InlineInfo info) {
- if (hints != null && hints.containsKey(info.invoke())) {
- return hints.get(info.invoke());
- }
- return 1;
- }
-
- protected boolean isIntrinsic(Replacements replacements, InlineInfo info) {
- if (AlwaysInlineIntrinsics.getValue()) {
- return onlyIntrinsics(replacements, info);
- } else {
- return onlyForcedIntrinsics(replacements, info);
- }
- }
-
- private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) {
- for (int i = 0; i < info.numberOfMethods(); i++) {
- if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
- return false;
- }
- }
- return true;
- }
-
- private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) {
- for (int i = 0; i < info.numberOfMethods(); i++) {
- if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
- return false;
- }
- if (!replacements.isForcedSubstitution(info.methodAt(i))) {
- return false;
- }
- }
- return true;
- }
-
- protected static int previousLowLevelGraphSize(InlineInfo info) {
- int size = 0;
- for (int i = 0; i < info.numberOfMethods(); i++) {
- ResolvedJavaMethod m = info.methodAt(i);
- ProfilingInfo profile = m.getProfilingInfo();
- int compiledGraphSize = profile.getCompilerIRSize(StructuredGraph.class);
- if (compiledGraphSize > 0) {
- size += compiledGraphSize;
- }
- }
- return size;
- }
-
- protected static int determineNodeCount(InlineInfo info) {
- int nodes = 0;
- for (int i = 0; i < info.numberOfMethods(); i++) {
- Inlineable elem = info.inlineableElementAt(i);
- if (elem != null) {
- nodes += elem.getNodeCount();
- }
- }
- return nodes;
- }
-
- protected static double determineInvokeProbability(ToDoubleFunction probabilities, InlineInfo info) {
- double invokeProbability = 0;
- for (int i = 0; i < info.numberOfMethods(); i++) {
- Inlineable callee = info.inlineableElementAt(i);
- Iterable invokes = callee.getInvokes();
- if (invokes.iterator().hasNext()) {
- for (Invoke invoke : invokes) {
- invokeProbability += probabilities.applyAsDouble(invoke.asNode());
- }
- }
- }
- return invokeProbability;
- }
- }
-
- public static class GreedyInliningPolicy extends AbstractInliningPolicy {
-
- public GreedyInliningPolicy(Map hints) {
- super(hints);
- }
-
- public boolean continueInlining(StructuredGraph currentGraph) {
- if (currentGraph.getNodeCount() >= MaximumDesiredSize.getValue()) {
- InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize");
- metricInliningStoppedByMaxDesiredSize.increment();
- return false;
- }
- return true;
- }
-
- @Override
- public boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
- boolean fullyProcessed) {
- if (InlineEverything.getValue()) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
- }
-
- if (isIntrinsic(replacements, info)) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
- }
-
- if (info.shouldInline()) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
- }
-
- double inliningBonus = getInliningBonus(info);
- int nodes = determineNodeCount(info);
- int lowLevelGraphSize = previousLowLevelGraphSize(info);
-
- if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) {
- return InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)",
- lowLevelGraphSize, relevance, probability, inliningBonus, nodes);
- }
-
- if (nodes < TrivialInliningSize.getValue() * inliningBonus) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
- }
-
- /*
- * TODO (chaeubl): invoked methods that are on important paths but not yet compiled ->
- * will be compiled anyways and it is likely that we are the only caller... might be
- * useful to inline those methods but increases bootstrap time (maybe those methods are
- * also getting queued in the compilation queue concurrently)
- */
- double invokes = determineInvokeProbability(probabilities, info);
- if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) {
- return InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes,
- relevance, probability, inliningBonus, nodes);
- }
-
- double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue() * inliningBonus));
- if (nodes <= maximumNodes) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability,
- inliningBonus, nodes, maximumNodes);
- }
-
- return InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes,
- maximumNodes);
- }
- }
-
- public static final class InlineEverythingPolicy implements InliningPolicy {
-
- public boolean continueInlining(StructuredGraph graph) {
- if (graph.getNodeCount() >= MaximumDesiredSize.getValue()) {
- throw new BailoutException("Inline all calls failed. The resulting graph is too large.");
- }
- return true;
- }
-
- public boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
- boolean fullyProcessed) {
- return true;
- }
- }
-
- /**
- * Holds the data for building the callee graphs recursively: graphs and invocations (each
- * invocation can have multiple graphs).
- */
- static class InliningData {
-
- private static final GraphInfo DummyGraphInfo = new GraphInfo(null, 1.0, 1.0);
-
- /**
- * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
- */
- private final ArrayDeque graphQueue;
- private final ArrayDeque invocationQueue;
-
- private int maxGraphs;
-
- public InliningData(StructuredGraph rootGraph, Assumptions rootAssumptions) {
- this.graphQueue = new ArrayDeque<>();
- this.invocationQueue = new ArrayDeque<>();
- this.maxGraphs = 1;
-
- invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
- pushGraph(rootGraph, 1.0, 1.0);
- }
-
- public int graphCount() {
- return graphQueue.size();
- }
-
- public void pushGraph(StructuredGraph graph, double probability, double relevance) {
- assert !contains(graph);
- graphQueue.push(new GraphInfo(graph, probability, relevance));
- assert graphQueue.size() <= maxGraphs;
- }
-
- public void pushDummyGraph() {
- graphQueue.push(DummyGraphInfo);
- }
-
- public boolean hasUnprocessedGraphs() {
- return !graphQueue.isEmpty();
- }
-
- public GraphInfo currentGraph() {
- return graphQueue.peek();
- }
-
- public void popGraph() {
- graphQueue.pop();
- assert graphQueue.size() <= maxGraphs;
- }
-
- public void popGraphs(int count) {
- assert count >= 0;
- for (int i = 0; i < count; i++) {
- graphQueue.pop();
- }
- }
-
- private static final Object[] NO_CONTEXT = {};
-
- /**
- * Gets the call hierarchy of this inlining from outer most call to inner most callee.
- */
- public Object[] inliningContext() {
- if (!Debug.isDumpEnabled()) {
- return NO_CONTEXT;
- }
- Object[] result = new Object[graphQueue.size()];
- int i = 0;
- for (GraphInfo g : graphQueue) {
- result[i++] = g.graph.method();
- }
- return result;
- }
-
- public MethodInvocation currentInvocation() {
- return invocationQueue.peekFirst();
- }
-
- public MethodInvocation pushInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
- MethodInvocation methodInvocation = new MethodInvocation(info, new Assumptions(assumptions.useOptimisticAssumptions()), probability, relevance);
- invocationQueue.addFirst(methodInvocation);
- maxGraphs += info.numberOfMethods();
- assert graphQueue.size() <= maxGraphs;
- return methodInvocation;
- }
-
- public void popInvocation() {
- maxGraphs -= invocationQueue.peekFirst().callee.numberOfMethods();
- assert graphQueue.size() <= maxGraphs;
- invocationQueue.removeFirst();
- }
-
- public int countRecursiveInlining(ResolvedJavaMethod method) {
- int count = 0;
- for (GraphInfo graphInfo : graphQueue) {
- if (method.equals(graphInfo.method())) {
- count++;
- }
- }
- return count;
- }
-
- public int inliningDepth() {
- assert invocationQueue.size() > 0;
- return invocationQueue.size() - 1;
- }
-
- @Override
- public String toString() {
- StringBuilder result = new StringBuilder("Invocations: ");
-
- for (MethodInvocation invocation : invocationQueue) {
- if (invocation.callee() != null) {
- result.append(invocation.callee().numberOfMethods());
- result.append("x ");
- result.append(invocation.callee().invoke());
- result.append("; ");
- }
- }
-
- result.append("\nGraphs: ");
- for (GraphInfo graph : graphQueue) {
- result.append(graph.graph());
- result.append("; ");
- }
-
- return result.toString();
- }
-
- private boolean contains(StructuredGraph graph) {
- for (GraphInfo info : graphQueue) {
- if (info.graph() == graph) {
- return true;
- }
- }
- return false;
- }
- }
-
- private static class MethodInvocation {
-
- private final InlineInfo callee;
- private final Assumptions assumptions;
- private final double probability;
- private final double relevance;
-
- private int processedGraphs;
-
- public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
- this.callee = info;
- this.assumptions = assumptions;
- this.probability = probability;
- this.relevance = relevance;
- }
-
- public void incrementProcessedGraphs() {
- processedGraphs++;
- assert processedGraphs <= callee.numberOfMethods();
- }
-
- public int processedGraphs() {
- assert processedGraphs <= callee.numberOfMethods();
- return processedGraphs;
- }
-
- public int totalGraphs() {
- return callee.numberOfMethods();
- }
-
- public InlineInfo callee() {
- return callee;
- }
-
- public Assumptions assumptions() {
- return assumptions;
- }
-
- public double probability() {
- return probability;
- }
-
- public double relevance() {
- return relevance;
- }
-
- public boolean isRoot() {
- return callee == null;
- }
-
- @Override
- public String toString() {
- if (isRoot()) {
- return "";
- }
- CallTargetNode callTarget = callee.invoke().callTarget();
- if (callTarget instanceof MethodCallTargetNode) {
- ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
- return MetaUtil.format("Invoke#%H.%n(%p)", calleeMethod);
- } else {
- return "Invoke#" + callTarget.targetName();
- }
- }
- }
-
- /**
- * Information about a graph that will potentially be inlined. This includes tracking the
- * invocations in graph that will subject to inlining themselves.
- */
- private static class GraphInfo {
-
- private final StructuredGraph graph;
- private final LinkedList remainingInvokes;
- private final double probability;
- private final double relevance;
-
- private final ToDoubleFunction probabilities;
- private final ComputeInliningRelevance computeInliningRelevance;
-
- public GraphInfo(StructuredGraph graph, double probability, double relevance) {
- this.graph = graph;
- if (graph == null) {
- this.remainingInvokes = new LinkedList<>();
- } else {
- LinkedList invokes = new InliningIterator(graph).apply();
- assert invokes.size() == count(graph.getInvokes());
- this.remainingInvokes = invokes;
- }
- this.probability = probability;
- this.relevance = relevance;
-
- if (graph != null && !remainingInvokes.isEmpty()) {
- probabilities = new FixedNodeProbabilityCache();
- computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
- computeProbabilities();
- } else {
- probabilities = null;
- computeInliningRelevance = null;
- }
- }
-
- private static int count(Iterable invokes) {
- int count = 0;
- Iterator iterator = invokes.iterator();
- while (iterator.hasNext()) {
- iterator.next();
- count++;
- }
- return count;
- }
-
- /**
- * Gets the method associated with the {@linkplain #graph() graph} represented by this
- * object.
- */
- public ResolvedJavaMethod method() {
- return graph.method();
- }
-
- public boolean hasRemainingInvokes() {
- return !remainingInvokes.isEmpty();
- }
-
- /**
- * The graph about which this object contains inlining information.
- */
- public StructuredGraph graph() {
- return graph;
- }
-
- public Invoke popInvoke() {
- return remainingInvokes.removeFirst();
- }
-
- public void pushInvoke(Invoke invoke) {
- remainingInvokes.push(invoke);
- }
-
- public void computeProbabilities() {
- computeInliningRelevance.compute();
- }
-
- public double invokeProbability(Invoke invoke) {
- return probability * probabilities.applyAsDouble(invoke.asNode());
- }
-
- public double invokeRelevance(Invoke invoke) {
- return Math.min(CapInheritedRelevance.getValue(), relevance) * computeInliningRelevance.getRelevance(invoke);
- }
-
- @Override
- public String toString() {
- return (graph != null ? MetaUtil.format("%H.%n(%p)", method()) : "") + remainingInvokes;
- }
- }
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Wed May 21 11:45:50 2014 +0200
@@ -28,15 +28,10 @@
import static com.oracle.graal.compiler.common.type.StampFactory.*;
import java.util.*;
-import java.util.function.*;
import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Assumptions.Assumption;
import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
-import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.compiler.common.type.*;
import com.oracle.graal.debug.*;
import com.oracle.graal.debug.Debug.Scope;
@@ -51,15 +46,10 @@
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.common.inlining.InliningPhase.*;
-import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
+import com.oracle.graal.phases.common.inlining.info.*;
public class InliningUtil {
- private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
private static final String inliningDecisionsScopeString = "InliningDecisions";
/**
* Meters the size (in bytecodes) of all methods processed during compilation (i.e., top level
@@ -68,66 +58,6 @@
*/
public static final DebugMetric InlinedBytecodes = Debug.metric("InlinedBytecodes");
- public interface InliningPolicy {
-
- boolean continueInlining(StructuredGraph graph);
-
- boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed);
- }
-
- public interface Inlineable {
-
- int getNodeCount();
-
- Iterable getInvokes();
- }
-
- public static class InlineableGraph implements Inlineable {
-
- private final StructuredGraph graph;
-
- public InlineableGraph(StructuredGraph graph) {
- this.graph = graph;
- }
-
- @Override
- public int getNodeCount() {
- return graph.getNodeCount();
- }
-
- @Override
- public Iterable getInvokes() {
- return graph.getInvokes();
- }
-
- public StructuredGraph getGraph() {
- return graph;
- }
- }
-
- public static class InlineableMacroNode implements Inlineable {
-
- private final Class extends FixedWithNextNode> macroNodeClass;
-
- public InlineableMacroNode(Class extends FixedWithNextNode> macroNodeClass) {
- this.macroNodeClass = macroNodeClass;
- }
-
- @Override
- public int getNodeCount() {
- return 1;
- }
-
- @Override
- public Iterable getInvokes() {
- return Collections.emptyList();
- }
-
- public Class extends FixedWithNextNode> getMacroNodeClass() {
- return macroNodeClass;
- }
- }
-
/**
* Print a HotSpot-style inlining message to the console.
*/
@@ -155,22 +85,21 @@
}
}
- public static boolean logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) {
- return logInliningDecision(info, inliningDepth, allowLogging, true, msg, args);
+ public static void logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) {
+ logInliningDecision(info, inliningDepth, allowLogging, true, msg, args);
}
- public static boolean logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) {
- return logInliningDecision(info, inliningDepth, true, false, msg, args);
+ public static void logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) {
+ logInliningDecision(info, inliningDepth, true, false, msg, args);
}
- public static boolean logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) {
+ public static void logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) {
if (allowLogging) {
printInlining(info, inliningDepth, success, msg, args);
if (shouldLogInliningDecision()) {
logInliningDecision(methodName(info), success, msg, args);
}
}
- return success;
}
public static void logInliningDecision(final String msg, final Object... args) {
@@ -182,34 +111,23 @@
}
}
- private static boolean logNotInlinedMethod(Invoke invoke, String msg) {
+ public static void logNotInlinedMethod(Invoke invoke, String msg) {
if (shouldLogInliningDecision()) {
String methodString = invoke.toString() + (invoke.callTarget() == null ? " callTarget=null" : invoke.callTarget().targetName());
logInliningDecision(methodString, false, msg, new Object[0]);
}
- return false;
}
- private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
- return logNotInlinedMethodAndReturnNull(invoke, inliningDepth, method, msg, new Object[0]);
+ public static void logNotInlined(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
+ logNotInlinedInvoke(invoke, inliningDepth, method, msg, new Object[0]);
}
- private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) {
+ public static void logNotInlinedInvoke(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) {
printInlining(method, invoke, inliningDepth, false, msg, args);
if (shouldLogInliningDecision()) {
String methodString = methodName(method, invoke);
logInliningDecision(methodString, false, msg, args);
}
- return null;
- }
-
- private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
- printInlining(method, invoke, inliningDepth, false, msg, new Object[0]);
- if (shouldLogInliningDecision()) {
- String methodString = methodName(method, invoke);
- logInliningDecision(methodString, false, msg, new Object[0]);
- }
- return false;
}
private static void logInliningDecision(final String methodString, final boolean success, final String msg, final Object... args) {
@@ -255,995 +173,13 @@
return sb.toString();
}
- /**
- * Represents an opportunity for inlining at a given invoke, with the given weight and level.
- * The weight is the amortized weight of the additional code - so smaller is better. The level
- * is the number of nested inlinings that lead to this invoke.
- */
- public interface InlineInfo {
-
- /**
- * The graph containing the {@link #invoke() invocation} that may be inlined.
- */
- StructuredGraph graph();
-
- /**
- * The invocation that may be inlined.
- */
- Invoke invoke();
-
- /**
- * Returns the number of methods that may be inlined by the {@link #invoke() invocation}.
- * This may be more than one in the case of a invocation profile showing a number of "hot"
- * concrete methods dispatched to by the invocation.
- */
- int numberOfMethods();
-
- ResolvedJavaMethod methodAt(int index);
-
- Inlineable inlineableElementAt(int index);
-
- double probabilityAt(int index);
-
- double relevanceAt(int index);
-
- void setInlinableElement(int index, Inlineable inlineableElement);
-
- /**
- * Performs the inlining described by this object and returns the node that represents the
- * return value of the inlined method (or null for void methods and methods that have no
- * non-exceptional exit).
- */
- void inline(Providers providers, Assumptions assumptions);
-
- /**
- * Try to make the call static bindable to avoid interface and virtual method calls.
- */
- void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions);
-
- boolean shouldInline();
- }
-
- public abstract static class AbstractInlineInfo implements InlineInfo {
-
- protected final Invoke invoke;
-
- public AbstractInlineInfo(Invoke invoke) {
- this.invoke = invoke;
- }
-
- @Override
- public StructuredGraph graph() {
- return invoke.asNode().graph();
- }
-
- @Override
- public Invoke invoke() {
- return invoke;
- }
-
- protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
- if (inlineable instanceof InlineableGraph) {
- StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
- InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
- } else {
- assert inlineable instanceof InlineableMacroNode;
-
- Class extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
- inlineMacroNode(invoke, concrete, macroNodeClass);
- }
-
- InlinedBytecodes.add(concrete.getCodeSize());
- assumptions.recordMethodContents(concrete);
- }
- }
-
public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) {
MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget();
MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType()));
invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget);
}
- /**
- * Represents an inlining opportunity where the compiler can statically determine a monomorphic
- * target method and therefore is able to determine the called method exactly.
- */
- public static class ExactInlineInfo extends AbstractInlineInfo {
-
- protected final ResolvedJavaMethod concrete;
- private Inlineable inlineableElement;
- private boolean suppressNullCheck;
-
- public ExactInlineInfo(Invoke invoke, ResolvedJavaMethod concrete) {
- super(invoke);
- this.concrete = concrete;
- assert concrete != null;
- }
-
- public void suppressNullCheck() {
- suppressNullCheck = true;
- }
-
- @Override
- public void inline(Providers providers, Assumptions assumptions) {
- inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
- }
-
- @Override
- public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
- // nothing todo, can already be bound statically
- }
-
- @Override
- public int numberOfMethods() {
- return 1;
- }
-
- @Override
- public ResolvedJavaMethod methodAt(int index) {
- assert index == 0;
- return concrete;
- }
-
- @Override
- public double probabilityAt(int index) {
- assert index == 0;
- return 1.0;
- }
-
- @Override
- public double relevanceAt(int index) {
- assert index == 0;
- return 1.0;
- }
-
- @Override
- public String toString() {
- return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
- }
-
- @Override
- public Inlineable inlineableElementAt(int index) {
- assert index == 0;
- return inlineableElement;
- }
-
- @Override
- public void setInlinableElement(int index, Inlineable inlineableElement) {
- assert index == 0;
- this.inlineableElement = inlineableElement;
- }
-
- public boolean shouldInline() {
- return concrete.shouldBeInlined();
- }
- }
-
- /**
- * Represents an inlining opportunity for which profiling information suggests a monomorphic
- * receiver, but for which the receiver type cannot be proven. A type check guard will be
- * generated if this inlining is performed.
- */
- private static class TypeGuardInlineInfo extends AbstractInlineInfo {
-
- private final ResolvedJavaMethod concrete;
- private final ResolvedJavaType type;
- private Inlineable inlineableElement;
-
- public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) {
- super(invoke);
- this.concrete = concrete;
- this.type = type;
- assert type.isArray() || !type.isAbstract() : type;
- }
-
- @Override
- public int numberOfMethods() {
- return 1;
- }
-
- @Override
- public ResolvedJavaMethod methodAt(int index) {
- assert index == 0;
- return concrete;
- }
-
- @Override
- public Inlineable inlineableElementAt(int index) {
- assert index == 0;
- return inlineableElement;
- }
-
- @Override
- public double probabilityAt(int index) {
- assert index == 0;
- return 1.0;
- }
-
- @Override
- public double relevanceAt(int index) {
- assert index == 0;
- return 1.0;
- }
-
- @Override
- public void setInlinableElement(int index, Inlineable inlineableElement) {
- assert index == 0;
- this.inlineableElement = inlineableElement;
- }
-
- @Override
- public void inline(Providers providers, Assumptions assumptions) {
- createGuard(graph(), providers.getMetaAccess());
- inline(invoke, concrete, inlineableElement, assumptions, false);
- }
-
- @Override
- public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
- createGuard(graph(), metaAccess);
- replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
- }
-
- private void createGuard(StructuredGraph graph, MetaAccessProvider metaAccess) {
- ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
- ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), metaAccess, graph);
- LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.getKind()));
-
- CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub);
- FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
- assert invoke.predecessor() != null;
-
- ValueNode anchoredReceiver = createAnchoredReceiver(graph, guard, type, nonNullReceiver, true);
- invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver);
-
- graph.addBeforeFixed(invoke.asNode(), guard);
- }
-
- @Override
- public String toString() {
- return "type-checked with type " + type.getName() + " and method " + MetaUtil.format("%H.%n(%p):%r", concrete);
- }
-
- public boolean shouldInline() {
- return concrete.shouldBeInlined();
- }
- }
-
- /**
- * Polymorphic inlining of m methods with n type checks (n ≥ m) in case that the profiling
- * information suggests a reasonable amount of different receiver types and different methods.
- * If an unknown type is encountered a deoptimization is triggered.
- */
- private static class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
-
- private final List concretes;
- private final double[] methodProbabilities;
- private final double maximumMethodProbability;
- private final ArrayList typesToConcretes;
- private final ArrayList ptypes;
- private final ArrayList concretesProbabilities;
- private final double notRecordedTypeProbability;
- private final Inlineable[] inlineableElements;
-
- public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList concretes, ArrayList concretesProbabilities, ArrayList ptypes,
- ArrayList typesToConcretes, double notRecordedTypeProbability) {
- super(invoke);
- assert concretes.size() > 0 : "must have at least one method";
- assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
-
- this.concretesProbabilities = concretesProbabilities;
- this.concretes = concretes;
- this.ptypes = ptypes;
- this.typesToConcretes = typesToConcretes;
- this.notRecordedTypeProbability = notRecordedTypeProbability;
- this.inlineableElements = new Inlineable[concretes.size()];
- this.methodProbabilities = computeMethodProbabilities();
- this.maximumMethodProbability = maximumMethodProbability();
- assert maximumMethodProbability > 0;
- }
-
- private double[] computeMethodProbabilities() {
- double[] result = new double[concretes.size()];
- for (int i = 0; i < typesToConcretes.size(); i++) {
- int concrete = typesToConcretes.get(i);
- double probability = ptypes.get(i).getProbability();
- result[concrete] += probability;
- }
- return result;
- }
-
- private double maximumMethodProbability() {
- double max = 0;
- for (int i = 0; i < methodProbabilities.length; i++) {
- max = Math.max(max, methodProbabilities[i]);
- }
- return max;
- }
-
- @Override
- public int numberOfMethods() {
- return concretes.size();
- }
-
- @Override
- public ResolvedJavaMethod methodAt(int index) {
- assert index >= 0 && index < concretes.size();
- return concretes.get(index);
- }
-
- @Override
- public Inlineable inlineableElementAt(int index) {
- assert index >= 0 && index < concretes.size();
- return inlineableElements[index];
- }
-
- @Override
- public double probabilityAt(int index) {
- return methodProbabilities[index];
- }
-
- @Override
- public double relevanceAt(int index) {
- return probabilityAt(index) / maximumMethodProbability;
- }
-
- @Override
- public void setInlinableElement(int index, Inlineable inlineableElement) {
- assert index >= 0 && index < concretes.size();
- inlineableElements[index] = inlineableElement;
- }
-
- @Override
- public void inline(Providers providers, Assumptions assumptions) {
- if (hasSingleMethod()) {
- inlineSingleMethod(graph(), providers.getMetaAccess(), assumptions);
- } else {
- inlineMultipleMethods(graph(), providers, assumptions);
- }
- }
-
- public boolean shouldInline() {
- for (ResolvedJavaMethod method : concretes) {
- if (method.shouldBeInlined()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean hasSingleMethod() {
- return concretes.size() == 1 && !shouldFallbackToInvoke();
- }
-
- private boolean shouldFallbackToInvoke() {
- return notRecordedTypeProbability > 0;
- }
-
- private void inlineMultipleMethods(StructuredGraph graph, Providers providers, Assumptions assumptions) {
- int numberOfMethods = concretes.size();
- FixedNode continuation = invoke.next();
-
- ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
- // setup merge and phi nodes for results and exceptions
- MergeNode returnMerge = graph.add(new MergeNode());
- returnMerge.setStateAfter(invoke.stateAfter());
-
- PhiNode returnValuePhi = null;
- if (invoke.asNode().getKind() != Kind.Void) {
- returnValuePhi = graph.addWithoutUnique(new ValuePhiNode(invoke.asNode().stamp().unrestricted(), returnMerge));
- }
-
- MergeNode exceptionMerge = null;
- PhiNode exceptionObjectPhi = null;
- if (invoke instanceof InvokeWithExceptionNode) {
- InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
- ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
-
- exceptionMerge = graph.add(new MergeNode());
-
- FixedNode exceptionSux = exceptionEdge.next();
- graph.addBeforeFixed(exceptionSux, exceptionMerge);
- exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(Kind.Object), exceptionMerge));
- exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi));
- }
-
- // create one separate block for each invoked method
- BeginNode[] successors = new BeginNode[numberOfMethods + 1];
- for (int i = 0; i < numberOfMethods; i++) {
- successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
- }
-
- // create the successor for an unknown type
- FixedNode unknownTypeSux;
- if (shouldFallbackToInvoke()) {
- unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false);
- } else {
- unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
- }
- successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
-
- // replace the invoke exception edge
- if (invoke instanceof InvokeWithExceptionNode) {
- InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
- ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExceptionNode.exceptionEdge();
- exceptionEdge.replaceAtUsages(exceptionObjectPhi);
- exceptionEdge.setNext(null);
- GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
- }
-
- assert invoke.asNode().isAlive();
-
- // replace the invoke with a switch on the type of the actual receiver
- boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getMetaAccess());
-
- assert invoke.next() == continuation;
- invoke.setNext(null);
- returnMerge.setNext(continuation);
- invoke.asNode().replaceAtUsages(returnValuePhi);
- invoke.asNode().replaceAndDelete(null);
-
- ArrayList replacementNodes = new ArrayList<>();
-
- // do the actual inlining for every invoke
- for (int i = 0; i < numberOfMethods; i++) {
- BeginNode node = successors[i];
- Invoke invokeForInlining = (Invoke) node.next();
-
- ResolvedJavaType commonType;
- if (methodDispatch) {
- commonType = concretes.get(i).getDeclaringClass();
- } else {
- commonType = getLeastCommonType(i);
- }
-
- ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
- boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
- GuardedValueNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
- invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
-
- inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false);
-
- replacementNodes.add(anchoredReceiver);
- }
- if (shouldFallbackToInvoke()) {
- replacementNodes.add(null);
- }
-
- if (OptTailDuplication.getValue()) {
- /*
- * We might want to perform tail duplication at the merge after a type switch, if
- * there are invokes that would benefit from the improvement in type information.
- */
- FixedNode current = returnMerge;
- int opportunities = 0;
- do {
- if (current instanceof InvokeNode && ((InvokeNode) current).callTarget() instanceof MethodCallTargetNode &&
- ((MethodCallTargetNode) ((InvokeNode) current).callTarget()).receiver() == originalReceiver) {
- opportunities++;
- } else if (current.inputs().contains(originalReceiver)) {
- opportunities++;
- }
- current = ((FixedWithNextNode) current).next();
- } while (current instanceof FixedWithNextNode);
-
- if (opportunities > 0) {
- metricInliningTailDuplication.increment();
- Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
- PhaseContext phaseContext = new PhaseContext(providers, assumptions);
- CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
- TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
- }
- }
- }
-
- private int getTypeCount(int concreteMethodIndex) {
- int count = 0;
- for (int i = 0; i < typesToConcretes.size(); i++) {
- if (typesToConcretes.get(i) == concreteMethodIndex) {
- count++;
- }
- }
- return count;
- }
-
- private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
- ResolvedJavaType commonType = null;
- for (int i = 0; i < typesToConcretes.size(); i++) {
- if (typesToConcretes.get(i) == concreteMethodIndex) {
- if (commonType == null) {
- commonType = ptypes.get(i).getType();
- } else {
- commonType = commonType.findLeastCommonAncestor(ptypes.get(i).getType());
- }
- }
- }
- assert commonType != null;
- return commonType;
- }
-
- private ResolvedJavaType getLeastCommonType() {
- ResolvedJavaType result = getLeastCommonType(0);
- for (int i = 1; i < concretes.size(); i++) {
- result = result.findLeastCommonAncestor(getLeastCommonType(i));
- }
- return result;
- }
-
- private void inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, Assumptions assumptions) {
- assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
-
- BeginNode calleeEntryNode = graph.add(new BeginNode());
-
- BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
- BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux};
- createDispatchOnTypeBeforeInvoke(graph, successors, false, metaAccess);
-
- calleeEntryNode.setNext(invoke.asNode());
-
- inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
- }
-
- private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider metaAccess) {
- assert ptypes.size() >= 1;
- ValueNode nonNullReceiver = nonNullReceiver(invoke);
- Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
- LoadHubNode hub = graph.unique(new LoadHubNode(nonNullReceiver, hubKind));
-
- if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
- assert successors.length == concretes.size() + 1;
- assert concretes.size() > 0;
- Debug.log("Method check cascade with %d methods", concretes.size());
-
- ValueNode[] constantMethods = new ValueNode[concretes.size()];
- double[] probability = new double[concretes.size()];
- for (int i = 0; i < concretes.size(); ++i) {
- ResolvedJavaMethod firstMethod = concretes.get(i);
- Constant firstMethodConstant = firstMethod.getEncoding();
-
- ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, metaAccess, graph);
- constantMethods[i] = firstMethodConstantNode;
- double concretesProbability = concretesProbabilities.get(i);
- assert concretesProbability >= 0.0;
- probability[i] = concretesProbability;
- if (i > 0) {
- double prevProbability = probability[i - 1];
- if (prevProbability == 1.0) {
- probability[i] = 1.0;
- } else {
- probability[i] = Math.min(1.0, Math.max(0.0, probability[i] / (1.0 - prevProbability)));
- }
- }
- }
-
- FixedNode lastSucc = successors[concretes.size()];
- for (int i = concretes.size() - 1; i >= 0; --i) {
- LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].getKind()));
- CompareNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i]);
- IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
- method.setNext(ifNode);
- lastSucc = method;
- }
-
- FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
- pred.setNext(lastSucc);
- return true;
- } else {
- Debug.log("Type switch with %d types", concretes.size());
- }
-
- ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
- double[] keyProbabilities = new double[ptypes.size() + 1];
- int[] keySuccessors = new int[ptypes.size() + 1];
- for (int i = 0; i < ptypes.size(); i++) {
- keys[i] = ptypes.get(i).getType();
- keyProbabilities[i] = ptypes.get(i).getProbability();
- keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
- assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
- }
- keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
- keySuccessors[keySuccessors.length - 1] = successors.length - 1;
-
- TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors));
- FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
- pred.setNext(typeSwitch);
- return false;
- }
-
- private boolean chooseMethodDispatch() {
- for (ResolvedJavaMethod concrete : concretes) {
- if (!concrete.isInVirtualMethodTable()) {
- return false;
- }
- }
-
- if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) {
- // Always chose method dispatch if there is a single concrete method and the call
- // site is megamorphic.
- return true;
- }
-
- if (concretes.size() == ptypes.size()) {
- // Always prefer types over methods if the number of types is smaller than the
- // number of methods.
- return false;
- }
-
- return chooseMethodDispatchCostBased();
- }
-
- private boolean chooseMethodDispatchCostBased() {
- double remainder = 1.0 - this.notRecordedTypeProbability;
- double costEstimateMethodDispatch = remainder;
- for (int i = 0; i < concretes.size(); ++i) {
- if (i != 0) {
- costEstimateMethodDispatch += remainder;
- }
- remainder -= concretesProbabilities.get(i);
- }
-
- double costEstimateTypeDispatch = 0.0;
- remainder = 1.0;
- for (int i = 0; i < ptypes.size(); ++i) {
- if (i != 0) {
- costEstimateTypeDispatch += remainder;
- }
- remainder -= ptypes.get(i).getProbability();
- }
- costEstimateTypeDispatch += notRecordedTypeProbability;
- return costEstimateMethodDispatch < costEstimateTypeDispatch;
- }
-
- private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
- boolean useForInlining) {
- Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
- BeginNode calleeEntryNode = graph.add(new BeginNode());
- calleeEntryNode.setNext(duplicatedInvoke.asNode());
-
- AbstractEndNode endNode = graph.add(new EndNode());
- duplicatedInvoke.setNext(endNode);
- returnMerge.addForwardEnd(endNode);
-
- if (returnValuePhi != null) {
- returnValuePhi.addInput(duplicatedInvoke.asNode());
- }
- return calleeEntryNode;
- }
-
- private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining) {
- Invoke result = (Invoke) invoke.asNode().copyWithInputs();
- Node callTarget = result.callTarget().copyWithInputs();
- result.asNode().replaceFirstInput(result.callTarget(), callTarget);
- result.setUseForInlining(useForInlining);
-
- Kind kind = invoke.asNode().getKind();
- if (kind != Kind.Void) {
- FrameState stateAfter = invoke.stateAfter();
- stateAfter = stateAfter.duplicate(stateAfter.bci);
- stateAfter.replaceFirstInput(invoke.asNode(), result.asNode());
- result.setStateAfter(stateAfter);
- }
-
- if (invoke instanceof InvokeWithExceptionNode) {
- assert exceptionMerge != null && exceptionObjectPhi != null;
-
- InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
- ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
- FrameState stateAfterException = exceptionEdge.stateAfter();
-
- ExceptionObjectNode newExceptionEdge = (ExceptionObjectNode) exceptionEdge.copyWithInputs();
- // set new state (pop old exception object, push new one)
- newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionEdge));
-
- AbstractEndNode endNode = graph.add(new EndNode());
- newExceptionEdge.setNext(endNode);
- exceptionMerge.addForwardEnd(endNode);
- exceptionObjectPhi.addInput(newExceptionEdge);
-
- ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
- }
- return result;
- }
-
- @Override
- public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
- if (hasSingleMethod()) {
- devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), metaAccess);
- } else {
- tryToDevirtualizeMultipleMethods(graph(), metaAccess);
- }
- }
-
- private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider metaAccess) {
- MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
- if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
- ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
- ResolvedJavaType leastCommonType = getLeastCommonType();
- // check if we have a common base type that implements the interface -> in that case
- // we have a vtable entry for the interface method and can use a less expensive
- // virtual call
- if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
- ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod);
- if (baseClassTargetMethod != null) {
- devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod), metaAccess);
- }
- }
- }
- }
-
- private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider metaAccess) {
- BeginNode invocationEntry = graph.add(new BeginNode());
- BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
- BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux};
- createDispatchOnTypeBeforeInvoke(graph, successors, true, metaAccess);
-
- invocationEntry.setNext(invoke.asNode());
- ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
- GuardedValueNode anchoredReceiver = createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false);
- invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
- replaceInvokeCallTarget(invoke, graph, kind, target);
- }
-
- private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
- return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
- builder.append(", ");
- builder.append(concretes.size());
- builder.append(" methods [ ");
- for (int i = 0; i < concretes.size(); i++) {
- builder.append(MetaUtil.format(" %H.%n(%p):%r", concretes.get(i)));
- }
- builder.append(" ], ");
- builder.append(ptypes.size());
- builder.append(" type checks [ ");
- for (int i = 0; i < ptypes.size(); i++) {
- builder.append(" ");
- builder.append(ptypes.get(i).getType().getName());
- builder.append(ptypes.get(i).getProbability());
- }
- builder.append(" ]");
- return builder.toString();
- }
- }
-
- /**
- * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic
- * target method, but for which an assumption has to be registered because of non-final classes.
- */
- private static class AssumptionInlineInfo extends ExactInlineInfo {
-
- private final Assumption takenAssumption;
-
- public AssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumption takenAssumption) {
- super(invoke, concrete);
- this.takenAssumption = takenAssumption;
- }
-
- @Override
- public void inline(Providers providers, Assumptions assumptions) {
- assumptions.record(takenAssumption);
- super.inline(providers, assumptions);
- }
-
- @Override
- public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
- assumptions.record(takenAssumption);
- replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
- }
-
- @Override
- public String toString() {
- return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
- }
- }
-
- /**
- * Determines if inlining is possible at the given invoke node.
- *
- * @param invoke the invoke that should be inlined
- * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
- */
- public static InlineInfo getInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, Assumptions assumptions, OptimisticOptimizations optimisticOpts) {
- if (!checkInvokeConditions(invoke)) {
- return null;
- }
- MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
- ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-
- if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
- return getExactInlineInfo(data, invoke, replacements, optimisticOpts, targetMethod);
- }
-
- assert callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface;
-
- ResolvedJavaType holder = targetMethod.getDeclaringClass();
- if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) {
- return null;
- }
- ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp();
- if (receiverStamp.alwaysNull()) {
- // Don't inline if receiver is known to be null
- return null;
- }
- if (receiverStamp.type() != null) {
- // the invoke target might be more specific than the holder (happens after inlining:
- // parameters lose their declared type...)
- ResolvedJavaType receiverType = receiverStamp.type();
- if (receiverType != null && holder.isAssignableFrom(receiverType)) {
- holder = receiverType;
- if (receiverStamp.isExactType()) {
- assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
- ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod);
- if (resolvedMethod != null) {
- return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod);
- }
- }
- }
- }
-
- if (holder.isArray()) {
- // arrays can be treated as Objects
- ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod);
- if (resolvedMethod != null) {
- return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod);
- }
- }
-
- if (assumptions.useOptimisticAssumptions()) {
- ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
- if (uniqueSubtype != null) {
- ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveMethod(targetMethod);
- if (resolvedMethod != null) {
- return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod, new Assumptions.ConcreteSubtype(holder, uniqueSubtype));
- }
- }
-
- ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
- if (concrete != null) {
- return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete));
- }
- }
-
- // type check based inlining
- return getTypeCheckedInlineInfo(data, invoke, maxNumberOfMethods, replacements, targetMethod, optimisticOpts);
- }
-
- private static InlineInfo getAssumptionInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete,
- Assumption takenAssumption) {
- assert !concrete.isAbstract();
- if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
- return null;
- }
- return new AssumptionInlineInfo(invoke, concrete, takenAssumption);
- }
-
- private static InlineInfo getExactInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod targetMethod) {
- assert !targetMethod.isAbstract();
- if (!checkTargetConditions(data, replacements, invoke, targetMethod, optimisticOpts)) {
- return null;
- }
- return new ExactInlineInfo(invoke, targetMethod);
- }
-
- private static InlineInfo getTypeCheckedInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, ResolvedJavaMethod targetMethod,
- OptimisticOptimizations optimisticOpts) {
- JavaTypeProfile typeProfile;
- ValueNode receiver = invoke.callTarget().arguments().get(0);
- if (receiver instanceof TypeProfileProxyNode) {
- TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver;
- typeProfile = typeProfileProxyNode.getProfile();
- } else {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no type profile exists");
- }
-
- ProfiledType[] ptypes = typeProfile.getTypes();
- if (ptypes == null || ptypes.length <= 0) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types in profile");
- }
-
- double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
- if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
- if (!optimisticOpts.inlineMonomorphicCalls()) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
- }
-
- ResolvedJavaType type = ptypes[0].getType();
- assert type.isArray() || !type.isAbstract();
- ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
- if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
- return null;
- }
- return new TypeGuardInlineInfo(invoke, concrete, type);
- } else {
- invoke.setPolymorphic(true);
-
- if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
- }
- if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
- // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
- // the number of types is lower than what can be recorded in a type profile
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
- notRecordedTypeProbability * 100);
- }
-
- // Find unique methods and their probabilities.
- ArrayList concreteMethods = new ArrayList<>();
- ArrayList concreteMethodsProbabilities = new ArrayList<>();
- for (int i = 0; i < ptypes.length; i++) {
- ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod);
- if (concrete == null) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "could not resolve method");
- }
- int index = concreteMethods.indexOf(concrete);
- double curProbability = ptypes[i].getProbability();
- if (index < 0) {
- index = concreteMethods.size();
- concreteMethods.add(concrete);
- concreteMethodsProbabilities.add(curProbability);
- } else {
- concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability);
- }
- }
-
- if (concreteMethods.size() > maxNumberOfMethods) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxNumberOfMethods);
- }
-
- // Clear methods that fall below the threshold.
- if (notRecordedTypeProbability > 0) {
- ArrayList newConcreteMethods = new ArrayList<>();
- ArrayList newConcreteMethodsProbabilities = new ArrayList<>();
- for (int i = 0; i < concreteMethods.size(); ++i) {
- if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue()) {
- newConcreteMethods.add(concreteMethods.get(i));
- newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
- }
- }
-
- if (newConcreteMethods.size() == 0) {
- // No method left that is worth inlining.
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
- concreteMethods.size());
- }
-
- concreteMethods = newConcreteMethods;
- concreteMethodsProbabilities = newConcreteMethodsProbabilities;
- }
-
- // Clean out types whose methods are no longer available.
- ArrayList usedTypes = new ArrayList<>();
- ArrayList typesToConcretes = new ArrayList<>();
- for (ProfiledType type : ptypes) {
- ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod);
- int index = concreteMethods.indexOf(concrete);
- if (index == -1) {
- notRecordedTypeProbability += type.getProbability();
- } else {
- assert type.getType().isArray() || !type.getType().isAbstract() : type + " " + concrete;
- usedTypes.add(type);
- typesToConcretes.add(index);
- }
- }
-
- if (usedTypes.size() == 0) {
- // No type left that is worth checking for.
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
- }
-
- for (ResolvedJavaMethod concrete : concreteMethods) {
- if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
- }
- }
- return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability);
- }
- }
-
- private static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
+ public static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
return createAnchoredReceiver(graph, anchor, receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType));
}
@@ -1252,45 +188,32 @@
return graph.unique(new GuardedValueNode(receiver, anchor, stamp));
}
- // TODO (chaeubl): cleanup this method
- private static boolean checkInvokeConditions(Invoke invoke) {
+ /**
+ * @return null iff the check succeeds, otherwise a (non-null) descriptive message.
+ */
+ public static String checkInvokeConditions(Invoke invoke) {
if (invoke.predecessor() == null || !invoke.asNode().isAlive()) {
- return logNotInlinedMethod(invoke, "the invoke is dead code");
- } else if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
- return logNotInlinedMethod(invoke, "the invoke has already been lowered, or has been created as a low-level node");
- } else if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() == null) {
- return logNotInlinedMethod(invoke, "target method is null");
- } else if (invoke.stateAfter() == null) {
- // TODO (chaeubl): why should an invoke not have a state after?
- return logNotInlinedMethod(invoke, "the invoke has no after state");
- } else if (!invoke.useForInlining()) {
- return logNotInlinedMethod(invoke, "the invoke is marked to be not used for inlining");
- } else if (((MethodCallTargetNode) invoke.callTarget()).receiver() != null && ((MethodCallTargetNode) invoke.callTarget()).receiver().isConstant() &&
- ((MethodCallTargetNode) invoke.callTarget()).receiver().asConstant().isNull()) {
- return logNotInlinedMethod(invoke, "receiver is null");
- } else {
- return true;
+ return "the invoke is dead code";
+ }
+ if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
+ return "the invoke has already been lowered, or has been created as a low-level node";
}
- }
-
- private static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) {
- if (method == null) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method is not resolved");
- } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(replacements, method))) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is a non-intrinsic native method");
- } else if (method.isAbstract()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is an abstract method");
- } else if (!method.getDeclaringClass().isInitialized()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method's class is not initialized");
- } else if (!method.canBeInlined()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is marked non-inlinable");
- } else if (data.countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it exceeds the maximum recursive inlining depth");
- } else if (new OptimisticOptimizations(method.getProfilingInfo()).lessOptimisticThan(optimisticOpts)) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the callee uses less optimistic optimizations than caller");
- } else {
- return true;
+ MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+ if (callTarget.targetMethod() == null) {
+ return "target method is null";
+ }
+ if (invoke.stateAfter() == null) {
+ // TODO (chaeubl): why should an invoke not have a state after?
+ return "the invoke has no after state";
}
+ if (!invoke.useForInlining()) {
+ return "the invoke is marked to be not used for inlining";
+ }
+ ValueNode receiver = callTarget.receiver();
+ if (receiver != null && receiver.isConstant() && receiver.asConstant().isNull()) {
+ return "receiver is null";
+ }
+ return null;
}
/**
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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.phases.common.inlining.info;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
+
+public abstract class AbstractInlineInfo implements InlineInfo {
+
+ protected final Invoke invoke;
+
+ public AbstractInlineInfo(Invoke invoke) {
+ this.invoke = invoke;
+ }
+
+ @Override
+ public StructuredGraph graph() {
+ return invoke.asNode().graph();
+ }
+
+ @Override
+ public Invoke invoke() {
+ return invoke;
+ }
+
+ protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
+ if (inlineable instanceof InlineableGraph) {
+ StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
+ InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
+ } else {
+ assert inlineable instanceof InlineableMacroNode;
+
+ Class extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
+ InliningUtil.inlineMacroNode(invoke, concrete, macroNodeClass);
+ }
+
+ InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
+ assumptions.recordMethodContents(concrete);
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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.phases.common.inlining.info;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.MetaAccessProvider;
+import com.oracle.graal.api.meta.MetaUtil;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.util.Providers;
+import com.oracle.graal.api.code.Assumptions.Assumption;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+
+/**
+ * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic
+ * target method, but for which an assumption has to be registered because of non-final classes.
+ */
+public class AssumptionInlineInfo extends ExactInlineInfo {
+
+ private final Assumption takenAssumption;
+
+ public AssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumption takenAssumption) {
+ super(invoke, concrete);
+ this.takenAssumption = takenAssumption;
+ }
+
+ @Override
+ public void inline(Providers providers, Assumptions assumptions) {
+ assumptions.record(takenAssumption);
+ super.inline(providers, assumptions);
+ }
+
+ @Override
+ public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+ assumptions.record(takenAssumption);
+ InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
+ }
+
+ @Override
+ public String toString() {
+ return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/ExactInlineInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/ExactInlineInfo.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,106 @@
+/*
+ * 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.phases.common.inlining.info;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.MetaAccessProvider;
+import com.oracle.graal.api.meta.MetaUtil;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.util.Providers;
+
+/**
+ * Represents an inlining opportunity where the compiler can statically determine a monomorphic
+ * target method and therefore is able to determine the called method exactly.
+ */
+public class ExactInlineInfo extends AbstractInlineInfo {
+
+ protected final ResolvedJavaMethod concrete;
+ private Inlineable inlineableElement;
+ private boolean suppressNullCheck;
+
+ public ExactInlineInfo(Invoke invoke, ResolvedJavaMethod concrete) {
+ super(invoke);
+ this.concrete = concrete;
+ assert concrete != null;
+ }
+
+ public void suppressNullCheck() {
+ suppressNullCheck = true;
+ }
+
+ @Override
+ public void inline(Providers providers, Assumptions assumptions) {
+ inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
+ }
+
+ @Override
+ public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+ // nothing todo, can already be bound statically
+ }
+
+ @Override
+ public int numberOfMethods() {
+ return 1;
+ }
+
+ @Override
+ public ResolvedJavaMethod methodAt(int index) {
+ assert index == 0;
+ return concrete;
+ }
+
+ @Override
+ public double probabilityAt(int index) {
+ assert index == 0;
+ return 1.0;
+ }
+
+ @Override
+ public double relevanceAt(int index) {
+ assert index == 0;
+ return 1.0;
+ }
+
+ @Override
+ public String toString() {
+ return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
+ }
+
+ @Override
+ public Inlineable inlineableElementAt(int index) {
+ assert index == 0;
+ return inlineableElement;
+ }
+
+ @Override
+ public void setInlinableElement(int index, Inlineable inlineableElement) {
+ assert index == 0;
+ this.inlineableElement = inlineableElement;
+ }
+
+ public boolean shouldInline() {
+ return concrete.shouldBeInlined();
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,80 @@
+/*
+ * 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.phases.common.inlining.info;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.MetaAccessProvider;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.util.Providers;
+
+/**
+ * Represents an opportunity for inlining at a given invoke, with the given weight and level. The
+ * weight is the amortized weight of the additional code - so smaller is better. The level is the
+ * number of nested inlinings that lead to this invoke.
+ */
+public interface InlineInfo {
+
+ /**
+ * The graph containing the {@link #invoke() invocation} that may be inlined.
+ */
+ StructuredGraph graph();
+
+ /**
+ * The invocation that may be inlined.
+ */
+ Invoke invoke();
+
+ /**
+ * Returns the number of methods that may be inlined by the {@link #invoke() invocation}. This
+ * may be more than one in the case of a invocation profile showing a number of "hot" concrete
+ * methods dispatched to by the invocation.
+ */
+ int numberOfMethods();
+
+ ResolvedJavaMethod methodAt(int index);
+
+ Inlineable inlineableElementAt(int index);
+
+ double probabilityAt(int index);
+
+ double relevanceAt(int index);
+
+ void setInlinableElement(int index, Inlineable inlineableElement);
+
+ /**
+ * Performs the inlining described by this object and returns the node that represents the
+ * return value of the inlined method (or null for void methods and methods that have no
+ * non-exceptional exit).
+ */
+ void inline(Providers providers, Assumptions assumptions);
+
+ /**
+ * Try to make the call static bindable to avoid interface and virtual method calls.
+ */
+ void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions);
+
+ boolean shouldInline();
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,551 @@
+/*
+ * 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.phases.common.inlining.info;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+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.util.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+
+/**
+ * Polymorphic inlining of m methods with n type checks (n ≥ m) in case that the profiling
+ * information suggests a reasonable amount of different receiver types and different methods. If an
+ * unknown type is encountered a deoptimization is triggered.
+ */
+public class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
+
+ private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
+
+ private final List concretes;
+ private final double[] methodProbabilities;
+ private final double maximumMethodProbability;
+ private final ArrayList typesToConcretes;
+ private final ArrayList ptypes;
+ private final ArrayList concretesProbabilities;
+ private final double notRecordedTypeProbability;
+ private final Inlineable[] inlineableElements;
+
+ public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList concretes, ArrayList concretesProbabilities, ArrayList ptypes,
+ ArrayList typesToConcretes, double notRecordedTypeProbability) {
+ super(invoke);
+ assert concretes.size() > 0 : "must have at least one method";
+ assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
+
+ this.concretesProbabilities = concretesProbabilities;
+ this.concretes = concretes;
+ this.ptypes = ptypes;
+ this.typesToConcretes = typesToConcretes;
+ this.notRecordedTypeProbability = notRecordedTypeProbability;
+ this.inlineableElements = new Inlineable[concretes.size()];
+ this.methodProbabilities = computeMethodProbabilities();
+ this.maximumMethodProbability = maximumMethodProbability();
+ assert maximumMethodProbability > 0;
+ }
+
+ private double[] computeMethodProbabilities() {
+ double[] result = new double[concretes.size()];
+ for (int i = 0; i < typesToConcretes.size(); i++) {
+ int concrete = typesToConcretes.get(i);
+ double probability = ptypes.get(i).getProbability();
+ result[concrete] += probability;
+ }
+ return result;
+ }
+
+ private double maximumMethodProbability() {
+ double max = 0;
+ for (int i = 0; i < methodProbabilities.length; i++) {
+ max = Math.max(max, methodProbabilities[i]);
+ }
+ return max;
+ }
+
+ @Override
+ public int numberOfMethods() {
+ return concretes.size();
+ }
+
+ @Override
+ public ResolvedJavaMethod methodAt(int index) {
+ assert index >= 0 && index < concretes.size();
+ return concretes.get(index);
+ }
+
+ @Override
+ public Inlineable inlineableElementAt(int index) {
+ assert index >= 0 && index < concretes.size();
+ return inlineableElements[index];
+ }
+
+ @Override
+ public double probabilityAt(int index) {
+ return methodProbabilities[index];
+ }
+
+ @Override
+ public double relevanceAt(int index) {
+ return probabilityAt(index) / maximumMethodProbability;
+ }
+
+ @Override
+ public void setInlinableElement(int index, Inlineable inlineableElement) {
+ assert index >= 0 && index < concretes.size();
+ inlineableElements[index] = inlineableElement;
+ }
+
+ @Override
+ public void inline(Providers providers, Assumptions assumptions) {
+ if (hasSingleMethod()) {
+ inlineSingleMethod(graph(), providers.getMetaAccess(), assumptions);
+ } else {
+ inlineMultipleMethods(graph(), providers, assumptions);
+ }
+ }
+
+ public boolean shouldInline() {
+ for (ResolvedJavaMethod method : concretes) {
+ if (method.shouldBeInlined()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean hasSingleMethod() {
+ return concretes.size() == 1 && !shouldFallbackToInvoke();
+ }
+
+ private boolean shouldFallbackToInvoke() {
+ return notRecordedTypeProbability > 0;
+ }
+
+ private void inlineMultipleMethods(StructuredGraph graph, Providers providers, Assumptions assumptions) {
+ int numberOfMethods = concretes.size();
+ FixedNode continuation = invoke.next();
+
+ ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
+ // setup merge and phi nodes for results and exceptions
+ MergeNode returnMerge = graph.add(new MergeNode());
+ returnMerge.setStateAfter(invoke.stateAfter());
+
+ PhiNode returnValuePhi = null;
+ if (invoke.asNode().getKind() != Kind.Void) {
+ returnValuePhi = graph.addWithoutUnique(new ValuePhiNode(invoke.asNode().stamp().unrestricted(), returnMerge));
+ }
+
+ MergeNode exceptionMerge = null;
+ PhiNode exceptionObjectPhi = null;
+ if (invoke instanceof InvokeWithExceptionNode) {
+ InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+ ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+
+ exceptionMerge = graph.add(new MergeNode());
+
+ FixedNode exceptionSux = exceptionEdge.next();
+ graph.addBeforeFixed(exceptionSux, exceptionMerge);
+ exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(Kind.Object), exceptionMerge));
+ exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi));
+ }
+
+ // create one separate block for each invoked method
+ BeginNode[] successors = new BeginNode[numberOfMethods + 1];
+ for (int i = 0; i < numberOfMethods; i++) {
+ successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
+ }
+
+ // create the successor for an unknown type
+ FixedNode unknownTypeSux;
+ if (shouldFallbackToInvoke()) {
+ unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false);
+ } else {
+ unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
+ }
+ successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
+
+ // replace the invoke exception edge
+ if (invoke instanceof InvokeWithExceptionNode) {
+ InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
+ ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExceptionNode.exceptionEdge();
+ exceptionEdge.replaceAtUsages(exceptionObjectPhi);
+ exceptionEdge.setNext(null);
+ GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
+ }
+
+ assert invoke.asNode().isAlive();
+
+ // replace the invoke with a switch on the type of the actual receiver
+ boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getMetaAccess());
+
+ assert invoke.next() == continuation;
+ invoke.setNext(null);
+ returnMerge.setNext(continuation);
+ invoke.asNode().replaceAtUsages(returnValuePhi);
+ invoke.asNode().replaceAndDelete(null);
+
+ ArrayList replacementNodes = new ArrayList<>();
+
+ // do the actual inlining for every invoke
+ for (int i = 0; i < numberOfMethods; i++) {
+ BeginNode node = successors[i];
+ Invoke invokeForInlining = (Invoke) node.next();
+
+ ResolvedJavaType commonType;
+ if (methodDispatch) {
+ commonType = concretes.get(i).getDeclaringClass();
+ } else {
+ commonType = getLeastCommonType(i);
+ }
+
+ ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
+ boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
+ GuardedValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, node, commonType, receiver, exact);
+ invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+
+ inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false);
+
+ replacementNodes.add(anchoredReceiver);
+ }
+ if (shouldFallbackToInvoke()) {
+ replacementNodes.add(null);
+ }
+
+ if (OptTailDuplication.getValue()) {
+ /*
+ * We might want to perform tail duplication at the merge after a type switch, if there
+ * are invokes that would benefit from the improvement in type information.
+ */
+ FixedNode current = returnMerge;
+ int opportunities = 0;
+ do {
+ if (current instanceof InvokeNode && ((InvokeNode) current).callTarget() instanceof MethodCallTargetNode &&
+ ((MethodCallTargetNode) ((InvokeNode) current).callTarget()).receiver() == originalReceiver) {
+ opportunities++;
+ } else if (current.inputs().contains(originalReceiver)) {
+ opportunities++;
+ }
+ current = ((FixedWithNextNode) current).next();
+ } while (current instanceof FixedWithNextNode);
+
+ if (opportunities > 0) {
+ metricInliningTailDuplication.increment();
+ Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
+ PhaseContext phaseContext = new PhaseContext(providers, assumptions);
+ CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
+ TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
+ }
+ }
+ }
+
+ private int getTypeCount(int concreteMethodIndex) {
+ int count = 0;
+ for (int i = 0; i < typesToConcretes.size(); i++) {
+ if (typesToConcretes.get(i) == concreteMethodIndex) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
+ ResolvedJavaType commonType = null;
+ for (int i = 0; i < typesToConcretes.size(); i++) {
+ if (typesToConcretes.get(i) == concreteMethodIndex) {
+ if (commonType == null) {
+ commonType = ptypes.get(i).getType();
+ } else {
+ commonType = commonType.findLeastCommonAncestor(ptypes.get(i).getType());
+ }
+ }
+ }
+ assert commonType != null;
+ return commonType;
+ }
+
+ private ResolvedJavaType getLeastCommonType() {
+ ResolvedJavaType result = getLeastCommonType(0);
+ for (int i = 1; i < concretes.size(); i++) {
+ result = result.findLeastCommonAncestor(getLeastCommonType(i));
+ }
+ return result;
+ }
+
+ private void inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, Assumptions assumptions) {
+ assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
+
+ BeginNode calleeEntryNode = graph.add(new BeginNode());
+
+ BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+ BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux};
+ createDispatchOnTypeBeforeInvoke(graph, successors, false, metaAccess);
+
+ calleeEntryNode.setNext(invoke.asNode());
+
+ inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
+ }
+
+ private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider metaAccess) {
+ assert ptypes.size() >= 1;
+ ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
+ Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(ResolvedJavaType.Representation.ObjectHub).getKind();
+ LoadHubNode hub = graph.unique(new LoadHubNode(nonNullReceiver, hubKind));
+
+ if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
+ assert successors.length == concretes.size() + 1;
+ assert concretes.size() > 0;
+ Debug.log("Method check cascade with %d methods", concretes.size());
+
+ ValueNode[] constantMethods = new ValueNode[concretes.size()];
+ double[] probability = new double[concretes.size()];
+ for (int i = 0; i < concretes.size(); ++i) {
+ ResolvedJavaMethod firstMethod = concretes.get(i);
+ Constant firstMethodConstant = firstMethod.getEncoding();
+
+ ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, metaAccess, graph);
+ constantMethods[i] = firstMethodConstantNode;
+ double concretesProbability = concretesProbabilities.get(i);
+ assert concretesProbability >= 0.0;
+ probability[i] = concretesProbability;
+ if (i > 0) {
+ double prevProbability = probability[i - 1];
+ if (prevProbability == 1.0) {
+ probability[i] = 1.0;
+ } else {
+ probability[i] = Math.min(1.0, Math.max(0.0, probability[i] / (1.0 - prevProbability)));
+ }
+ }
+ }
+
+ ResolvedJavaType receiverType = invoke.getReceiverType();
+ FixedNode lastSucc = successors[concretes.size()];
+ for (int i = concretes.size() - 1; i >= 0; --i) {
+ LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), receiverType, hub, constantMethods[i].getKind()));
+ CompareNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i]);
+ IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
+ method.setNext(ifNode);
+ lastSucc = method;
+ }
+
+ FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
+ pred.setNext(lastSucc);
+ return true;
+ } else {
+ Debug.log("Type switch with %d types", concretes.size());
+ }
+
+ ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
+ double[] keyProbabilities = new double[ptypes.size() + 1];
+ int[] keySuccessors = new int[ptypes.size() + 1];
+ for (int i = 0; i < ptypes.size(); i++) {
+ keys[i] = ptypes.get(i).getType();
+ keyProbabilities[i] = ptypes.get(i).getProbability();
+ keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
+ assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
+ }
+ keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
+ keySuccessors[keySuccessors.length - 1] = successors.length - 1;
+
+ TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors));
+ FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
+ pred.setNext(typeSwitch);
+ return false;
+ }
+
+ private boolean chooseMethodDispatch() {
+ ResolvedJavaType receiverType = invoke.getReceiverType();
+ for (ResolvedJavaMethod concrete : concretes) {
+ if (!concrete.isInVirtualMethodTable(receiverType)) {
+ return false;
+ }
+ }
+
+ if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) {
+ // Always chose method dispatch if there is a single concrete method and the call
+ // site is megamorphic.
+ return true;
+ }
+
+ if (concretes.size() == ptypes.size()) {
+ // Always prefer types over methods if the number of types is smaller than the
+ // number of methods.
+ return false;
+ }
+
+ return chooseMethodDispatchCostBased();
+ }
+
+ private boolean chooseMethodDispatchCostBased() {
+ double remainder = 1.0 - this.notRecordedTypeProbability;
+ double costEstimateMethodDispatch = remainder;
+ for (int i = 0; i < concretes.size(); ++i) {
+ if (i != 0) {
+ costEstimateMethodDispatch += remainder;
+ }
+ remainder -= concretesProbabilities.get(i);
+ }
+
+ double costEstimateTypeDispatch = 0.0;
+ remainder = 1.0;
+ for (int i = 0; i < ptypes.size(); ++i) {
+ if (i != 0) {
+ costEstimateTypeDispatch += remainder;
+ }
+ remainder -= ptypes.get(i).getProbability();
+ }
+ costEstimateTypeDispatch += notRecordedTypeProbability;
+ return costEstimateMethodDispatch < costEstimateTypeDispatch;
+ }
+
+ private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
+ boolean useForInlining) {
+ Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
+ BeginNode calleeEntryNode = graph.add(new BeginNode());
+ calleeEntryNode.setNext(duplicatedInvoke.asNode());
+
+ AbstractEndNode endNode = graph.add(new EndNode());
+ duplicatedInvoke.setNext(endNode);
+ returnMerge.addForwardEnd(endNode);
+
+ if (returnValuePhi != null) {
+ returnValuePhi.addInput(duplicatedInvoke.asNode());
+ }
+ return calleeEntryNode;
+ }
+
+ private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining) {
+ Invoke result = (Invoke) invoke.asNode().copyWithInputs();
+ Node callTarget = result.callTarget().copyWithInputs();
+ result.asNode().replaceFirstInput(result.callTarget(), callTarget);
+ result.setUseForInlining(useForInlining);
+
+ Kind kind = invoke.asNode().getKind();
+ if (kind != Kind.Void) {
+ FrameState stateAfter = invoke.stateAfter();
+ stateAfter = stateAfter.duplicate(stateAfter.bci);
+ stateAfter.replaceFirstInput(invoke.asNode(), result.asNode());
+ result.setStateAfter(stateAfter);
+ }
+
+ if (invoke instanceof InvokeWithExceptionNode) {
+ assert exceptionMerge != null && exceptionObjectPhi != null;
+
+ InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+ ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+ FrameState stateAfterException = exceptionEdge.stateAfter();
+
+ ExceptionObjectNode newExceptionEdge = (ExceptionObjectNode) exceptionEdge.copyWithInputs();
+ // set new state (pop old exception object, push new one)
+ newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionEdge));
+
+ AbstractEndNode endNode = graph.add(new EndNode());
+ newExceptionEdge.setNext(endNode);
+ exceptionMerge.addForwardEnd(endNode);
+ exceptionObjectPhi.addInput(newExceptionEdge);
+
+ ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
+ }
+ return result;
+ }
+
+ @Override
+ public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+ if (hasSingleMethod()) {
+ devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), metaAccess);
+ } else {
+ tryToDevirtualizeMultipleMethods(graph(), metaAccess);
+ }
+ }
+
+ private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider metaAccess) {
+ MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
+ if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
+ ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
+ ResolvedJavaType leastCommonType = getLeastCommonType();
+ ResolvedJavaType contextType = invoke.getContextType();
+ // check if we have a common base type that implements the interface -> in that case
+ // we have a vtable entry for the interface method and can use a less expensive
+ // virtual call
+ if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
+ ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod, contextType);
+ if (baseClassTargetMethod != null) {
+ devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod, contextType), metaAccess);
+ }
+ }
+ }
+ }
+
+ private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider metaAccess) {
+ BeginNode invocationEntry = graph.add(new BeginNode());
+ BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+ BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux};
+ createDispatchOnTypeBeforeInvoke(graph, successors, true, metaAccess);
+
+ invocationEntry.setNext(invoke.asNode());
+ ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
+ GuardedValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false);
+ invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+ InliningUtil.replaceInvokeCallTarget(invoke, graph, kind, target);
+ }
+
+ private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
+ return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
+ builder.append(", ");
+ builder.append(concretes.size());
+ builder.append(" methods [ ");
+ for (int i = 0; i < concretes.size(); i++) {
+ builder.append(MetaUtil.format(" %H.%n(%p):%r", concretes.get(i)));
+ }
+ builder.append(" ], ");
+ builder.append(ptypes.size());
+ builder.append(" type checks [ ");
+ for (int i = 0; i < ptypes.size(); i++) {
+ builder.append(" ");
+ builder.append(ptypes.get(i).getType().getName());
+ builder.append(ptypes.get(i).getProbability());
+ }
+ builder.append(" ]");
+ return builder.toString();
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,124 @@
+/*
+ * 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.phases.common.inlining.info;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.Condition;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.CompareNode;
+import com.oracle.graal.nodes.extended.LoadHubNode;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.util.Providers;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+
+/**
+ * Represents an inlining opportunity for which profiling information suggests a monomorphic
+ * receiver, but for which the receiver type cannot be proven. A type check guard will be generated
+ * if this inlining is performed.
+ */
+public class TypeGuardInlineInfo extends AbstractInlineInfo {
+
+ private final ResolvedJavaMethod concrete;
+ private final ResolvedJavaType type;
+ private Inlineable inlineableElement;
+
+ public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) {
+ super(invoke);
+ this.concrete = concrete;
+ this.type = type;
+ assert type.isArray() || !type.isAbstract() : type;
+ }
+
+ @Override
+ public int numberOfMethods() {
+ return 1;
+ }
+
+ @Override
+ public ResolvedJavaMethod methodAt(int index) {
+ assert index == 0;
+ return concrete;
+ }
+
+ @Override
+ public Inlineable inlineableElementAt(int index) {
+ assert index == 0;
+ return inlineableElement;
+ }
+
+ @Override
+ public double probabilityAt(int index) {
+ assert index == 0;
+ return 1.0;
+ }
+
+ @Override
+ public double relevanceAt(int index) {
+ assert index == 0;
+ return 1.0;
+ }
+
+ @Override
+ public void setInlinableElement(int index, Inlineable inlineableElement) {
+ assert index == 0;
+ this.inlineableElement = inlineableElement;
+ }
+
+ @Override
+ public void inline(Providers providers, Assumptions assumptions) {
+ createGuard(graph(), providers.getMetaAccess());
+ inline(invoke, concrete, inlineableElement, assumptions, false);
+ }
+
+ @Override
+ public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+ createGuard(graph(), metaAccess);
+ InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
+ }
+
+ private void createGuard(StructuredGraph graph, MetaAccessProvider metaAccess) {
+ ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
+ ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(ResolvedJavaType.Representation.ObjectHub), metaAccess, graph);
+ LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.getKind()));
+
+ CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub);
+ FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
+ assert invoke.predecessor() != null;
+
+ ValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, guard, type, nonNullReceiver, true);
+ invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver);
+
+ graph.addBeforeFixed(invoke.asNode(), guard);
+ }
+
+ @Override
+ public String toString() {
+ return "type-checked with type " + type.getName() + " and method " + MetaUtil.format("%H.%n(%p):%r", concrete);
+ }
+
+ public boolean shouldInline() {
+ return concrete.shouldBeInlined();
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012, 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.phases.common.inlining.info.elem;
+
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.tiers.HighTierContext;
+
+public interface Inlineable {
+
+ static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) {
+ Class extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
+ if (macroNodeClass != null) {
+ return new InlineableMacroNode(macroNodeClass);
+ } else {
+ return new InlineableGraph(method, invoke, context, canonicalizer);
+ }
+ }
+
+ int getNodeCount();
+
+ Iterable getInvokes();
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2012, 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.phases.common.inlining.info.elem;
+
+import com.oracle.graal.api.meta.Constant;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.graph.NodeInputList;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.tiers.HighTierContext;
+
+import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
+
+public class InlineableGraph implements Inlineable {
+
+ private final StructuredGraph graph;
+
+ public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
+ this.graph = buildGraph(method, invoke, context, canonicalizer);
+ }
+
+ private static StructuredGraph buildGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
+ final StructuredGraph newGraph;
+ final boolean parseBytecodes;
+
+ // TODO (chaeubl): copying the graph is only necessary if it is modified or if it contains
+ // any invokes
+ StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(context.getReplacements(), method);
+ if (intrinsicGraph != null) {
+ newGraph = intrinsicGraph.copy();
+ parseBytecodes = false;
+ } else {
+ StructuredGraph cachedGraph = getCachedGraph(method, context);
+ if (cachedGraph != null) {
+ newGraph = cachedGraph.copy();
+ parseBytecodes = false;
+ } else {
+ newGraph = new StructuredGraph(method);
+ parseBytecodes = true;
+ }
+ }
+
+ try (Debug.Scope s = Debug.scope("InlineGraph", newGraph)) {
+ if (parseBytecodes) {
+ parseBytecodes(newGraph, context, canonicalizer);
+ }
+
+ boolean callerHasMoreInformationAboutArguments = false;
+ NodeInputList args = invoke.callTarget().arguments();
+ for (ParameterNode param : newGraph.getNodes(ParameterNode.class).snapshot()) {
+ ValueNode arg = args.get(param.index());
+ if (arg.isConstant()) {
+ Constant constant = arg.asConstant();
+ newGraph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph));
+ callerHasMoreInformationAboutArguments = true;
+ } else {
+ Stamp joinedStamp = param.stamp().join(arg.stamp());
+ if (joinedStamp != null && !joinedStamp.equals(param.stamp())) {
+ param.setStamp(joinedStamp);
+ callerHasMoreInformationAboutArguments = true;
+ }
+ }
+ }
+
+ if (!callerHasMoreInformationAboutArguments) {
+ // TODO (chaeubl): if args are not more concrete, inlining should be avoided
+ // in most cases or we could at least use the previous graph size + invoke
+ // probability to check the inlining
+ }
+
+ if (OptCanonicalizer.getValue()) {
+ canonicalizer.apply(newGraph, context);
+ }
+
+ return newGraph;
+ } catch (Throwable e) {
+ throw Debug.handle(e);
+ }
+ }
+
+ private static StructuredGraph getCachedGraph(ResolvedJavaMethod method, HighTierContext context) {
+ if (context.getGraphCache() != null) {
+ StructuredGraph cachedGraph = context.getGraphCache().get(method);
+ if (cachedGraph != null) {
+ return cachedGraph;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * This method builds the IR nodes for newGraph
and canonicalizes them. Provided
+ * profiling info is mature, the resulting graph is cached.
+ */
+ private static StructuredGraph parseBytecodes(StructuredGraph newGraph, HighTierContext context, CanonicalizerPhase canonicalizer) {
+ final boolean hasMatureProfilingInfo = newGraph.method().getProfilingInfo().isMature();
+
+ if (context.getGraphBuilderSuite() != null) {
+ context.getGraphBuilderSuite().apply(newGraph, context);
+ }
+ assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
+
+ new DeadCodeEliminationPhase().apply(newGraph);
+
+ if (OptCanonicalizer.getValue()) {
+ canonicalizer.apply(newGraph, context);
+ }
+
+ if (hasMatureProfilingInfo && context.getGraphCache() != null) {
+ context.getGraphCache().put(newGraph.method(), newGraph.copy());
+ }
+ return newGraph;
+ }
+
+ @Override
+ public int getNodeCount() {
+ return graph.getNodeCount();
+ }
+
+ @Override
+ public Iterable getInvokes() {
+ return graph.getInvokes();
+ }
+
+ public StructuredGraph getGraph() {
+ return graph;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableMacroNode.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableMacroNode.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 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.phases.common.inlining.info.elem;
+
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.Invoke;
+
+import java.util.Collections;
+
+public class InlineableMacroNode implements Inlineable {
+
+ private final Class extends FixedWithNextNode> macroNodeClass;
+
+ public InlineableMacroNode(Class extends FixedWithNextNode> macroNodeClass) {
+ this.macroNodeClass = macroNodeClass;
+ }
+
+ @Override
+ public int getNodeCount() {
+ return 1;
+ }
+
+ @Override
+ public Iterable getInvokes() {
+ return Collections.emptyList();
+ }
+
+ public Class extends FixedWithNextNode> getMacroNodeClass() {
+ return macroNodeClass;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2011, 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.phases.common.inlining.policy;
+
+import com.oracle.graal.api.meta.ProfilingInfo;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.Replacements;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+
+import java.util.Map;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.RelevanceCapForInlining;
+import static com.oracle.graal.phases.common.inlining.InliningPhase.Options.AlwaysInlineIntrinsics;
+
+public abstract class AbstractInliningPolicy implements InliningPolicy {
+
+ protected final Map hints;
+
+ public AbstractInliningPolicy(Map hints) {
+ this.hints = hints;
+ }
+
+ protected double computeMaximumSize(double relevance, int configuredMaximum) {
+ double inlineRatio = Math.min(RelevanceCapForInlining.getValue(), relevance);
+ return configuredMaximum * inlineRatio;
+ }
+
+ protected double getInliningBonus(InlineInfo info) {
+ if (hints != null && hints.containsKey(info.invoke())) {
+ return hints.get(info.invoke());
+ }
+ return 1;
+ }
+
+ protected boolean isIntrinsic(Replacements replacements, InlineInfo info) {
+ if (AlwaysInlineIntrinsics.getValue()) {
+ return onlyIntrinsics(replacements, info);
+ } else {
+ return onlyForcedIntrinsics(replacements, info);
+ }
+ }
+
+ private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) {
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) {
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
+ return false;
+ }
+ if (!replacements.isForcedSubstitution(info.methodAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected static int previousLowLevelGraphSize(InlineInfo info) {
+ int size = 0;
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ ResolvedJavaMethod m = info.methodAt(i);
+ ProfilingInfo profile = m.getProfilingInfo();
+ int compiledGraphSize = profile.getCompilerIRSize(StructuredGraph.class);
+ if (compiledGraphSize > 0) {
+ size += compiledGraphSize;
+ }
+ }
+ return size;
+ }
+
+ protected static int determineNodeCount(InlineInfo info) {
+ int nodes = 0;
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ Inlineable elem = info.inlineableElementAt(i);
+ if (elem != null) {
+ nodes += elem.getNodeCount();
+ }
+ }
+ return nodes;
+ }
+
+ protected static double determineInvokeProbability(ToDoubleFunction probabilities, InlineInfo info) {
+ double invokeProbability = 0;
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ Inlineable callee = info.inlineableElementAt(i);
+ Iterable invokes = callee.getInvokes();
+ if (invokes.iterator().hasNext()) {
+ for (Invoke invoke : invokes) {
+ invokeProbability += probabilities.applyAsDouble(invoke.asNode());
+ }
+ }
+ }
+ return invokeProbability;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2011, 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.phases.common.inlining.policy;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.Replacements;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+
+import java.util.Map;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+public class GreedyInliningPolicy extends AbstractInliningPolicy {
+
+ private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
+
+ public GreedyInliningPolicy(Map hints) {
+ super(hints);
+ }
+
+ public boolean continueInlining(StructuredGraph currentGraph) {
+ if (currentGraph.getNodeCount() >= MaximumDesiredSize.getValue()) {
+ InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize");
+ metricInliningStoppedByMaxDesiredSize.increment();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
+ boolean fullyProcessed) {
+ if (InlineEverything.getValue()) {
+ InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
+ return true;
+ }
+
+ if (isIntrinsic(replacements, info)) {
+ InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
+ return true;
+ }
+
+ if (info.shouldInline()) {
+ InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
+ return true;
+ }
+
+ double inliningBonus = getInliningBonus(info);
+ int nodes = determineNodeCount(info);
+ int lowLevelGraphSize = previousLowLevelGraphSize(info);
+
+ if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) {
+ InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize,
+ relevance, probability, inliningBonus, nodes);
+ return false;
+ }
+
+ if (nodes < TrivialInliningSize.getValue() * inliningBonus) {
+ InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
+ return true;
+ }
+
+ /*
+ * TODO (chaeubl): invoked methods that are on important paths but not yet compiled -> will
+ * be compiled anyways and it is likely that we are the only caller... might be useful to
+ * inline those methods but increases bootstrap time (maybe those methods are also getting
+ * queued in the compilation queue concurrently)
+ */
+ double invokes = determineInvokeProbability(probabilities, info);
+ if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) {
+ InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance,
+ probability, inliningBonus, nodes);
+ return false;
+ }
+
+ double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue() * inliningBonus));
+ if (nodes <= maximumNodes) {
+ InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
+ nodes, maximumNodes);
+ return true;
+ }
+
+ InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
+ return false;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011, 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.phases.common.inlining.policy;
+
+import com.oracle.graal.api.code.BailoutException;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.Replacements;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize;
+
+public final class InlineEverythingPolicy implements InliningPolicy {
+
+ public boolean continueInlining(StructuredGraph graph) {
+ if (graph.getNodeCount() >= MaximumDesiredSize.getValue()) {
+ throw new BailoutException("Inline all calls failed. The resulting graph is too large.");
+ }
+ return true;
+ }
+
+ public boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
+ boolean fullyProcessed) {
+ return true;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2011, 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.phases.common.inlining.policy;
+
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.Replacements;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+
+import java.util.function.ToDoubleFunction;
+
+public interface InliningPolicy {
+
+ boolean continueInlining(StructuredGraph graph);
+
+ boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed);
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolder.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2011, 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.phases.common.inlining.walker;
+
+import com.oracle.graal.api.meta.MetaUtil;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.graph.FixedNodeProbabilityCache;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.CapInheritedRelevance;
+
+/**
+ * Information about a graph that will potentially be inlined. This includes tracking the
+ * invocations in graph that will subject to inlining themselves.
+ */
+public class CallsiteHolder {
+
+ private final StructuredGraph graph;
+ private final LinkedList remainingInvokes;
+ private final double probability;
+ private final double relevance;
+
+ private final ToDoubleFunction probabilities;
+ private final ComputeInliningRelevance computeInliningRelevance;
+
+ public CallsiteHolder(StructuredGraph graph, double probability, double relevance) {
+ this.graph = graph;
+ if (graph == null) {
+ this.remainingInvokes = new LinkedList<>();
+ } else {
+ LinkedList invokes = new InliningIterator(graph).apply();
+ assert invokes.size() == count(graph.getInvokes());
+ this.remainingInvokes = invokes;
+ }
+ this.probability = probability;
+ this.relevance = relevance;
+
+ if (graph != null && !remainingInvokes.isEmpty()) {
+ probabilities = new FixedNodeProbabilityCache();
+ computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
+ computeProbabilities();
+ } else {
+ probabilities = null;
+ computeInliningRelevance = null;
+ }
+ }
+
+ private static int count(Iterable invokes) {
+ int count = 0;
+ Iterator iterator = invokes.iterator();
+ while (iterator.hasNext()) {
+ iterator.next();
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * Gets the method associated with the {@linkplain #graph() graph} represented by this object.
+ */
+ public ResolvedJavaMethod method() {
+ return graph == null ? null : graph.method();
+ }
+
+ public boolean hasRemainingInvokes() {
+ return !remainingInvokes.isEmpty();
+ }
+
+ /**
+ * The graph about which this object contains inlining information.
+ */
+ public StructuredGraph graph() {
+ return graph;
+ }
+
+ public Invoke popInvoke() {
+ return remainingInvokes.removeFirst();
+ }
+
+ public void pushInvoke(Invoke invoke) {
+ remainingInvokes.push(invoke);
+ }
+
+ public void computeProbabilities() {
+ computeInliningRelevance.compute();
+ }
+
+ public double invokeProbability(Invoke invoke) {
+ return probability * probabilities.applyAsDouble(invoke.asNode());
+ }
+
+ public double invokeRelevance(Invoke invoke) {
+ return Math.min(CapInheritedRelevance.getValue(), relevance) * computeInliningRelevance.getRelevance(invoke);
+ }
+
+ @Override
+ public String toString() {
+ return (graph != null ? MetaUtil.format("%H.%n(%p)", method()) : "") + remainingInvokes;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,324 @@
+/*
+ * 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.phases.common.inlining.walker;
+
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+import edu.umd.cs.findbugs.annotations.*;
+
+public class ComputeInliningRelevance {
+
+ private static final double EPSILON = 1d / Integer.MAX_VALUE;
+ private static final double UNINITIALIZED = -1D;
+
+ private static final int EXPECTED_MIN_INVOKE_COUNT = 3;
+ private static final int EXPECTED_INVOKE_RATIO = 20;
+ private static final int EXPECTED_LOOP_COUNT = 3;
+
+ private final StructuredGraph graph;
+ private final ToDoubleFunction nodeProbabilities;
+
+ /**
+ * Node relevances are pre-computed for all invokes if the graph contains loops. If there are no
+ * loops, the computation happens lazily based on {@link #rootScope}.
+ */
+ private Map nodeRelevances;
+ /**
+ * This scope is non-null if (and only if) there are no loops in the graph. In this case, the
+ * root scope is used to compute invoke relevances on the fly.
+ */
+ private Scope rootScope;
+
+ public ComputeInliningRelevance(StructuredGraph graph, ToDoubleFunction nodeProbabilities) {
+ this.graph = graph;
+ this.nodeProbabilities = nodeProbabilities;
+ }
+
+ /**
+ * Initializes or updates the relevance computation. If there are no loops within the graph,
+ * most computation happens lazily.
+ */
+ public void compute() {
+ rootScope = null;
+ if (!graph.hasLoops()) {
+ // fast path for the frequent case of no loops
+ rootScope = new Scope(graph.start(), null);
+ } else {
+ if (nodeRelevances == null) {
+ nodeRelevances = newNodeIdentityMap(EXPECTED_MIN_INVOKE_COUNT + graph.getNodeCount() / EXPECTED_INVOKE_RATIO);
+ }
+ NodeWorkList workList = graph.createNodeWorkList();
+ Map loops = newNodeIdentityMap(EXPECTED_LOOP_COUNT);
+
+ loops.put(null, new Scope(graph.start(), null));
+ for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.class)) {
+ createLoopScope(loopBegin, loops);
+ }
+
+ for (Scope scope : loops.values()) {
+ scope.process(workList);
+ }
+ }
+ }
+
+ public double getRelevance(Invoke invoke) {
+ if (rootScope != null) {
+ return rootScope.computeInvokeRelevance(invoke);
+ }
+ assert nodeRelevances != null : "uninitialized relevance";
+ return nodeRelevances.get(invoke);
+ }
+
+ /**
+ * Determines the parent of the given loop and creates a {@link Scope} object for each one. This
+ * method will call itself recursively if no {@link Scope} for the parent loop exists.
+ */
+ private Scope createLoopScope(LoopBeginNode loopBegin, Map loops) {
+ Scope scope = loops.get(loopBegin);
+ if (scope == null) {
+ final Scope parent;
+ // look for the parent scope
+ FixedNode current = loopBegin.forwardEnd();
+ while (true) {
+ if (current.predecessor() == null) {
+ if (current instanceof LoopBeginNode) {
+ // if we reach a LoopBeginNode then we're within this loop
+ parent = createLoopScope((LoopBeginNode) current, loops);
+ break;
+ } else if (current instanceof StartNode) {
+ // we're within the outermost scope
+ parent = loops.get(null);
+ break;
+ } else {
+ assert current.getClass() == MergeNode.class : current;
+ // follow any path upwards - it doesn't matter which one
+ current = ((MergeNode) current).forwardEndAt(0);
+ }
+ } else if (current instanceof LoopExitNode) {
+ // if we reach a loop exit then we follow this loop and have the same parent
+ parent = createLoopScope(((LoopExitNode) current).loopBegin(), loops).parent;
+ break;
+ } else {
+ current = (FixedNode) current.predecessor();
+ }
+ }
+ scope = new Scope(loopBegin, parent);
+ loops.put(loopBegin, scope);
+ }
+ return scope;
+ }
+
+ /**
+ * A scope holds information for the contents of one loop or of the root of the method. It does
+ * not include child loops, i.e., the iteration in {@link #process(NodeWorkList)} explicitly
+ * excludes the nodes of child loops.
+ */
+ private class Scope {
+ public final FixedNode start;
+ public final Scope parent; // can be null for the outermost scope
+
+ /**
+ * The minimum probability along the most probable path in this scope. Computed lazily.
+ */
+ private double fastPathMinProbability = UNINITIALIZED;
+ /**
+ * A measure of how important this scope is within its parent scope. Computed lazily.
+ */
+ private double scopeRelevanceWithinParent = UNINITIALIZED;
+
+ public Scope(FixedNode start, Scope parent) {
+ this.start = start;
+ this.parent = parent;
+ }
+
+ @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
+ public double getFastPathMinProbability() {
+ if (fastPathMinProbability == UNINITIALIZED) {
+ fastPathMinProbability = Math.max(EPSILON, computeFastPathMinProbability(start));
+ }
+ return fastPathMinProbability;
+ }
+
+ /**
+ * Computes the ratio between the probabilities of the current scope's entry point and the
+ * parent scope's fastPathMinProbability.
+ */
+ @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
+ public double getScopeRelevanceWithinParent() {
+ if (scopeRelevanceWithinParent == UNINITIALIZED) {
+ if (start instanceof LoopBeginNode) {
+ assert parent != null;
+ double scopeEntryProbability = nodeProbabilities.applyAsDouble(((LoopBeginNode) start).forwardEnd());
+
+ scopeRelevanceWithinParent = scopeEntryProbability / parent.getFastPathMinProbability();
+ } else {
+ scopeRelevanceWithinParent = 1D;
+ }
+ }
+ return scopeRelevanceWithinParent;
+ }
+
+ /**
+ * Processes all invokes in this scope by starting at the scope's start node and iterating
+ * all fixed nodes. Child loops are skipped by going from loop entries directly to the loop
+ * exits. Processing stops at loop exits of the current loop.
+ */
+ public void process(NodeWorkList workList) {
+ assert !(start instanceof Invoke);
+ workList.addAll(start.successors());
+
+ for (Node current : workList) {
+ assert current.isAlive();
+
+ if (current instanceof Invoke) {
+ // process the invoke and queue its successors
+ nodeRelevances.put((FixedNode) current, computeInvokeRelevance((Invoke) current));
+ workList.addAll(current.successors());
+ } else if (current instanceof LoopBeginNode) {
+ // skip child loops by advancing over the loop exits
+ ((LoopBeginNode) current).loopExits().forEach(exit -> workList.add(exit.next()));
+ } else if (current instanceof LoopEndNode) {
+ // nothing to do
+ } else if (current instanceof LoopExitNode) {
+ // nothing to do
+ } else if (current instanceof FixedWithNextNode) {
+ workList.add(((FixedWithNextNode) current).next());
+ } else if (current instanceof EndNode) {
+ workList.add(((EndNode) current).merge());
+ } else if (current instanceof ControlSinkNode) {
+ // nothing to do
+ } else if (current instanceof ControlSplitNode) {
+ workList.addAll(current.successors());
+ } else {
+ assert false : current;
+ }
+ }
+ }
+
+ /**
+ * The relevance of an invoke is the ratio between the invoke's probability and the current
+ * scope's fastPathMinProbability, adjusted by scopeRelevanceWithinParent.
+ */
+ public double computeInvokeRelevance(Invoke invoke) {
+ double invokeProbability = nodeProbabilities.applyAsDouble(invoke.asNode());
+ assert !Double.isNaN(invokeProbability);
+
+ double relevance = (invokeProbability / getFastPathMinProbability()) * Math.min(1.0, getScopeRelevanceWithinParent());
+ assert !Double.isNaN(relevance) : invoke + ": " + relevance + " / " + invokeProbability + " / " + getFastPathMinProbability() + " / " + getScopeRelevanceWithinParent();
+ return relevance;
+ }
+ }
+
+ /**
+ * Computes the minimum probability along the most probable path within the scope. During
+ * iteration, the method returns immediately once a loop exit is discovered.
+ */
+ private double computeFastPathMinProbability(FixedNode scopeStart) {
+ ArrayList pathBeginNodes = new ArrayList<>();
+ pathBeginNodes.add(scopeStart);
+ double minPathProbability = nodeProbabilities.applyAsDouble(scopeStart);
+ boolean isLoopScope = scopeStart instanceof LoopBeginNode;
+
+ do {
+ Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1);
+ do {
+ if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) {
+ return minPathProbability;
+ } else if (current instanceof LoopBeginNode && current != scopeStart) {
+ current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes);
+ minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+ } else if (current instanceof ControlSplitNode) {
+ current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes);
+ minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+ } else {
+ assert current.successors().count() <= 1;
+ current = current.successors().first();
+ }
+ } while (current != null);
+ } while (!pathBeginNodes.isEmpty());
+
+ return minPathProbability;
+ }
+
+ private double getMinPathProbability(FixedNode current, double minPathProbability) {
+ return current == null ? minPathProbability : Math.min(minPathProbability, nodeProbabilities.applyAsDouble(current));
+ }
+
+ /**
+ * Returns the most probable successor. If multiple successors share the maximum probability,
+ * one is returned and the others are enqueued in pathBeginNodes.
+ */
+ private static Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList pathBeginNodes) {
+ Node maxSux = null;
+ double maxProbability = 0.0;
+ int pathBeginCount = pathBeginNodes.size();
+
+ for (Node sux : controlSplit.successors()) {
+ double probability = controlSplit.probability((BeginNode) sux);
+ if (probability > maxProbability) {
+ maxProbability = probability;
+ maxSux = sux;
+ truncate(pathBeginNodes, pathBeginCount);
+ } else if (probability == maxProbability) {
+ pathBeginNodes.add((FixedNode) sux);
+ }
+ }
+
+ return maxSux;
+ }
+
+ /**
+ * Returns the most probable loop exit. If multiple successors share the maximum probability,
+ * one is returned and the others are enqueued in pathBeginNodes.
+ */
+ private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList pathBeginNodes) {
+ Node maxSux = null;
+ double maxProbability = 0.0;
+ int pathBeginCount = pathBeginNodes.size();
+
+ for (LoopExitNode sux : loopBegin.loopExits()) {
+ double probability = nodeProbabilities.applyAsDouble(sux);
+ if (probability > maxProbability) {
+ maxProbability = probability;
+ maxSux = sux;
+ truncate(pathBeginNodes, pathBeginCount);
+ } else if (probability == maxProbability) {
+ pathBeginNodes.add(sux);
+ }
+ }
+
+ return maxSux;
+ }
+
+ private static void truncate(ArrayList pathBeginNodes, int pathBeginCount) {
+ for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) {
+ pathBeginNodes.remove(pathBeginNodes.size() - 1);
+ }
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2011, 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.phases.common.inlining.walker;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.code.BailoutException;
+import com.oracle.graal.api.meta.JavaTypeProfile;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.compiler.common.GraalInternalError;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Graph;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.phases.OptimisticOptimizations;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.*;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
+import com.oracle.graal.phases.common.inlining.policy.InliningPolicy;
+import com.oracle.graal.phases.graph.FixedNodeProbabilityCache;
+import com.oracle.graal.phases.tiers.HighTierContext;
+import com.oracle.graal.phases.util.Providers;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+/**
+ * Holds the data for building the callee graphs recursively: graphs and invocations (each
+ * invocation can have multiple graphs).
+ */
+public class InliningData {
+
+ private static final CallsiteHolder DUMMY_CALLSITE_HOLDER = new CallsiteHolder(null, 1.0, 1.0);
+ // Metrics
+ private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
+ private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
+ private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
+
+ /**
+ * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
+ */
+ private final ArrayDeque graphQueue = new ArrayDeque<>();
+ private final ArrayDeque invocationQueue = new ArrayDeque<>();
+ private final ToDoubleFunction probabilities = new FixedNodeProbabilityCache();
+
+ private final HighTierContext context;
+ private final int maxMethodPerInlining;
+ private final CanonicalizerPhase canonicalizer;
+ private final InliningPolicy inliningPolicy;
+
+ private int maxGraphs;
+
+ public InliningData(StructuredGraph rootGraph, HighTierContext context, int maxMethodPerInlining, CanonicalizerPhase canonicalizer, InliningPolicy inliningPolicy) {
+ assert rootGraph != null;
+ this.context = context;
+ this.maxMethodPerInlining = maxMethodPerInlining;
+ this.canonicalizer = canonicalizer;
+ this.inliningPolicy = inliningPolicy;
+ this.maxGraphs = 1;
+
+ Assumptions rootAssumptions = context.getAssumptions();
+ invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
+ pushGraph(rootGraph, 1.0, 1.0);
+ }
+
+ private String checkTargetConditionsHelper(ResolvedJavaMethod method) {
+ if (method == null) {
+ return "the method is not resolved";
+ } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(context.getReplacements(), method))) {
+ return "it is a non-intrinsic native method";
+ } else if (method.isAbstract()) {
+ return "it is an abstract method";
+ } else if (!method.getDeclaringClass().isInitialized()) {
+ return "the method's class is not initialized";
+ } else if (!method.canBeInlined()) {
+ return "it is marked non-inlinable";
+ } else if (countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) {
+ return "it exceeds the maximum recursive inlining depth";
+ } else if (new OptimisticOptimizations(method.getProfilingInfo()).lessOptimisticThan(context.getOptimisticOptimizations())) {
+ return "the callee uses less optimistic optimizations than caller";
+ } else {
+ return null;
+ }
+ }
+
+ private boolean checkTargetConditions(Invoke invoke, ResolvedJavaMethod method) {
+ final String failureMessage = checkTargetConditionsHelper(method);
+ if (failureMessage == null) {
+ return true;
+ } else {
+ InliningUtil.logNotInlined(invoke, inliningDepth(), method, failureMessage);
+ return false;
+ }
+ }
+
+ /**
+ * Determines if inlining is possible at the given invoke node.
+ *
+ * @param invoke the invoke that should be inlined
+ * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
+ */
+ private InlineInfo getInlineInfo(Invoke invoke, Assumptions assumptions) {
+ final String failureMessage = InliningUtil.checkInvokeConditions(invoke);
+ if (failureMessage != null) {
+ InliningUtil.logNotInlinedMethod(invoke, failureMessage);
+ return null;
+ }
+ MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+ ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+
+ if (callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
+ return getExactInlineInfo(invoke, targetMethod);
+ }
+
+ assert callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Virtual || callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Interface;
+
+ ResolvedJavaType holder = targetMethod.getDeclaringClass();
+ if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) {
+ return null;
+ }
+ ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp();
+ if (receiverStamp.alwaysNull()) {
+ // Don't inline if receiver is known to be null
+ return null;
+ }
+ ResolvedJavaType contextType = invoke.getContextType();
+ if (receiverStamp.type() != null) {
+ // the invoke target might be more specific than the holder (happens after inlining:
+ // parameters lose their declared type...)
+ ResolvedJavaType receiverType = receiverStamp.type();
+ if (receiverType != null && holder.isAssignableFrom(receiverType)) {
+ holder = receiverType;
+ if (receiverStamp.isExactType()) {
+ assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
+ ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod, contextType);
+ if (resolvedMethod != null) {
+ return getExactInlineInfo(invoke, resolvedMethod);
+ }
+ }
+ }
+ }
+
+ if (holder.isArray()) {
+ // arrays can be treated as Objects
+ ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod, contextType);
+ if (resolvedMethod != null) {
+ return getExactInlineInfo(invoke, resolvedMethod);
+ }
+ }
+
+ if (assumptions.useOptimisticAssumptions()) {
+ ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
+ if (uniqueSubtype != null) {
+ ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveMethod(targetMethod, contextType);
+ if (resolvedMethod != null) {
+ return getAssumptionInlineInfo(invoke, resolvedMethod, new Assumptions.ConcreteSubtype(holder, uniqueSubtype));
+ }
+ }
+
+ ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
+ if (concrete != null) {
+ return getAssumptionInlineInfo(invoke, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete));
+ }
+ }
+
+ // type check based inlining
+ return getTypeCheckedInlineInfo(invoke, targetMethod);
+ }
+
+ private InlineInfo getTypeCheckedInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) {
+ JavaTypeProfile typeProfile;
+ ValueNode receiver = invoke.callTarget().arguments().get(0);
+ if (receiver instanceof TypeProfileProxyNode) {
+ TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver;
+ typeProfile = typeProfileProxyNode.getProfile();
+ } else {
+ InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no type profile exists");
+ return null;
+ }
+
+ JavaTypeProfile.ProfiledType[] ptypes = typeProfile.getTypes();
+ if (ptypes == null || ptypes.length <= 0) {
+ InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no types in profile");
+ return null;
+ }
+ ResolvedJavaType contextType = invoke.getContextType();
+ double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
+ final OptimisticOptimizations optimisticOpts = context.getOptimisticOptimizations();
+ if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
+ if (!optimisticOpts.inlineMonomorphicCalls()) {
+ InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
+ return null;
+ }
+
+ ResolvedJavaType type = ptypes[0].getType();
+ assert type.isArray() || !type.isAbstract();
+ ResolvedJavaMethod concrete = type.resolveMethod(targetMethod, contextType);
+ if (!checkTargetConditions(invoke, concrete)) {
+ return null;
+ }
+ return new TypeGuardInlineInfo(invoke, concrete, type);
+ } else {
+ invoke.setPolymorphic(true);
+
+ if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
+ InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
+ return null;
+ }
+ if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
+ // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
+ // the number of types is lower than what can be recorded in a type profile
+ InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
+ notRecordedTypeProbability * 100);
+ return null;
+ }
+
+ // Find unique methods and their probabilities.
+ ArrayList concreteMethods = new ArrayList<>();
+ ArrayList concreteMethodsProbabilities = new ArrayList<>();
+ for (int i = 0; i < ptypes.length; i++) {
+ ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod, contextType);
+ if (concrete == null) {
+ InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "could not resolve method");
+ return null;
+ }
+ int index = concreteMethods.indexOf(concrete);
+ double curProbability = ptypes[i].getProbability();
+ if (index < 0) {
+ index = concreteMethods.size();
+ concreteMethods.add(concrete);
+ concreteMethodsProbabilities.add(curProbability);
+ } else {
+ concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability);
+ }
+ }
+
+ if (concreteMethods.size() > maxMethodPerInlining) {
+ InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining);
+ return null;
+ }
+
+ // Clear methods that fall below the threshold.
+ if (notRecordedTypeProbability > 0) {
+ ArrayList newConcreteMethods = new ArrayList<>();
+ ArrayList newConcreteMethodsProbabilities = new ArrayList<>();
+ for (int i = 0; i < concreteMethods.size(); ++i) {
+ if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue()) {
+ newConcreteMethods.add(concreteMethods.get(i));
+ newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
+ }
+ }
+
+ if (newConcreteMethods.size() == 0) {
+ // No method left that is worth inlining.
+ InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
+ concreteMethods.size());
+ return null;
+ }
+
+ concreteMethods = newConcreteMethods;
+ concreteMethodsProbabilities = newConcreteMethodsProbabilities;
+ }
+
+ // Clean out types whose methods are no longer available.
+ ArrayList usedTypes = new ArrayList<>();
+ ArrayList typesToConcretes = new ArrayList<>();
+ for (JavaTypeProfile.ProfiledType type : ptypes) {
+ ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod, contextType);
+ int index = concreteMethods.indexOf(concrete);
+ if (index == -1) {
+ notRecordedTypeProbability += type.getProbability();
+ } else {
+ assert type.getType().isArray() || !type.getType().isAbstract() : type + " " + concrete;
+ usedTypes.add(type);
+ typesToConcretes.add(index);
+ }
+ }
+
+ if (usedTypes.size() == 0) {
+ // No type left that is worth checking for.
+ InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
+ return null;
+ }
+
+ for (ResolvedJavaMethod concrete : concreteMethods) {
+ if (!checkTargetConditions(invoke, concrete)) {
+ InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
+ return null;
+ }
+ }
+ return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability);
+ }
+ }
+
+ private InlineInfo getAssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumptions.Assumption takenAssumption) {
+ assert !concrete.isAbstract();
+ if (!checkTargetConditions(invoke, concrete)) {
+ return null;
+ }
+ return new AssumptionInlineInfo(invoke, concrete, takenAssumption);
+ }
+
+ private InlineInfo getExactInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) {
+ assert !targetMethod.isAbstract();
+ if (!checkTargetConditions(invoke, targetMethod)) {
+ return null;
+ }
+ return new ExactInlineInfo(invoke, targetMethod);
+ }
+
+ private void doInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInvocation, Assumptions callerAssumptions) {
+ StructuredGraph callerGraph = callerCallsiteHolder.graph();
+ Graph.Mark markBeforeInlining = callerGraph.getMark();
+ InlineInfo calleeInfo = calleeInvocation.callee();
+ try {
+ try (Debug.Scope scope = Debug.scope("doInline", callerGraph)) {
+ List invokeUsages = calleeInfo.invoke().asNode().usages().snapshot();
+ calleeInfo.inline(new Providers(context), callerAssumptions);
+ callerAssumptions.record(calleeInvocation.assumptions());
+ metricInliningRuns.increment();
+ Debug.dump(callerGraph, "after %s", calleeInfo);
+
+ if (OptCanonicalizer.getValue()) {
+ Graph.Mark markBeforeCanonicalization = callerGraph.getMark();
+ canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
+
+ // process invokes that are possibly created during canonicalization
+ for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
+ if (newNode instanceof Invoke) {
+ callerCallsiteHolder.pushInvoke((Invoke) newNode);
+ }
+ }
+ }
+
+ callerCallsiteHolder.computeProbabilities();
+
+ metricInliningPerformed.increment();
+ }
+ } catch (BailoutException bailout) {
+ throw bailout;
+ } catch (AssertionError | RuntimeException e) {
+ throw new GraalInternalError(e).addContext(calleeInfo.toString());
+ } catch (GraalInternalError e) {
+ throw e.addContext(calleeInfo.toString());
+ }
+ }
+
+ /**
+ * @return true iff inlining was actually performed
+ */
+ private boolean tryToInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInvocation, MethodInvocation parentInvocation, int inliningDepth) {
+ InlineInfo calleeInfo = calleeInvocation.callee();
+ Assumptions callerAssumptions = parentInvocation.assumptions();
+ metricInliningConsidered.increment();
+
+ if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), calleeInfo, inliningDepth, calleeInvocation.probability(), calleeInvocation.relevance(), true)) {
+ doInline(callerCallsiteHolder, calleeInvocation, callerAssumptions);
+ return true;
+ }
+
+ if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
+ calleeInfo.tryToDevirtualizeInvoke(context.getMetaAccess(), callerAssumptions);
+ }
+
+ return false;
+ }
+
+ /**
+ * Process the next invoke and enqueue all its graphs for processing.
+ */
+ private void processNextInvoke() {
+ CallsiteHolder callsiteHolder = currentGraph();
+ Invoke invoke = callsiteHolder.popInvoke();
+ MethodInvocation callerInvocation = currentInvocation();
+ Assumptions parentAssumptions = callerInvocation.assumptions();
+ Assumptions calleeAssumptions = new Assumptions(parentAssumptions.useOptimisticAssumptions());
+ InlineInfo info = populateInlineInfo(invoke, parentAssumptions, calleeAssumptions);
+
+ if (info != null) {
+ double invokeProbability = callsiteHolder.invokeProbability(invoke);
+ double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
+ MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance);
+ pushInvocation(methodInvocation);
+
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ Inlineable elem = info.inlineableElementAt(i);
+ if (elem instanceof InlineableGraph) {
+ pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
+ } else {
+ assert elem instanceof InlineableMacroNode;
+ pushDummyGraph();
+ }
+ }
+ }
+ }
+
+ private InlineInfo populateInlineInfo(Invoke invoke, Assumptions parentAssumptions, Assumptions calleeAssumptions) {
+ InlineInfo info = getInlineInfo(invoke, parentAssumptions);
+ if (info == null) {
+ return null;
+ }
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ Inlineable elem = Inlineable.getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeAssumptions), canonicalizer);
+ info.setInlinableElement(i, elem);
+ }
+ return info;
+ }
+
+ public int graphCount() {
+ return graphQueue.size();
+ }
+
+ private void pushGraph(StructuredGraph graph, double probability, double relevance) {
+ assert graph != null;
+ assert !contains(graph);
+ graphQueue.push(new CallsiteHolder(graph, probability, relevance));
+ assert graphQueue.size() <= maxGraphs;
+ }
+
+ private void pushDummyGraph() {
+ graphQueue.push(DUMMY_CALLSITE_HOLDER);
+ }
+
+ public boolean hasUnprocessedGraphs() {
+ return !graphQueue.isEmpty();
+ }
+
+ private CallsiteHolder currentGraph() {
+ return graphQueue.peek();
+ }
+
+ private void popGraph() {
+ graphQueue.pop();
+ assert graphQueue.size() <= maxGraphs;
+ }
+
+ private void popGraphs(int count) {
+ assert count >= 0;
+ for (int i = 0; i < count; i++) {
+ graphQueue.pop();
+ }
+ }
+
+ private static final Object[] NO_CONTEXT = {};
+
+ /**
+ * Gets the call hierarchy of this inlining from outer most call to inner most callee.
+ */
+ private Object[] inliningContext() {
+ if (!Debug.isDumpEnabled()) {
+ return NO_CONTEXT;
+ }
+ Object[] result = new Object[graphQueue.size()];
+ int i = 0;
+ for (CallsiteHolder g : graphQueue) {
+ result[i++] = g.method();
+ }
+ return result;
+ }
+
+ private MethodInvocation currentInvocation() {
+ return invocationQueue.peekFirst();
+ }
+
+ private void pushInvocation(MethodInvocation methodInvocation) {
+ invocationQueue.addFirst(methodInvocation);
+ maxGraphs += methodInvocation.callee().numberOfMethods();
+ assert graphQueue.size() <= maxGraphs;
+ }
+
+ private void popInvocation() {
+ maxGraphs -= invocationQueue.peekFirst().callee().numberOfMethods();
+ assert graphQueue.size() <= maxGraphs;
+ invocationQueue.removeFirst();
+ }
+
+ public int countRecursiveInlining(ResolvedJavaMethod method) {
+ int count = 0;
+ for (CallsiteHolder callsiteHolder : graphQueue) {
+ if (method.equals(callsiteHolder.method())) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ public int inliningDepth() {
+ assert invocationQueue.size() > 0;
+ return invocationQueue.size() - 1;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder("Invocations: ");
+
+ for (MethodInvocation invocation : invocationQueue) {
+ if (invocation.callee() != null) {
+ result.append(invocation.callee().numberOfMethods());
+ result.append("x ");
+ result.append(invocation.callee().invoke());
+ result.append("; ");
+ }
+ }
+
+ result.append("\nGraphs: ");
+ for (CallsiteHolder graph : graphQueue) {
+ result.append(graph.graph());
+ result.append("; ");
+ }
+
+ return result.toString();
+ }
+
+ private boolean contains(StructuredGraph graph) {
+ for (CallsiteHolder info : graphQueue) {
+ if (info.graph() == graph) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return true iff inlining was actually performed
+ */
+ public boolean moveForward() {
+
+ final MethodInvocation currentInvocation = currentInvocation();
+
+ final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation.callee(), inliningDepth(),
+ currentInvocation.probability(), currentInvocation.relevance(), false));
+ if (backtrack) {
+ int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
+ assert remainingGraphs > 0;
+ popGraphs(remainingGraphs);
+ popInvocation();
+ return false;
+ }
+
+ final boolean delve = currentGraph().hasRemainingInvokes() && inliningPolicy.continueInlining(currentGraph().graph());
+ if (delve) {
+ processNextInvoke();
+ return false;
+ }
+
+ popGraph();
+ if (currentInvocation.isRoot()) {
+ return false;
+ }
+
+ // try to inline
+ assert currentInvocation.callee().invoke().asNode().isAlive();
+ currentInvocation.incrementProcessedGraphs();
+ if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
+ popInvocation();
+ final MethodInvocation parentInvoke = currentInvocation();
+ try (Debug.Scope s = Debug.scope("Inlining", inliningContext())) {
+ return tryToInline(currentGraph(), currentInvocation, parentInvoke, inliningDepth() + 1);
+ } catch (Throwable e) {
+ throw Debug.handle(e);
+ }
+ }
+
+ return false;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningIterator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningIterator.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2011, 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.phases.common.inlining.walker;
+
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeBitMap;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.LinkedList;
+
+/**
+ * Given a graph, visit all fixed nodes in dominator-based order, collecting in the process the
+ * {@link Invoke} nodes with {@link MethodCallTargetNode}. Such list of callsites is returned by
+ * {@link #apply()}
+ */
+public class InliningIterator {
+
+ private final StartNode start;
+ private final Deque nodeQueue;
+ private final NodeBitMap queuedNodes;
+
+ public InliningIterator(StructuredGraph graph) {
+ this.start = graph.start();
+ this.nodeQueue = new ArrayDeque<>();
+ this.queuedNodes = graph.createNodeBitMap();
+ assert start.isAlive();
+ }
+
+ public LinkedList apply() {
+ LinkedList invokes = new LinkedList<>();
+ FixedNode current;
+ forcedQueue(start);
+
+ while ((current = nextQueuedNode()) != null) {
+ assert current.isAlive();
+
+ if (current instanceof Invoke && ((Invoke) current).callTarget() instanceof MethodCallTargetNode) {
+ if (current != start) {
+ invokes.addLast((Invoke) current);
+ }
+ queueSuccessors(current);
+ } else if (current instanceof LoopBeginNode) {
+ queueSuccessors(current);
+ } else if (current instanceof LoopEndNode) {
+ // nothing to do
+ } else if (current instanceof MergeNode) {
+ queueSuccessors(current);
+ } else if (current instanceof FixedWithNextNode) {
+ queueSuccessors(current);
+ } else if (current instanceof EndNode) {
+ queueMerge((EndNode) current);
+ } else if (current instanceof ControlSinkNode) {
+ // nothing to do
+ } else if (current instanceof ControlSplitNode) {
+ queueSuccessors(current);
+ } else {
+ assert false : current;
+ }
+ }
+
+ return invokes;
+ }
+
+ private void queueSuccessors(FixedNode x) {
+ for (Node node : x.successors()) {
+ queue(node);
+ }
+ }
+
+ private void queue(Node node) {
+ if (node != null && !queuedNodes.isMarked(node)) {
+ forcedQueue(node);
+ }
+ }
+
+ private void forcedQueue(Node node) {
+ queuedNodes.mark(node);
+ nodeQueue.addFirst((FixedNode) node);
+ }
+
+ private FixedNode nextQueuedNode() {
+ if (nodeQueue.isEmpty()) {
+ return null;
+ }
+
+ FixedNode result = nodeQueue.removeFirst();
+ assert queuedNodes.isMarked(result);
+ return result;
+ }
+
+ private void queueMerge(AbstractEndNode end) {
+ MergeNode merge = end.merge();
+ if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
+ queuedNodes.mark(merge);
+ nodeQueue.add(merge);
+ }
+ }
+
+ private boolean visitedAllEnds(MergeNode merge) {
+ for (int i = 0; i < merge.forwardEndCount(); i++) {
+ if (!queuedNodes.isMarked(merge.forwardEndAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2011, 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.phases.common.inlining.walker;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.MetaUtil;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.CallTargetNode;
+import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+
+public class MethodInvocation {
+
+ private final InlineInfo callee;
+ private final Assumptions assumptions;
+ private final double probability;
+ private final double relevance;
+
+ private int processedGraphs;
+
+ public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
+ this.callee = info;
+ this.assumptions = assumptions;
+ this.probability = probability;
+ this.relevance = relevance;
+ }
+
+ public void incrementProcessedGraphs() {
+ processedGraphs++;
+ assert processedGraphs <= callee.numberOfMethods();
+ }
+
+ public int processedGraphs() {
+ assert processedGraphs <= callee.numberOfMethods();
+ return processedGraphs;
+ }
+
+ public int totalGraphs() {
+ return callee.numberOfMethods();
+ }
+
+ public InlineInfo callee() {
+ return callee;
+ }
+
+ public Assumptions assumptions() {
+ return assumptions;
+ }
+
+ public double probability() {
+ return probability;
+ }
+
+ public double relevance() {
+ return relevance;
+ }
+
+ public boolean isRoot() {
+ return callee == null;
+ }
+
+ @Override
+ public String toString() {
+ if (isRoot()) {
+ return "";
+ }
+ CallTargetNode callTarget = callee.invoke().callTarget();
+ if (callTarget instanceof MethodCallTargetNode) {
+ ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
+ return MetaUtil.format("Invoke#%H.%n(%p)", calleeMethod);
+ } else {
+ return "Invoke#" + callTarget.targetName();
+ }
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Wed May 21 11:45:50 2014 +0200
@@ -28,6 +28,7 @@
import com.oracle.graal.debug.Debug.Scope;
import com.oracle.graal.debug.DebugMemUseTracker.Closeable;
import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
/**
@@ -39,9 +40,26 @@
private CharSequence name;
- private final DebugTimer phaseTimer;
- private final DebugMetric phaseMetric;
- private final DebugMemUseTracker phaseMemUseTracker;
+ /**
+ * Records time spent in {@link #apply(StructuredGraph, Object, boolean)}.
+ */
+ private final DebugTimer timer;
+
+ /**
+ * Counts calls to {@link #apply(StructuredGraph, Object, boolean)}.
+ */
+ private final DebugMetric executionCount;
+
+ /**
+ * Accumulates the {@linkplain Graph#getNodeCount() live node count} of all graphs sent to
+ * {@link #apply(StructuredGraph, Object, boolean)}.
+ */
+ private final DebugMetric inputNodesCount;
+
+ /**
+ * Records memory usage within {@link #apply(StructuredGraph, Object, boolean)}.
+ */
+ private final DebugMemUseTracker memUseTracker;
private static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
@@ -51,17 +69,19 @@
}
protected BasePhase() {
- phaseTimer = Debug.timer("PhaseTime_%s", getClass());
- phaseMetric = Debug.metric("PhaseCount_%s", getClass());
- phaseMemUseTracker = Debug.memUseTracker("PhaseMemUse_%s", getClass());
+ timer = Debug.timer("PhaseTime_%s", getClass());
+ executionCount = Debug.metric("PhaseCount_%s", getClass());
+ memUseTracker = Debug.memUseTracker("PhaseMemUse_%s", getClass());
+ inputNodesCount = Debug.metric("PhaseNodes_%s", getClass());
}
protected BasePhase(String name) {
assert checkName(name);
this.name = name;
- phaseTimer = Debug.timer("PhaseTime_%s", getClass());
- phaseMetric = Debug.metric("PhaseCount_%s", getClass());
- phaseMemUseTracker = Debug.memUseTracker("PhaseMemUse_%s", getClass());
+ timer = Debug.timer("PhaseTime_%s", getClass());
+ executionCount = Debug.metric("PhaseCount_%s", getClass());
+ memUseTracker = Debug.memUseTracker("PhaseMemUse_%s", getClass());
+ inputNodesCount = Debug.metric("PhaseNodes_%s", getClass());
}
protected CharSequence getDetailedName() {
@@ -73,9 +93,10 @@
}
public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) {
- try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(getClass(), this); Closeable c = phaseMemUseTracker.start()) {
+ try (TimerCloseable a = timer.start(); Scope s = Debug.scope(getClass(), this); Closeable c = memUseTracker.start()) {
BasePhase.this.run(graph, context);
- phaseMetric.increment();
+ executionCount.increment();
+ inputNodesCount.add(graph.getNodeCount());
if (dumpGraph && Debug.isDumpEnabled()) {
Debug.dump(graph, "After phase %s", getName());
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/SinglePassNodeIterator.java
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/SinglePassNodeIterator.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/SinglePassNodeIterator.java Wed May 21 11:45:50 2014 +0200
@@ -58,9 +58,9 @@
private final NodeBitMap visitedEnds;
/**
- * @see SinglePassNodeIterator.QElem
+ * @see SinglePassNodeIterator.PathStart
*/
- private final Deque> nodeQueue;
+ private final Deque> nodeQueue;
/**
* The keys in this map may be:
@@ -104,23 +104,32 @@
*
* - a {@link MergeNode} whose pre-state results from merging those of its forward-ends, see
* {@link #nextQueuedNode()}
- * - the successor of a control-split node, in which case the pre-state of the successor in
- * question is also stored in the item, see {@link #nextQueuedNode()}
+ * - a successor of a control-split node, in which case the state on entry to it (the
+ * successor) is also stored in the item, see {@link #nextQueuedNode()}
*
*
*/
- private static class QElem {
- private final FixedNode node;
- private final U preState;
+ private static class PathStart {
+ private final BeginNode node;
+ private final U stateOnEntry;
- private QElem(FixedNode node, U preState) {
+ private PathStart(BeginNode node, U stateOnEntry) {
this.node = node;
- this.preState = preState;
+ this.stateOnEntry = stateOnEntry;
assert repOK();
}
+ /**
+ * @return true iff this instance is internally consistent (ie, its "representation is OK")
+ */
private boolean repOK() {
- return (node instanceof MergeNode && preState == null) || (node instanceof BeginNode && preState != null);
+ if (node == null) {
+ return false;
+ }
+ if (node instanceof MergeNode) {
+ return stateOnEntry == null;
+ }
+ return (stateOnEntry != null);
}
}
@@ -188,11 +197,29 @@
finished();
}
+ /**
+ * Two methods enqueue items in {@link #nodeQueue}. Of them, only this method enqueues items
+ * with non-null state (the other method being {@link #queueMerge(EndNode)}).
+ *
+ *
+ * A space optimization is made: the state is cloned for all successors except the first. Given
+ * that right after invoking this method, {@link #nextQueuedNode()} is invoked, that single
+ * non-cloned state instance is in effect "handed over" to its next owner (thus realizing an
+ * owner-is-mutator access protocol).
+ *
+ */
private void queueSuccessors(FixedNode x) {
- for (Node node : x.successors()) {
- if (node != null) {
- nodeQueue.addFirst(new QElem<>((BeginNode) node, state));
- }
+ Iterator iter = x.successors().nonNull().iterator();
+ if (iter.hasNext()) {
+ BeginNode begin = (BeginNode) iter.next();
+ // the current state isn't cloned for the first successor
+ // conceptually, the state is handed over to it
+ nodeQueue.addFirst(new PathStart<>(begin, state));
+ }
+ while (iter.hasNext()) {
+ BeginNode begin = (BeginNode) iter.next();
+ // for all other successors it is cloned
+ nodeQueue.addFirst(new PathStart<>(begin, state.clone()));
}
}
@@ -210,10 +237,10 @@
if (nodeQueue.isEmpty()) {
return null;
}
- QElem elem = nodeQueue.removeFirst();
+ PathStart elem = nodeQueue.removeFirst();
if (elem.node instanceof MergeNode) {
MergeNode merge = (MergeNode) elem.node;
- state = pruneEntry(merge.forwardEndAt(0)).clone();
+ state = pruneEntry(merge.forwardEndAt(0));
ArrayList states = new ArrayList<>(merge.forwardEndCount() - 1);
for (int i = 1; i < merge.forwardEndCount(); i++) {
T other = pruneEntry(merge.forwardEndAt(i));
@@ -223,9 +250,9 @@
assert ready : "Not a single-pass iterator after all";
return merge;
} else {
- BeginNode begin = (BeginNode) elem.node;
+ BeginNode begin = elem.node;
assert begin.predecessor() != null;
- state = elem.preState.clone();
+ state = elem.stateOnEntry;
state.afterSplit(begin);
return begin;
}
@@ -292,7 +319,7 @@
}
}
if (endsVisited) {
- nodeQueue.add(new QElem<>(merge, null));
+ nodeQueue.add(new PathStart<>(merge, null));
}
}
@@ -338,6 +365,7 @@
private void keepForLater(FixedNode x, T s) {
assert !nodeStates.containsKey(x);
assert (x instanceof LoopBeginNode) || (x instanceof LoopEndNode) || (x instanceof EndNode);
+ assert s != null;
nodeStates.put(x, s);
}
diff -r a43ff5d18350 -r a6eeb3750238 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 Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Wed May 21 11:45:50 2014 +0200
@@ -235,18 +235,17 @@
if (!foundExcludeNode && node == excludeNode) {
foundExcludeNode = true;
}
- if (node == startNode) {
- continue;
+ if (node != startNode) {
+ if (node instanceof MemoryCheckpoint.Single) {
+ LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+ accm.add(identity);
+ } else if (node instanceof MemoryCheckpoint.Multi) {
+ for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+ accm.add(identity);
+ }
+ }
+ assert MemoryCheckpoint.TypeAssertion.correctType(node);
}
- if (node instanceof MemoryCheckpoint.Single) {
- LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
- accm.add(identity);
- } else if (node instanceof MemoryCheckpoint.Multi) {
- for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
- accm.add(identity);
- }
- }
- assert MemoryCheckpoint.TypeAssertion.correctType(node);
if (foundExcludeNode) {
accm = set;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Wed May 21 11:45:50 2014 +0200
@@ -224,7 +224,8 @@
if (pendingStateAfter != null) {
pendingStateAfter.applyToNonVirtual(new NodeClosure() {
public void apply(Node usage, Node nonVirtualNode) {
- assert currentState.isMarked(nonVirtualNode) : nonVirtualNode + " not available at virtualstate " + usage + " at end of block " + block + " \n" + list;
+ assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode : nonVirtualNode + " not available at virtualstate " + usage +
+ " at end of block " + block + " \n" + list;
}
});
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Wed May 21 11:45:50 2014 +0200
@@ -79,9 +79,9 @@
Object arg1 = args1[i];
Object arg2 = args2[i];
// Verify that the original method and the substitution produce the same value
- assertEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2));
+ assertDeepEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2));
// Verify that the generated code and the original produce the same value
- assertEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2));
+ assertDeepEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2));
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java Wed May 21 11:45:50 2014 +0200
@@ -32,10 +32,10 @@
public class NewArrayTest extends GraalCompilerTest {
@Override
- protected void assertEquals(Object expected, Object actual) {
+ protected void assertDeepEquals(Object expected, Object actual) {
Assert.assertTrue(expected != null);
Assert.assertTrue(actual != null);
- super.assertEquals(expected.getClass(), actual.getClass());
+ super.assertDeepEquals(expected.getClass(), actual.getClass());
if (expected instanceof int[]) {
Assert.assertArrayEquals((int[]) expected, (int[]) actual);
} else if (expected instanceof byte[]) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java Wed May 21 11:45:50 2014 +0200
@@ -34,10 +34,10 @@
public class NewInstanceTest extends GraalCompilerTest {
@Override
- protected void assertEquals(Object expected, Object actual) {
+ protected void assertDeepEquals(Object expected, Object actual) {
Assert.assertTrue(expected != null);
Assert.assertTrue(actual != null);
- super.assertEquals(expected.getClass(), actual.getClass());
+ super.assertDeepEquals(expected.getClass(), actual.getClass());
if (expected instanceof Object[]) {
Assert.assertTrue(actual instanceof Object[]);
@@ -45,12 +45,12 @@
Object[] aArr = (Object[]) actual;
Assert.assertTrue(eArr.length == aArr.length);
for (int i = 0; i < eArr.length; i++) {
- assertEquals(eArr[i], aArr[i]);
+ assertDeepEquals(eArr[i], aArr[i]);
}
} else if (expected.getClass() != Object.class) {
try {
expected.getClass().getDeclaredMethod("equals", Object.class);
- super.assertEquals(expected, actual);
+ super.assertDeepEquals(expected, actual);
} catch (Exception e) {
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Wed May 21 11:45:50 2014 +0200
@@ -44,12 +44,12 @@
test("math");
double value = 34567.891D;
- assertEquals(Math.sqrt(value), MathSubstitutionsX86.sqrt(value));
- assertEquals(Math.log(value), MathSubstitutionsX86.log(value));
- assertEquals(Math.log10(value), MathSubstitutionsX86.log10(value));
- assertEquals(Math.sin(value), MathSubstitutionsX86.sin(value));
- assertEquals(Math.cos(value), MathSubstitutionsX86.cos(value));
- assertEquals(Math.tan(value), MathSubstitutionsX86.tan(value));
+ assertDeepEquals(Math.sqrt(value), MathSubstitutionsX86.sqrt(value));
+ assertDeepEquals(Math.log(value), MathSubstitutionsX86.log(value));
+ assertDeepEquals(Math.log10(value), MathSubstitutionsX86.log10(value));
+ assertDeepEquals(Math.sin(value), MathSubstitutionsX86.sin(value));
+ assertDeepEquals(Math.cos(value), MathSubstitutionsX86.cos(value));
+ assertDeepEquals(Math.tan(value), MathSubstitutionsX86.tan(value));
}
@SuppressWarnings("all")
@@ -98,9 +98,9 @@
assert optional || code != null;
for (Object l : args) {
// Verify that the original method and the substitution produce the same value
- assertEquals(invokeSafe(testMethod, l), invokeSafe(realMethod, l));
+ assertDeepEquals(invokeSafe(testMethod, l), invokeSafe(realMethod, l));
// Verify that the generated code and the original produce the same value
- assertEquals(executeVarargsSafe(code, l), invokeSafe(realMethod, l));
+ assertDeepEquals(executeVarargsSafe(code, l), invokeSafe(realMethod, l));
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java Wed May 21 11:45:50 2014 +0200
@@ -73,9 +73,9 @@
Object arg1 = args1[i];
Object arg2 = args2[i];
// Verify that the original method and the substitution produce the same value
- assertEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, arg1, arg2));
+ assertDeepEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, arg1, arg2));
// Verify that the generated code and the original produce the same value
- assertEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, arg1, arg2));
+ assertDeepEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, arg1, arg2));
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java Wed May 21 11:45:50 2014 +0200
@@ -69,14 +69,14 @@
{
Object expected = invokeSafe(originalMethod, receiver, args1);
Object actual = invokeSafe(testMethod, null, args2);
- assertEquals(expected, actual);
+ assertDeepEquals(expected, actual);
}
// Verify that the generated code and the original produce the same value
{
Object expected = invokeSafe(originalMethod, receiver, args1);
Object actual = executeVarargsSafe(code, args2);
- assertEquals(expected, actual);
+ assertDeepEquals(expected, actual);
}
}
@@ -201,18 +201,18 @@
AtomicInteger a1 = new AtomicInteger(42);
AtomicInteger a2 = new AtomicInteger(42);
- assertEquals(unsafe.compareAndSwapInt(a1, off(a1, "value"), 42, 53), compareAndSwapInt(unsafe, a2, off(a2, "value"), 42, 53));
- assertEquals(a1.get(), a2.get());
+ assertDeepEquals(unsafe.compareAndSwapInt(a1, off(a1, "value"), 42, 53), compareAndSwapInt(unsafe, a2, off(a2, "value"), 42, 53));
+ assertDeepEquals(a1.get(), a2.get());
AtomicLong l1 = new AtomicLong(42);
AtomicLong l2 = new AtomicLong(42);
- assertEquals(unsafe.compareAndSwapLong(l1, off(l1, "value"), 42, 53), compareAndSwapLong(unsafe, l2, off(l2, "value"), 42, 53));
- assertEquals(l1.get(), l2.get());
+ assertDeepEquals(unsafe.compareAndSwapLong(l1, off(l1, "value"), 42, 53), compareAndSwapLong(unsafe, l2, off(l2, "value"), 42, 53));
+ assertDeepEquals(l1.get(), l2.get());
AtomicReference o1 = new AtomicReference<>("42");
AtomicReference o2 = new AtomicReference<>("42");
- assertEquals(unsafe.compareAndSwapObject(o1, off(o1, "value"), "42", "53"), compareAndSwapObject(unsafe, o2, off(o2, "value"), "42", "53"));
- assertEquals(o1.get(), o2.get());
+ assertDeepEquals(unsafe.compareAndSwapObject(o1, off(o1, "value"), "42", "53"), compareAndSwapObject(unsafe, o2, off(o2, "value"), "42", "53"));
+ assertDeepEquals(o1.get(), o2.get());
Foo f1 = new Foo();
f1.test("z", "Boolean", Boolean.TRUE);
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.test/src/com/oracle/graal/test/AnsiTerminalDecorator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/AnsiTerminalDecorator.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.test;
+
+import org.junit.runner.*;
+import org.junit.runner.notification.*;
+
+import static com.oracle.graal.debug.AnsiColor.*;
+
+/**
+ * Color support for JUnit test output using ANSI escapes codes.
+ */
+public class AnsiTerminalDecorator extends GraalJUnitRunListenerDecorator {
+
+ public AnsiTerminalDecorator(GraalJUnitRunListener l) {
+ super(l);
+ }
+
+ @Override
+ public void testSucceeded(Description description) {
+ getWriter().print(GREEN);
+ super.testSucceeded(description);
+ getWriter().print(RESET);
+ }
+
+ @Override
+ public void testFailed(Failure failure) {
+ getWriter().print(RED);
+ super.testFailed(failure);
+ getWriter().print(RESET);
+ }
+
+ @Override
+ public void testIgnored(Description description) {
+ getWriter().print(MAGENTA);
+ super.testIgnored(description);
+ getWriter().print(RESET);
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.test/src/com/oracle/graal/test/EagerStackTraceDecorator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/EagerStackTraceDecorator.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.test;
+
+import org.junit.runner.notification.*;
+
+public class EagerStackTraceDecorator extends GraalJUnitRunListenerDecorator {
+
+ public EagerStackTraceDecorator(GraalJUnitRunListener l) {
+ super(l);
+ }
+
+ @Override
+ public void testFailed(Failure failure) {
+ super.testFailed(failure);
+ failure.getException().printStackTrace(getWriter());
+ }
+
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java Wed May 21 11:45:50 2014 +0200
@@ -49,6 +49,8 @@
List missingClasses = new ArrayList<>();
boolean verbose = false;
boolean enableTiming = false;
+ boolean color = false;
+ boolean eagerStackTrace = false;
for (String each : args) {
if (each.charAt(0) == '-') {
// command line arguments
@@ -56,6 +58,10 @@
verbose = true;
} else if (each.contentEquals("-JUnitEnableTiming")) {
enableTiming = true;
+ } else if (each.contentEquals("-JUnitColor")) {
+ color = true;
+ } else if (each.contentEquals("-JUnitEagerStackTrace")) {
+ eagerStackTrace = true;
} else {
system.out().println("Unknown command line argument: " + each);
}
@@ -80,6 +86,12 @@
if (enableTiming) {
graalListener = new TimingDecorator(graalListener);
}
+ if (color) {
+ graalListener = new AnsiTerminalDecorator(graalListener);
+ }
+ if (eagerStackTrace) {
+ graalListener = new EagerStackTraceDecorator(graalListener);
+ }
junitCore.addListener(GraalTextListener.createRunListener(graalListener));
Result result = junitCore.run(classes.toArray(new Class[0]));
for (Failure each : missingClasses) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Wed May 21 11:45:50 2014 +0200
@@ -76,37 +76,83 @@
* Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
* Does a deep copy equality comparison if {@code expected} is an array.
*/
- protected void assertEquals(Object expected, Object actual) {
- if (expected != null && expected.getClass().isArray()) {
- Assert.assertTrue(expected != null);
- Assert.assertTrue(actual != null);
- Assert.assertEquals(expected.getClass(), actual.getClass());
- if (expected instanceof int[]) {
- Assert.assertArrayEquals((int[]) expected, (int[]) actual);
- } else if (expected instanceof byte[]) {
- Assert.assertArrayEquals((byte[]) expected, (byte[]) actual);
- } else if (expected instanceof char[]) {
- Assert.assertArrayEquals((char[]) expected, (char[]) actual);
- } else if (expected instanceof short[]) {
- Assert.assertArrayEquals((short[]) expected, (short[]) actual);
- } else if (expected instanceof float[]) {
- Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f);
- } else if (expected instanceof long[]) {
- Assert.assertArrayEquals((long[]) expected, (long[]) actual);
- } else if (expected instanceof double[]) {
- Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d);
- } else if (expected instanceof boolean[]) {
- new ExactComparisonCriteria().arrayEquals(null, expected, actual);
- } else if (expected instanceof Object[]) {
- Assert.assertArrayEquals((Object[]) expected, (Object[]) actual);
+ protected void assertDeepEquals(Object expected, Object actual) {
+ assertDeepEquals(null, expected, actual);
+ }
+
+ /**
+ * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
+ * Does a deep copy equality comparison if {@code expected} is an array.
+ *
+ * @param message the identifying message for the {@link AssertionError}
+ */
+ protected void assertDeepEquals(String message, Object expected, Object actual) {
+ assertDeepEquals(message, expected, actual, equalFloatsOrDoublesDelta());
+ }
+
+ /**
+ * Compares two given values for equality, doing a recursive test if both values are arrays of
+ * the same type.
+ *
+ * @param message the identifying message for the {@link AssertionError}
+ * @param delta the maximum delta between two doubles or floats for which both numbers are still
+ * considered equal.
+ */
+ protected void assertDeepEquals(String message, Object expected, Object actual, double delta) {
+ if (expected != null && actual != null) {
+ Class> expectedClass = expected.getClass();
+ Class> actualClass = actual.getClass();
+ if (expectedClass.isArray()) {
+ Assert.assertTrue(message, expected != null);
+ Assert.assertTrue(message, actual != null);
+ Assert.assertEquals(message, expectedClass, actual.getClass());
+ if (expected instanceof int[]) {
+ Assert.assertArrayEquals(message, (int[]) expected, (int[]) actual);
+ } else if (expected instanceof byte[]) {
+ Assert.assertArrayEquals(message, (byte[]) expected, (byte[]) actual);
+ } else if (expected instanceof char[]) {
+ Assert.assertArrayEquals(message, (char[]) expected, (char[]) actual);
+ } else if (expected instanceof short[]) {
+ Assert.assertArrayEquals(message, (short[]) expected, (short[]) actual);
+ } else if (expected instanceof float[]) {
+ Assert.assertArrayEquals(message, (float[]) expected, (float[]) actual, (float) delta);
+ } else if (expected instanceof long[]) {
+ Assert.assertArrayEquals(message, (long[]) expected, (long[]) actual);
+ } else if (expected instanceof double[]) {
+ Assert.assertArrayEquals(message, (double[]) expected, (double[]) actual, delta);
+ } else if (expected instanceof boolean[]) {
+ new ExactComparisonCriteria().arrayEquals(message, expected, actual);
+ } else if (expected instanceof Object[]) {
+ new ComparisonCriteria() {
+ @Override
+ protected void assertElementsEqual(Object e, Object a) {
+ assertDeepEquals(message, e, a, delta);
+ }
+ }.arrayEquals(message, expected, actual);
+ } else {
+ Assert.fail((message == null ? "" : message) + "non-array value encountered: " + expected);
+ }
+ } else if (expectedClass.equals(double.class) && actualClass.equals(double.class)) {
+ Assert.assertEquals((double) expected, (double) actual, delta);
+ } else if (expectedClass.equals(float.class) && actualClass.equals(float.class)) {
+ Assert.assertEquals((float) expected, (float) actual, delta);
} else {
- Assert.fail("non-array value encountered: " + expected);
+ Assert.assertEquals(message, expected, actual);
}
} else {
- Assert.assertEquals(expected, actual);
+ Assert.assertEquals(message, expected, actual);
}
}
+ /**
+ * Gets the value used by {@link #assertDeepEquals(Object, Object)} and
+ * {@link #assertDeepEquals(String, Object, Object)} for the maximum delta between two doubles
+ * or floats for which both numbers are still considered equal.
+ */
+ protected double equalFloatsOrDoublesDelta() {
+ return 0.0D;
+ }
+
@SuppressWarnings("serial")
public static class MultiCauseAssertionError extends AssertionError {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalVerboseTextListener.java
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalVerboseTextListener.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalVerboseTextListener.java Wed May 21 11:45:50 2014 +0200
@@ -65,8 +65,7 @@
@Override
public void testFailed(Failure failure) {
- getWriter().println("FAILED");
- failure.getException().printStackTrace(getWriter());
+ getWriter().print("FAILED");
}
@Override
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Wed May 21 11:45:50 2014 +0200
@@ -284,7 +284,6 @@
if (frames.hasNext()) {
return new HotSpotFrameInstance.CallTargetFrame(frames.next(), true);
} else {
- System.out.println("no current frame found");
return null;
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/AssumptionPartialEvaluationTest.java
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/AssumptionPartialEvaluationTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/AssumptionPartialEvaluationTest.java Wed May 21 11:45:50 2014 +0200
@@ -46,7 +46,7 @@
InstalledCode installedCode = assertPartialEvalEquals("constant42", rootNode);
Assert.assertTrue(installedCode.isValid());
try {
- assertEquals(42, installedCode.executeVarargs(null, null, null));
+ assertDeepEquals(42, installedCode.executeVarargs(null, null, null));
} catch (InvalidInstalledCodeException e) {
Assert.fail("Code must not have been invalidated.");
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java Wed May 21 11:45:50 2014 +0200
@@ -62,6 +62,20 @@
}
@Test
+ public void testMulHigh() {
+ test("mulHigh", 7, 15);
+ test("mulHigh", Integer.MAX_VALUE, 15);
+ test("mulHigh", Integer.MIN_VALUE, 15);
+ }
+
+ @Test
+ public void testMulHighUnsigned() {
+ test("mulHighUnsigned", 7, 15);
+ test("mulHighUnsigned", Integer.MAX_VALUE, 15);
+ test("mulHighUnsigned", Integer.MIN_VALUE, 15);
+ }
+
+ @Test
public void testLongAdd() {
test("longAdd", (long) Integer.MAX_VALUE, 2L);
test("longAdd", Long.MAX_VALUE, 2L);
@@ -80,6 +94,20 @@
test("longSub", Long.MIN_VALUE, 2L);
}
+ @Test
+ public void testLongMulHigh() {
+ test("longMulHigh", 7L, 15L);
+ test("longMulHigh", Long.MAX_VALUE, 15L);
+ test("longMulHigh", Long.MIN_VALUE, 15L);
+ }
+
+ @Test
+ public void testLongMulHighUnsigned() {
+ test("longMulHighUnsigned", 7L, 15L);
+ test("longMulHighUnsigned", Long.MAX_VALUE, 15L);
+ test("longMulHighUnsigned", Long.MIN_VALUE, 15L);
+ }
+
public static int add(int a, int b) {
return ExactMath.addExact(a, b);
}
@@ -92,6 +120,14 @@
return ExactMath.subtractExact(a, b);
}
+ public static int mulHigh(int a, int b) {
+ return ExactMath.multiplyHigh(a, b);
+ }
+
+ public static int mulHighUnsigned(int a, int b) {
+ return ExactMath.multiplyHighUnsigned(a, b);
+ }
+
public static long longAdd(long a, long b) {
return ExactMath.addExact(a, b);
}
@@ -103,4 +139,12 @@
public static long longSub(long a, long b) {
return ExactMath.subtractExact(a, b);
}
+
+ public static long longMulHigh(long a, long b) {
+ return ExactMath.multiplyHigh(a, b);
+ }
+
+ public static long longMulHighUnsigned(long a, long b) {
+ return ExactMath.multiplyHighUnsigned(a, b);
+ }
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed May 21 11:45:50 2014 +0200
@@ -108,7 +108,7 @@
canonicalizer.apply(graph, baseContext);
// Intrinsify methods.
- new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph);
+ new IncrementalCanonicalizerPhase<>(canonicalizer, new ReplaceIntrinsicsPhase(providers.getReplacements())).apply(graph, baseContext);
Debug.dump(graph, "Before inlining");
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.truffle.nodes.arithmetic;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.truffle.api.*;
+
+@NodeInfo(shortName = "*H")
+public class IntegerMulHighNode extends IntegerArithmeticNode {
+
+ public IntegerMulHighNode(ValueNode x, ValueNode y) {
+ this(x.stamp().unrestricted(), x, y);
+ }
+
+ public IntegerMulHighNode(Stamp stamp, ValueNode x, ValueNode y) {
+ super(stamp, x, y);
+ }
+
+ @Override
+ public Constant evalConst(Constant... inputs) {
+ assert inputs.length == 2 && inputs[0].getKind() == inputs[1].getKind();
+ switch (inputs[0].getKind()) {
+ case Int:
+ return Constant.forInt(ExactMath.multiplyHigh(inputs[0].asInt(), inputs[1].asInt()));
+ case Long:
+ return Constant.forLong(ExactMath.multiplyHigh(inputs[0].asLong(), inputs[1].asLong()));
+ default:
+ throw GraalInternalError.unimplemented();
+ }
+ }
+
+ @Override
+ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
+ Value a = builder.operand(x());
+ Value b = builder.operand(y());
+ builder.setResult(this, gen.emitMulHigh(a, b));
+ }
+
+ @NodeIntrinsic
+ public static int multiplyHigh(int a, int b) {
+ return ExactMath.multiplyHigh(a, b);
+ }
+
+ @NodeIntrinsic
+ public static long multiplyHigh(long a, long b) {
+ return ExactMath.multiplyHigh(a, b);
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.truffle.nodes.arithmetic;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.truffle.api.*;
+
+@NodeInfo(shortName = "|*H|")
+public class UnsignedMulHighNode extends IntegerArithmeticNode {
+
+ public UnsignedMulHighNode(ValueNode x, ValueNode y) {
+ this(x.stamp().unrestricted(), x, y);
+ }
+
+ public UnsignedMulHighNode(Stamp stamp, ValueNode x, ValueNode y) {
+ super(stamp, x, y);
+ }
+
+ @Override
+ public Constant evalConst(Constant... inputs) {
+ assert inputs.length == 2 && inputs[0].getKind() == inputs[1].getKind();
+ switch (inputs[0].getKind()) {
+ case Int:
+ return Constant.forInt(ExactMath.multiplyHighUnsigned(inputs[0].asInt(), inputs[1].asInt()));
+ case Long:
+ return Constant.forLong(ExactMath.multiplyHighUnsigned(inputs[0].asLong(), inputs[1].asLong()));
+ default:
+ throw GraalInternalError.unimplemented();
+ }
+ }
+
+ @Override
+ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
+ Value a = builder.operand(x());
+ Value b = builder.operand(y());
+ builder.setResult(this, gen.emitUMulHigh(a, b));
+ }
+
+ @NodeIntrinsic
+ public static int multiplyHighUnsigned(int a, int b) {
+ return ExactMath.multiplyHighUnsigned(a, b);
+ }
+
+ @NodeIntrinsic
+ public static long multiplyHighUnsigned(long a, long b) {
+ return ExactMath.multiplyHighUnsigned(a, b);
+ }
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/ExactMathSubstitutions.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/ExactMathSubstitutions.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/ExactMathSubstitutions.java Wed May 21 11:45:50 2014 +0200
@@ -62,4 +62,24 @@
public static long multiplyExact(long x, long y) {
return IntegerMulExactNode.multiplyExact(x, y);
}
+
+ @MethodSubstitution
+ public static int multiplyHigh(int x, int y) {
+ return IntegerMulHighNode.multiplyHigh(x, y);
+ }
+
+ @MethodSubstitution
+ public static int multiplyHighUnsigned(int x, int y) {
+ return UnsignedMulHighNode.multiplyHighUnsigned(x, y);
+ }
+
+ @MethodSubstitution
+ public static long multiplyHigh(long x, long y) {
+ return IntegerMulHighNode.multiplyHigh(x, y);
+ }
+
+ @MethodSubstitution
+ public static long multiplyHighUnsigned(long x, long y) {
+ return UnsignedMulHighNode.multiplyHighUnsigned(x, y);
+ }
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java Wed May 21 11:45:50 2014 +0200
@@ -45,7 +45,7 @@
this.fieldValues = new NodeInputList<>(this, fieldValues);
}
- private VirtualObjectState(VirtualObjectNode object, List fieldValues) {
+ public VirtualObjectState(VirtualObjectNode object, List fieldValues) {
super(object);
assert object.entryCount() == fieldValues.size();
this.fieldValues = new NodeInputList<>(this, fieldValues);
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Wed May 21 11:45:50 2014 +0200
@@ -178,15 +178,15 @@
return;
}
+ Invoke invoke = callTargetNode.invoke();
if (!callTargetNode.isStatic()) {
assert callTargetNode.receiver().getKind() == wordKind : "changeToWord() missed the receiver";
- targetMethod = wordImplType.resolveMethod(targetMethod);
+ targetMethod = wordImplType.resolveMethod(targetMethod, invoke.getContextType());
}
Operation operation = targetMethod.getAnnotation(Word.Operation.class);
assert operation != null : targetMethod;
NodeInputList arguments = callTargetNode.arguments();
- Invoke invoke = callTargetNode.invoke();
switch (operation.opcode()) {
case NODE_CLASS:
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Wed May 21 11:45:50 2014 +0200
@@ -113,7 +113,7 @@
if (!isStatic) {
ValueNode receiver = arguments.get(argc);
if (receiver == node && isWord(node)) {
- ResolvedJavaMethod resolvedMethod = wordAccess.wordImplType.resolveMethod(method);
+ ResolvedJavaMethod resolvedMethod = wordAccess.wordImplType.resolveMethod(method, invoke.getContextType());
verify(resolvedMethod != null, node, invoke.asNode(), "cannot resolve method on Word class: " + MetaUtil.format("%H.%n(%P) %r", method));
Operation operation = resolvedMethod.getAnnotation(Word.Operation.class);
verify(operation != null, node, invoke.asNode(), "cannot dispatch on word value to non @Operation annotated method " + resolvedMethod);
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExactMath.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExactMath.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExactMath.java Wed May 21 11:45:50 2014 +0200
@@ -91,4 +91,54 @@
}
return r;
}
+
+ public static int multiplyHigh(int x, int y) {
+ long r = (long) x * (long) y;
+ return (int) (r >> 32);
+ }
+
+ public static int multiplyHighUnsigned(int x, int y) {
+ long xl = x & 0xFFFFFFFFL;
+ long yl = y & 0xFFFFFFFFL;
+ long r = xl * yl;
+ return (int) (r >> 32);
+ }
+
+ public static long multiplyHigh(long x, long y) {
+ long x0, y0, z0;
+ long x1, y1, z1, z2, t;
+
+ x0 = x & 0xFFFFFFFFL;
+ x1 = x >> 32;
+
+ y0 = y & 0xFFFFFFFFL;
+ y1 = y >> 32;
+
+ z0 = x0 * y0;
+ t = x1 * y0 + (z0 >>> 32);
+ z1 = t & 0xFFFFFFFFL;
+ z2 = t >> 32;
+ z1 += x0 * y1;
+
+ return x1 * y1 + z2 + (z1 >> 32);
+ }
+
+ public static long multiplyHighUnsigned(long x, long y) {
+ long x0, y0, z0;
+ long x1, y1, z1, z2, t;
+
+ x0 = x & 0xFFFFFFFFL;
+ x1 = x >>> 32;
+
+ y0 = y & 0xFFFFFFFFL;
+ y1 = y >>> 32;
+
+ z0 = x0 * y0;
+ t = x1 * y0 + (z0 >>> 32);
+ z1 = t & 0xFFFFFFFFL;
+ z2 = t >>> 32;
+ z1 += x0 * y1;
+
+ return x1 * y1 + z2 + (z1 >>> 32);
+ }
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Wed May 21 11:45:50 2014 +0200
@@ -27,31 +27,131 @@
import java.util.*;
import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.*;
import com.oracle.truffle.api.source.*;
/**
* Access to information and basic services in the runtime context for a Truffle-implemented guest
* language.
*
- * Disclaimer: this interface is under development and will change.
+ * Disclaimer: this class is under development and will change.
*/
-public interface ExecutionContext {
+public abstract class ExecutionContext {
+
+ private final ProbeManager probeManager = new ProbeManager();
+ private final SourceManager sourceManager = new SourceManager();
+ private final List sourceListeners = new ArrayList<>();
+ private Visualizer visualizer = new DefaultVisualizer();
+
+ protected ExecutionContext() {
+ }
+
+ public void initialize() {
+ setSourceCallback(new SourceCallback() {
+
+ public void startLoading(Source source) {
+ for (SourceListener listener : sourceListeners) {
+ listener.loadStarting(source);
+ }
+ }
+
+ public void endLoading(Source source) {
+ for (SourceListener listener : sourceListeners) {
+ listener.loadEnding(source);
+ }
+ }
+ });
+ }
+
+ /**
+ * Gets access to source management services.
+ */
+ public final SourceManager getSourceManager() {
+ return sourceManager;
+ }
+
+ /**
+ * Registers a tool interested in being notified about the loading of {@link Source}s.
+ */
+ public final void addSourceListener(SourceListener listener) {
+ assert listener != null;
+ sourceListeners.add(listener);
+ }
+
+ /**
+ * Registers a tool interested in being notified about the insertion of a newly created
+ * {@link Probe} into a Truffle AST.
+ */
+ public final void addProbeListener(ProbeListener listener) {
+ probeManager.addProbeListener(listener);
+ }
+
+ /**
+ * Return the (possibly newly created) {@link Probe} uniquely associated with a particular
+ * source code location. A newly created probe carries no tags.
+ *
+ * @return a probe uniquely associated with an extent of guest language source code.
+ */
+ public final Probe getProbe(SourceSection sourceSection) {
+ return probeManager.getProbe(sourceSection);
+ }
+
+ /**
+ * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty
+ * collection if no probes found.
+ */
+ public final Collection findProbesTaggedAs(PhylumTag tag) {
+ return probeManager.findProbesTaggedAs(tag);
+ }
+
+ /**
+ * Returns all existing probes with first character on a specified line; empty collection if no
+ * probes found.
+ */
+ public final Collection findProbesByLine(SourceLineLocation lineLocation) {
+ return probeManager.findProbesByLine(lineLocation);
+ }
+
+ /**
+ * Sets a trap that will make a callback at any AST location where a existing probe holds a
+ * specified tag; only one trap may be set at a time.
+ *
+ * @throws IllegalStateException if a trap is already set
+ */
+ public final void setPhylumTrap(PhylumTrap trap) throws IllegalStateException {
+ // TODO (mlvdv) consider allowing multiple traps (without inhibiting Truffle inlining)
+ probeManager.setPhylumTrap(trap);
+ }
+
+ /**
+ * Clears a trap that will halt execution; only one trap may be set at a time.
+ *
+ * @throws IllegalStateException if no trap is set.
+ */
+ public final void clearPhylumTrap() {
+ probeManager.clearPhylumTrap();
+ }
+
+ /**
+ * Access to information visualization services for the specific language.
+ */
+ public final Visualizer getVisualizer() {
+ return visualizer;
+ }
+
+ /**
+ * Assign guest language-specific visualization support for tools. This must be assigned outside
+ * the implementation context to avoid build circularities.
+ */
+ public final void setVisualizer(Visualizer visualizer) {
+ this.visualizer = visualizer;
+ }
/**
* Gets the name of the language, possibly with version number. in short enough form that it
* might be used for an interactive prompt.
*/
- String getLanguageShortName();
-
- /**
- * Gets access to source management services.
- */
- SourceManager getSourceManager();
-
- /**
- * Registers a tool interested in being notified of events related to the loading of sources.
- */
- void addSourceListener(SourceListener listener);
+ public abstract String getLanguageShortName();
/**
* Add instrumentation to subsequently constructed Truffle ASTs for the guest language; every
@@ -60,51 +160,19 @@
* @throws IllegalStateException if AST instrumentation not enabled
* @throws IllegalArgumentException if prober not usable for the guest language implementation.
*/
- void addNodeProber(ASTNodeProber nodeProber) throws IllegalStateException, IllegalArgumentException;
-
- /**
- * Registers a tool interested in being notified about the insertion of a newly created
- * {@link Probe} into a Truffle AST.
- */
- void addProbeListener(ProbeListener listener);
-
- /**
- * Return the (possibly newly created) {@link Probe} uniquely associated with a particular
- * source code location. A newly created probe carries no tags.
- *
- * @return a probe uniquely associated with an extent of guest language source code.
- */
- Probe getProbe(SourceSection sourceSection);
-
- /**
- * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty
- * collection if no probes found.
- */
- Collection findProbesTaggedAs(PhylumTag tag);
+ public abstract void addNodeProber(ASTNodeProber nodeProber) throws IllegalStateException, IllegalArgumentException;
/**
- * Returns all existing probes with first character on a specified line; empty collection if no
- * probes found.
+ * Assigns a guest language-specific manager for using {@link ASTNodeProber}s added by tools to
+ * instrument ASTs with {@link Probe}s at specified nodes. This must be assigned outside the
+ * implementation context to avoid build circularities. It must also be set before any
+ * instrumentation probe implementations are assigned.
*/
- Collection findProbesByLine(SourceLineLocation lineLocation);
+ public abstract void setASTProber(ASTProber astProber);
/**
- * Sets a trap that will make a callback at any AST location where a existing probe holds a
- * specified tag; only one trap may be set at a time.
- *
- * @throws IllegalStateException if a trap is already set
+ * Establishes source event reporting
*/
- void setTrap(PhylumTrap trap) throws IllegalStateException;
+ protected abstract void setSourceCallback(SourceCallback sourceCallback);
- /**
- * Clears a trap that will halt execution; only one trap may be set at a time.
- *
- * @throws IllegalStateException if no trap is set.
- */
- void clearTrap() throws IllegalStateException;
-
- /**
- * Access to information visualization services for the specific language.
- */
- Visualizer getVisualizer();
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java Wed May 21 11:45:50 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
import java.io.*;
+import com.oracle.truffle.api.source.*;
+
/**
* Represents a unit (typically a file) of guest language source code.
*/
@@ -97,4 +99,61 @@
*/
int getLineLength(int lineNumber);
+ /**
+ * Creates a representation of a contiguous region of text in the source. Computes the
+ * {@code (startLine, startColumn)} values by building a {@linkplain TextMap map} of lines in
+ * the source.
+ *
+ * Checks the position arguments for consistency with the source.
+ *
+ * The resulting representation defines hash/equality around equivalent location, presuming that
+ * {@link Source} representations are cannonical.
+ *
+ *
+ * @param identifier terse description of the region
+ * @param charIndex 0-based position of the first character in the section
+ * @param length the number of characters in the section
+ * @return newly created object representing the specified region
+ * @throws IllegalArgumentException if either of the arguments are outside the text of the
+ * source
+ * @throws IllegalStateException if the source is one of the "null" instances
+ */
+ SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException, IllegalStateException;
+
+ /**
+ * Creates a representation of a contiguous region of text in the source. Computes the
+ * {@code charIndex} value by building a {@linkplain TextMap map} of lines in the source.
+ *
+ * Checks the position arguments for consistency with the source.
+ *
+ * The resulting representation defines hash/equality around equivalent location, presuming that
+ * {@link Source} representations are cannonical.
+ *
+ * @param identifier terse description of the region
+ * @param startLine 1-based line number of the first character in the section
+ * @param startColumn 1-based column number of the first character in the section
+ * @param length the number of characters in the section
+ * @return newly created object representing the specified region
+ * @throws IllegalArgumentException if arguments are outside the text of the source
+ * @throws IllegalStateException if the source is one of the "null" instances
+ */
+ SourceSection createSection(String identifier, int startLine, int startColumn, int length);
+
+ /**
+ * Creates a representation of a contiguous region of text in the source.
+ *
+ * This method performs no checks on the validity of the arguments.
+ *
+ * The resulting representation defines hash/equality around equivalent location, presuming that
+ * {@link Source} representations are cannonical.
+ *
+ * @param identifier terse description of the region
+ * @param startLine 1-based line number of the first character in the section
+ * @param startColumn 1-based column number of the first character in the section
+ * @param charIndex the 0-based index of the first character of the section
+ * @param length the number of characters in the section
+ * @return newly created object representing the specified region
+ */
+ SourceSection createSection(String identifier, int startLine, int startColumn, int charIndex, int length);
+
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Wed May 21 11:45:50 2014 +0200
@@ -25,46 +25,62 @@
package com.oracle.truffle.api;
/**
- * Description of contiguous text section within the source code of a guest language program.
+ * Description of contiguous section of text within a {@link Source} of program code.
+ *
+ * The starting location of the section can be described using two different coordinates:
+ *
+ * - {@code (startLine, startColumn)}: rows and columns are 1-based, so the first character in a
+ * source file is at position {@code (1,1)}. {@code Tab} characters are counted as occupying one
+ * column.
+ * - character index: 0-based offset of the character from the beginning of the source, so
+ * the first character in a file is at index {@code 0}.
+ *
+ * The {@code Newline} that terminates each line counts as a single character for the purpose of a
+ * character index and when counting the length of text. The {@code (line,column)} coordinates of a
+ * {@code Newline} should never appear in a text section.
+ *
+ * If the final character of source is not a {@code Newline}, the final characters of the text are
+ * still considered to be a line ("unterminated").
+ *
+ *
+ * @see Source#createSection(String, int, int, int, int)
+ * @see Source#createSection(String, int, int, int)
+ * @see Source#createSection(String, int, int)
*/
public interface SourceSection {
+ // TODO support alternate text representations/encodings
+
/**
- * Returns the object representing the source program that contains this section.
+ * Representation of the source program that contains this section.
*
* @return the source object
*/
Source getSource();
/**
- * Returns 1-based line number of the first character in this source section (inclusive).
+ * Returns 1-based line number of the first character in this section (inclusive).
*
* @return the starting line number
*/
int getStartLine();
/**
- * Returns the 1-based column number of the first character in this source section (inclusive).
+ * Returns the 1-based column number of the first character in this section (inclusive).
*
* @return the starting column number
*/
int getStartColumn();
/**
- * Returns the 0-based index of the first character in this source section.
- *
- * The complete text of the source that contains this section can be retrieved via
- * {@link Source#getCode()}.
+ * Returns the 0-based index of the first character in this section.
*
* @return the starting character index
*/
int getCharIndex();
/**
- * Returns the length of this source section in characters.
- *
- * The complete text of the source that contains this section can be retrieved via
- * {@link Source#getCode()}.
+ * Returns the length of this section in characters.
*
* @return the number of characters in the section
*/
@@ -79,14 +95,14 @@
int getCharEndIndex();
/**
- * Returns the identifier of this source section that is used for printing the section.
+ * Returns terse text describing this source section, typically used for printing the section.
*
* @return the identifier of the section
*/
String getIdentifier();
/**
- * Returns text of the code represented by this source section.
+ * Returns text described by this section.
*
* @return the code as a String object
*/
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Wed May 21 11:45:50 2014 +0200
@@ -106,7 +106,8 @@
/**
* Accesses the current stack, i.e., the contents of the {@link Frame}s and the associated
- * {@link CallTarget}s.
+ * {@link CallTarget}s. Iteration starts at the caller frame, i.e., it does not include the
+ * current frame.
*
* @return a lazy collection of {@link FrameInstance}.
*/
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java Tue May 13 19:19:27 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,217 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.impl;
-
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.instrument.impl.*;
-import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeCallback;
-import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeImpl;
-import com.oracle.truffle.api.source.*;
-
-public abstract class AbstractExecutionContext implements ExecutionContext {
-
- // TODO (mlvdv) use weak references.
- /**
- * Map: SourceSection ==> probe associated with that source section in an AST.
- */
- private final Map srcToProbe = new HashMap<>();
-
- // TODO (mlvdv) use weak references.
- /**
- * Map: Source line ==> probes associated with source sections starting on the line.
- */
- private final Map> lineToProbes = new HashMap<>();
-
- private final SourceManager sourceManager = new SourceManager();
- private final List sourceListeners = new ArrayList<>();
- private final List probeListeners = new ArrayList<>();
-
- private final SourceCallback sourceCallback = new SourceCallback() {
-
- public void startLoading(Source source) {
- for (SourceListener listener : sourceListeners) {
- listener.loadStarting(source);
- }
- }
-
- public void endLoading(Source source) {
- for (SourceListener listener : sourceListeners) {
- listener.loadEnding(source);
- }
- }
- };
-
- private final ProbeCallback probeCallback = new ProbeCallback() {
- /**
- * Receives (from the {@link Probe} implementation) and distributes notification that a
- * {@link Probe} has acquired a new {@linkplain PhylumTag tag}.
- */
- public void newTagAdded(ProbeImpl probe, PhylumTag tag) {
- for (ProbeListener listener : probeListeners) {
- listener.probeTaggedAs(probe, tag);
- }
- if (trap != null && tag == trap.getTag()) {
- probe.setTrap(trap);
- }
- }
- };
-
- private Visualizer visualizer = new DefaultVisualizer();
-
- /**
- * When non-null, "enter" events with matching tags will trigger a callback.
- */
- private PhylumTrap trap = null;
-
- protected AbstractExecutionContext() {
- }
-
- public void initialize() {
- setSourceCallback(sourceCallback);
- }
-
- public final SourceManager getSourceManager() {
- return sourceManager;
- }
-
- public void addSourceListener(SourceListener listener) {
- assert listener != null;
- sourceListeners.add(listener);
- }
-
- public void addProbeListener(ProbeListener listener) {
- assert listener != null;
- probeListeners.add(listener);
- }
-
- public Probe getProbe(SourceSection sourceSection) {
- assert sourceSection != null;
-
- ProbeImpl probe = srcToProbe.get(sourceSection);
-
- if (probe != null) {
- return probe;
- }
- probe = InstrumentationNode.createProbe(sourceSection, probeCallback);
-
- // Register new probe by unique SourceSection
- srcToProbe.put(sourceSection, probe);
-
- // Register new probe by source line, there may be more than one
- // Create line location for map key
- final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine());
-
- Collection probes = lineToProbes.get(lineLocation);
- if (probes == null) {
- probes = new ArrayList<>(2);
- lineToProbes.put(lineLocation, probes);
- }
- probes.add(probe);
-
- for (ProbeListener listener : probeListeners) {
- listener.newProbeInserted(sourceSection, probe);
- }
-
- return probe;
- }
-
- /**
- * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty
- * collection if no probes found.
- */
- public Collection findProbesTaggedAs(PhylumTag tag) {
- final List probes = new ArrayList<>();
- for (Probe probe : srcToProbe.values()) {
- if (tag == null || probe.isTaggedAs(tag)) {
- probes.add(probe);
- }
- }
- return probes;
- }
-
- public Collection findProbesByLine(SourceLineLocation lineLocation) {
- final Collection probes = lineToProbes.get(lineLocation);
- if (probes == null) {
- return Collections.emptyList();
- }
- return new ArrayList<>(probes);
- }
-
- // TODO (mlvdv) consider allowing multiple traps (without inhibiting Truffle inlining)
- public void setTrap(PhylumTrap trap) {
- assert trap != null;
- if (this.trap != null) {
- throw new IllegalStateException("trap already set");
- }
- this.trap = trap;
-
- for (ProbeImpl probe : srcToProbe.values()) {
- if (probe.isTaggedAs(trap.getTag())) {
- probe.setTrap(trap);
- }
- }
- }
-
- public void clearTrap() {
- if (this.trap == null) {
- throw new IllegalStateException("no trap set");
- }
- for (ProbeImpl probe : srcToProbe.values()) {
- if (probe.isTaggedAs(trap.getTag())) {
- probe.setTrap(null);
- }
- }
- trap = null;
- }
-
- public Visualizer getVisualizer() {
- return visualizer;
- }
-
- /**
- * Assign guest language-specific visualization support for tools. This must be assigned outside
- * the implementation context to avoid build circularities.
- */
- public void setVisualizer(Visualizer visualizer) {
- this.visualizer = visualizer;
- }
-
- /**
- * Assigns a guest language-specific manager for using {@link ASTNodeProber}s added by tools to
- * instrument ASTs with {@link Probe}s at specified nodes. This must be assigned outside the
- * implementation context to avoid build circularities. It must also be set before any
- * instrumentation probe implementations are assigned.
- */
- public abstract void setASTProber(ASTProber astProber);
-
- /**
- * Establishes source event reporting
- */
- protected abstract void setSourceCallback(SourceCallback sourceCallback);
-
-}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java Tue May 13 19:19:27 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,168 +0,0 @@
-/*
- * 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.impl;
-
-import com.oracle.truffle.api.*;
-
-/**
- * Represents a contiguous text section within the source code of a guest language program.
- */
-public class DefaultSourceSection implements SourceSection {
-
- private final Source source;
- private final String identifier;
- private final int startLine;
- private final int startColumn;
- private final int charIndex;
- private final int charLength;
-
- /**
- * Creates a new object representing a contiguous text section within the source code of a guest
- * language program's text.
- *
- * The starting location of the section is specified using two different coordinate:
- *
- * - (row, column): rows and columns are 1-based, so the first character in a source
- * file is at position {@code (1,1)}.
- * - character index: 0-based offset of the character from the beginning of the source,
- * so the first character in a file is at index {@code 0}.
- *
- * The newline that terminates each line counts as a single character for the purpose of
- * a character index. The (row,column) coordinates of a newline character should never appear in
- * a text section.
- *
- *
- * @param source object representing the complete source program that contains this section
- * @param identifier an identifier used when printing the section
- * @param startLine the 1-based number of the start line of the section
- * @param startColumn the 1-based number of the start column of the section
- * @param charIndex the 0-based index of the first character of the section
- * @param charLength the length of the section in number of characters
- */
- public DefaultSourceSection(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) {
- this.source = source;
- this.identifier = identifier;
- this.startLine = startLine;
- this.startColumn = startColumn;
- this.charIndex = charIndex;
- this.charLength = charLength;
- }
-
- public final Source getSource() {
- return source;
- }
-
- public final int getStartLine() {
- return startLine;
- }
-
- public final int getStartColumn() {
- return startColumn;
- }
-
- public final int getCharIndex() {
- return charIndex;
- }
-
- public final int getCharLength() {
- return charLength;
- }
-
- public final int getCharEndIndex() {
- return charIndex + charLength;
- }
-
- public final String getIdentifier() {
- return identifier;
- }
-
- public final String getCode() {
- return getSource().getCode().substring(charIndex, charIndex + charLength);
- }
-
- public final String getShortDescription() {
- return String.format("%s:%d", source.getShortName(), startLine);
- }
-
- @Override
- public String toString() {
- return String.format("%s:%d", source.getName(), startLine);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + charIndex;
- result = prime * result + charLength;
- result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
- result = prime * result + ((source == null) ? 0 : source.hashCode());
- result = prime * result + startColumn;
- result = prime * result + startLine;
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (!(obj instanceof DefaultSourceSection)) {
- return false;
- }
- DefaultSourceSection other = (DefaultSourceSection) obj;
- if (charIndex != other.charIndex) {
- return false;
- }
- if (charLength != other.charLength) {
- return false;
- }
- if (identifier == null) {
- if (other.identifier != null) {
- return false;
- }
- } else if (!identifier.equals(other.identifier)) {
- return false;
- }
- if (source == null) {
- if (other.source != null) {
- return false;
- }
- } else if (!source.equals(other.source)) {
- return false;
- }
- if (startColumn != other.startColumn) {
- return false;
- }
- if (startLine != other.startLine) {
- return false;
- }
- return true;
- }
-
-}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Wed May 21 11:45:50 2014 +0200
@@ -31,29 +31,29 @@
import com.oracle.truffle.api.nodes.*;
/**
- * A receiver of Truffle AST {@link ExecutionEvents}, propagated from a {@link Probe} to which the
- * instrument is attached, for the benefit of associated tools.
+ * A receiver of Truffle AST runtime {@link ExecutionEvents}, propagated from the {@link Probe} to
+ * which the instrument is attached, for the benefit of associated tools.
*
- * Guidelines for implementing Instruments, with particular attention to avoiding undesired runtime
+ * Guidelines for implementing {@link Instrument}s, with particular attention to minimize runtime
* performance overhead:
*
- * - Extend {@link Instrument} and override only the event handling methods for which some action
- * is needed.
+ * - Extend this abstract class and override only the {@linkplain ExecutionEvents event handling
+ * methods} for which intervention is needed.
* - Instruments are Truffle {@link Node}s and should be coded as much as possible in the desired
* Truffle style, documented more thoroughly elsewhere.
* - Maintain as little state as possible.
- * - If state is necessary, make it {@code final} if possible.
- * - If non-final state is necessary, annotate it as {@link CompilationFinal} and call
- * {@linkplain InstrumentationNode#notifyProbeChanged(Instrument)} whenever it is modified.
+ * - If state is necessary, make object fields {@code final} if at all possible.
+ * - If non-final object-valued state is necessary, annotate it as {@link CompilationFinal} and
+ * call {@linkplain InstrumentationNode#notifyProbeChanged(Instrument)} whenever it is modified.
* - Never store a {@link Frame} value in a field.
* - Minimize computation in standard execution paths.
- * - Callbacks to tools should be made via callbacks provided at construction and stored in
- * {@code final} fields.
- * - Tool callback methods should usually be annotated as {@link SlowPath} to prevent them from
- * being inlined into fast execution paths.
- * - If computation is needed, and if performance is important, then the computation is best
- * expressed as a guest language AST and evaluated using standard Truffle mechanisms so that
- * standard Truffle optimizations can be applied.
+ * - If runtime calls must be made back to a tool, construct the instrument with a callback stored
+ * in a {@code final} field.
+ * - Tool methods called by the instrument should be annotated as {@link SlowPath} to prevent them
+ * from being inlined into fast execution paths.
+ * - If computation in the execution path is needed, and if performance is important, then the
+ * computation is best expressed as a guest language AST and evaluated using standard Truffle
+ * mechanisms so that standard Truffle optimizations can be applied.
*
*
* Guidelines for attachment to a {@link Probe}:
@@ -65,6 +65,18 @@
* every copy, and so the Instrument will receive events corresponding to the intended syntactic
* unit of code, independent of which AST copy is being executed.
*
+ *
+ * Guidelines for handling {@link ExecutionEvents}:
+ *
+ * - Separate event methods are defined for each kind of possible return: object-valued,
+ * primitive-valued, void-valued, and exceptional.
+ * - Override "leave*" primitive methods if the language implementation returns primitives and the
+ * instrument should avoid boxing them.
+ * - On the other hand, if boxing all primitives for instrumentation is desired, it is only
+ * necessary to override the object-valued return methods, since the default implementation of each
+ * primitive-valued return method is to box the value and forward it to the object-valued return
+ * method.
+ *
*
*
* Disclaimer: experimental; under development.
@@ -72,7 +84,7 @@
* @see Probe
* @see ASTNodeProber
*/
-public class Instrument extends InstrumentationNode {
+public abstract class Instrument extends InstrumentationNode {
protected Instrument() {
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Wed May 21 11:45:50 2014 +0200
@@ -25,8 +25,6 @@
package com.oracle.truffle.api.instrument;
import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
/**
* A collector of {@link ExecutionEvents} at a specific site (node) in a Truffle AST (generated by a
@@ -54,7 +52,7 @@
* @see Instrument
* @see Wrapper
*/
-public interface Probe extends PhylumTagged {
+public interface Probe extends ExecutionEvents, PhylumTagged {
/**
* The source location with which this probe is (presumably uniquely) associated.
@@ -77,66 +75,4 @@
*/
void removeInstrument(Instrument oldInstrument);
- // TODO (mlvdv) migrate the remaining methods to another interface.
-
- /**
- * @see ExecutionEvents#enter(Node, VirtualFrame)
- */
- void notifyEnter(Node astNode, VirtualFrame frame);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame)
- */
- void notifyLeave(Node astNode, VirtualFrame frame);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame, boolean)
- */
- void notifyLeave(Node astNode, VirtualFrame frame, boolean result);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame, byte)
- */
- void notifyLeave(Node astNode, VirtualFrame frame, byte result);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame, short)
- */
- void notifyLeave(Node astNode, VirtualFrame frame, short result);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame, int)
- */
- void notifyLeave(Node astNode, VirtualFrame frame, int result);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame, long)
- */
- void notifyLeave(Node astNode, VirtualFrame frame, long result);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame, char)
- */
- void notifyLeave(Node astNode, VirtualFrame frame, char result);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame, float)
- */
- void notifyLeave(Node astNode, VirtualFrame frame, float result);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame, double)
- */
- void notifyLeave(Node astNode, VirtualFrame frame, double result);
-
- /**
- * @see ExecutionEvents#leave(Node, VirtualFrame, Object)
- */
- void notifyLeave(Node astNode, VirtualFrame frame, Object result);
-
- /**
- * @see ExecutionEvents#leaveExceptional(Node, VirtualFrame, Exception)
- */
- void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e);
-
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceCallback.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceCallback.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Instrumentation callback for guest language source-related events.
+ */
+public interface SourceCallback {
+
+ public void startLoading(Source source);
+
+ public void endLoading(Source source);
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java Wed May 21 11:45:50 2014 +0200
@@ -61,7 +61,7 @@
/**
* Converts a value in the guest language to a display string.
*/
- String displayValue(Object value);
+ String displayValue(ExecutionContext context, Object value);
/**
* Converts a slot identifier in the guest language to a display string.
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java Wed May 21 11:45:50 2014 +0200
@@ -77,13 +77,14 @@
}
if (node instanceof PhylumTagged) {
final PhylumTagged taggedNode = (PhylumTagged) node;
+ p.print("[");
String prefix = "";
for (PhylumTag tag : taggedNode.getPhylumTags()) {
p.print(prefix);
prefix = ",";
p.print(tag.toString());
}
-
+ p.print("]");
}
ArrayList childFields = new ArrayList<>();
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Wed May 21 11:45:50 2014 +0200
@@ -69,7 +69,7 @@
return callTarget.toString();
}
- public String displayValue(Object value) {
+ public String displayValue(ExecutionContext context, Object value) {
return value.toString();
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java Wed May 21 11:45:50 2014 +0200
@@ -39,7 +39,7 @@
*/
public abstract class InstrumentationNode extends Node implements ExecutionEvents {
- public interface ProbeCallback {
+ interface ProbeCallback {
void newTagAdded(ProbeImpl probe, PhylumTag tag);
}
@@ -49,7 +49,7 @@
*
* @return a new probe
*/
- public static ProbeImpl createProbe(SourceSection sourceSection, ProbeCallback probeCallback) {
+ static ProbeImpl createProbe(SourceSection sourceSection, ProbeCallback probeCallback) {
return new ProbeImpl(sourceSection, probeCallback);
}
@@ -64,7 +64,7 @@
/**
* @return the instance of {@link Probe} to which this instrument is attached.
*/
- public Probe getProbe() {
+ protected Probe getProbe() {
final InstrumentationNode parent = (InstrumentationNode) getParent();
return parent == null ? null : parent.getProbe();
}
@@ -199,7 +199,7 @@
* May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful
* for instrumentation about its AST location(s).
*/
- public static final class ProbeImpl extends InstrumentationNode implements Probe {
+ static final class ProbeImpl extends InstrumentationNode implements Probe {
private final ProbeCallback probeCallback;
@@ -259,7 +259,7 @@
}
@Override
- public Probe getProbe() {
+ protected Probe getProbe() {
return this;
}
@@ -271,14 +271,14 @@
}
@SlowPath
- public void setTrap(PhylumTrap trap) {
+ void setTrap(PhylumTrap trap) {
assert trap == null || isTaggedAs(trap.getTag());
probeUnchanged.invalidate();
this.trap = trap;
probeUnchanged = Truffle.getRuntime().createAssumption();
}
- public void notifyEnter(Node astNode, VirtualFrame frame) {
+ public void enter(Node astNode, VirtualFrame frame) {
if (trap != null || next != null) {
if (!probeUnchanged.isValid()) {
CompilerDirectives.transferToInterpreter();
@@ -292,7 +292,7 @@
}
}
- public void notifyLeave(Node astNode, VirtualFrame frame) {
+ public void leave(Node astNode, VirtualFrame frame) {
if (next != null) {
if (!probeUnchanged.isValid()) {
CompilerDirectives.transferToInterpreter();
@@ -301,16 +301,7 @@
}
}
- public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) {
- if (next != null) {
- if (!probeUnchanged.isValid()) {
- CompilerDirectives.transferToInterpreter();
- }
- next.internalLeave(astNode, frame, result);
- }
- }
-
- public void notifyLeave(Node astNode, VirtualFrame frame, byte result) {
+ public void leave(Node astNode, VirtualFrame frame, boolean result) {
if (next != null) {
if (!probeUnchanged.isValid()) {
CompilerDirectives.transferToInterpreter();
@@ -319,16 +310,7 @@
}
}
- public void notifyLeave(Node astNode, VirtualFrame frame, short result) {
- if (next != null) {
- if (!probeUnchanged.isValid()) {
- CompilerDirectives.transferToInterpreter();
- }
- next.internalLeave(astNode, frame, result);
- }
- }
-
- public void notifyLeave(Node astNode, VirtualFrame frame, int result) {
+ public void leave(Node astNode, VirtualFrame frame, byte result) {
if (next != null) {
if (!probeUnchanged.isValid()) {
CompilerDirectives.transferToInterpreter();
@@ -337,7 +319,7 @@
}
}
- public void notifyLeave(Node astNode, VirtualFrame frame, long result) {
+ public void leave(Node astNode, VirtualFrame frame, short result) {
if (next != null) {
if (!probeUnchanged.isValid()) {
CompilerDirectives.transferToInterpreter();
@@ -346,16 +328,7 @@
}
}
- public void notifyLeave(Node astNode, VirtualFrame frame, char result) {
- if (next != null) {
- if (!probeUnchanged.isValid()) {
- CompilerDirectives.transferToInterpreter();
- }
- next.internalLeave(astNode, frame, result);
- }
- }
-
- public void notifyLeave(Node astNode, VirtualFrame frame, float result) {
+ public void leave(Node astNode, VirtualFrame frame, int result) {
if (next != null) {
if (!probeUnchanged.isValid()) {
CompilerDirectives.transferToInterpreter();
@@ -364,7 +337,16 @@
}
}
- public void notifyLeave(Node astNode, VirtualFrame frame, double result) {
+ public void leave(Node astNode, VirtualFrame frame, long result) {
+ if (next != null) {
+ if (!probeUnchanged.isValid()) {
+ CompilerDirectives.transferToInterpreter();
+ }
+ next.internalLeave(astNode, frame, result);
+ }
+ }
+
+ public void leave(Node astNode, VirtualFrame frame, char result) {
if (next != null) {
if (!probeUnchanged.isValid()) {
CompilerDirectives.transferToInterpreter();
@@ -373,7 +355,7 @@
}
}
- public void notifyLeave(Node astNode, VirtualFrame frame, Object result) {
+ public void leave(Node astNode, VirtualFrame frame, float result) {
if (next != null) {
if (!probeUnchanged.isValid()) {
CompilerDirectives.transferToInterpreter();
@@ -382,7 +364,25 @@
}
}
- public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+ public void leave(Node astNode, VirtualFrame frame, double result) {
+ if (next != null) {
+ if (!probeUnchanged.isValid()) {
+ CompilerDirectives.transferToInterpreter();
+ }
+ next.internalLeave(astNode, frame, result);
+ }
+ }
+
+ public void leave(Node astNode, VirtualFrame frame, Object result) {
+ if (next != null) {
+ if (!probeUnchanged.isValid()) {
+ CompilerDirectives.transferToInterpreter();
+ }
+ next.internalLeave(astNode, frame, result);
+ }
+ }
+
+ public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
if (next != null) {
if (!probeUnchanged.isValid()) {
CompilerDirectives.transferToInterpreter();
@@ -391,50 +391,6 @@
}
}
- public void enter(Node astNode, VirtualFrame frame) {
- }
-
- public void leave(Node astNode, VirtualFrame frame) {
- }
-
- public void leave(Node astNode, VirtualFrame frame, boolean result) {
- leave(astNode, frame, (Object) result);
- }
-
- public void leave(Node astNode, VirtualFrame frame, byte result) {
- leave(astNode, frame, (Object) result);
- }
-
- public void leave(Node astNode, VirtualFrame frame, short result) {
- leave(astNode, frame, (Object) result);
- }
-
- public void leave(Node astNode, VirtualFrame frame, int result) {
- leave(astNode, frame, (Object) result);
- }
-
- public void leave(Node astNode, VirtualFrame frame, long result) {
- leave(astNode, frame, (Object) result);
- }
-
- public void leave(Node astNode, VirtualFrame frame, char result) {
- leave(astNode, frame, (Object) result);
- }
-
- public void leave(Node astNode, VirtualFrame frame, float result) {
- leave(astNode, frame, (Object) result);
- }
-
- public void leave(Node astNode, VirtualFrame frame, double result) {
- leave(astNode, frame, (Object) result);
- }
-
- public void leave(Node astNode, VirtualFrame frame, Object result) {
- }
-
- public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
- }
-
}
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java Wed May 21 11:45:50 2014 +0200
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument.impl;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeCallback;
+import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeImpl;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * Factory and services for AST {@link Probe}s
+ */
+public final class ProbeManager {
+
+ // TODO (mlvdv) use weak references.
+ /**
+ * Map: SourceSection ==> probe associated with that source section in an AST.
+ */
+ private final Map srcToProbe = new HashMap<>();
+
+ // TODO (mlvdv) use weak references.
+ /**
+ * Map: Source line ==> probes associated with source sections starting on the line.
+ */
+ private final Map> lineToProbes = new HashMap<>();
+
+ private final List probeListeners = new ArrayList<>();
+
+ private final ProbeCallback probeCallback;
+
+ /**
+ * When non-null, "enter" events with matching tags will trigger a callback.
+ */
+ private PhylumTrap phylumTrap = null;
+
+ public ProbeManager() {
+ this.probeCallback = new ProbeCallback() {
+ /**
+ * Receives (from the {@link Probe} implementation) and distributes notification that a
+ * {@link Probe} has acquired a new {@linkplain PhylumTag tag}.
+ */
+ public void newTagAdded(ProbeImpl probe, PhylumTag tag) {
+ for (ProbeListener listener : probeListeners) {
+ listener.probeTaggedAs(probe, tag);
+ }
+ if (phylumTrap != null && tag == phylumTrap.getTag()) {
+ probe.setTrap(phylumTrap);
+ }
+ }
+ };
+ }
+
+ public void addProbeListener(ProbeListener listener) {
+ assert listener != null;
+ probeListeners.add(listener);
+ }
+
+ public Probe getProbe(SourceSection sourceSection) {
+ assert sourceSection != null;
+
+ ProbeImpl probe = srcToProbe.get(sourceSection);
+
+ if (probe != null) {
+ return probe;
+ }
+ probe = InstrumentationNode.createProbe(sourceSection, probeCallback);
+
+ // Register new probe by unique SourceSection
+ srcToProbe.put(sourceSection, probe);
+
+ // Register new probe by source line, there may be more than one
+ // Create line location for map key
+ final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine());
+
+ Collection probes = lineToProbes.get(lineLocation);
+ if (probes == null) {
+ probes = new ArrayList<>(2);
+ lineToProbes.put(lineLocation, probes);
+ }
+ probes.add(probe);
+
+ for (ProbeListener listener : probeListeners) {
+ listener.newProbeInserted(sourceSection, probe);
+ }
+
+ return probe;
+ }
+
+ public Collection findProbesTaggedAs(PhylumTag tag) {
+ final List probes = new ArrayList<>();
+ for (Probe probe : srcToProbe.values()) {
+ if (tag == null || probe.isTaggedAs(tag)) {
+ probes.add(probe);
+ }
+ }
+ return probes;
+ }
+
+ public Collection findProbesByLine(SourceLineLocation lineLocation) {
+ final Collection probes = lineToProbes.get(lineLocation);
+ if (probes == null) {
+ return Collections.emptyList();
+ }
+ return new ArrayList<>(probes);
+ }
+
+ public void setPhylumTrap(PhylumTrap trap) {
+ assert trap != null;
+ if (this.phylumTrap != null) {
+ throw new IllegalStateException("trap already set");
+ }
+ this.phylumTrap = trap;
+
+ PhylumTag tag = trap.getTag();
+ for (ProbeImpl probe : srcToProbe.values()) {
+ if (probe.isTaggedAs(tag)) {
+ probe.setTrap(trap);
+ }
+ }
+ }
+
+ public void clearPhylumTrap() {
+ if (this.phylumTrap == null) {
+ throw new IllegalStateException("no trap set");
+ }
+ for (ProbeImpl probe : srcToProbe.values()) {
+ if (probe.isTaggedAs(phylumTrap.getTag())) {
+ probe.setTrap(null);
+ }
+ }
+ phylumTrap = null;
+ }
+
+}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SourceCallback.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SourceCallback.java Tue May 13 19:19:27 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument.impl;
-
-import com.oracle.truffle.api.*;
-
-/**
- * Instrumentation callback for guest language source-related events.
- */
-public interface SourceCallback {
-
- public void startLoading(Source source);
-
- public void endLoading(Source source);
-}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed May 21 11:45:50 2014 +0200
@@ -506,4 +506,31 @@
throw new RuntimeException(e);
}
}
+
+ /**
+ * Returns a user-readable description of the purpose of the Node, or "" if no description is
+ * available.
+ */
+ public String getDescription() {
+ NodeInfo info = getClass().getAnnotation(NodeInfo.class);
+ if (info != null) {
+ return info.description();
+ }
+ return "";
+ }
+
+ /**
+ * Returns a string representing the language this node has been implemented for. If the
+ * language is unknown, returns "".
+ */
+ public String getLanguage() {
+ NodeInfo info = getClass().getAnnotation(NodeInfo.class);
+ if (info != null && info.language() != null && info.language().length() > 0) {
+ return info.language();
+ }
+ if (parent != null) {
+ return parent.getLanguage();
+ }
+ return "";
+ }
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java Wed May 21 11:45:50 2014 +0200
@@ -35,7 +35,7 @@
/**
* Short name representing the node that can be used for debugging.
- *
+ *
* @return the short name
*/
String shortName() default "";
@@ -43,10 +43,26 @@
/**
* Provides a rough estimate for the cost of the annotated {@link Node}. This estimate can be
* used by runtime systems or guest languages to implement heuristics based on Truffle ASTs.
- *
+ *
* @see Node#getCost()
* @see NodeCost
*/
NodeCost cost() default NodeCost.MONOMORPHIC;
+ /**
+ * A human readable explanation of the purpose of the annotated {@link Node}. Can be used e.g.
+ * for debugging or visualization purposes.
+ *
+ * @return the description
+ */
+ String description() default "";
+
+ /**
+ * A description, providing a user-readable explanation of the source language of the annotated
+ * {@link Node}. Can be used e.g. for debugging or visualization purposes. Typically this
+ * information is set only in an abstract base node for the language implementation.
+ *
+ * @return the description
+ */
+ String language() default "";
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java Wed May 21 11:45:50 2014 +0200
@@ -199,6 +199,32 @@
return checkTextMap().lineLength(lineNumber);
}
+ public final SourceSection createSection(String identifier, int startOffset, int sectionLength) throws IllegalArgumentException {
+ final int codeLength = getCode().length();
+ if (!(startOffset >= 0 && sectionLength >= 0 && startOffset + sectionLength <= codeLength)) {
+ throw new IllegalArgumentException("text positions out of range");
+ }
+ checkTextMap();
+ final int startLine = getLineNumber(startOffset);
+ final int startColumn = startOffset - getLineStartOffset(startLine) + 1;
+
+ return new SourceSectionImpl(this, identifier, startLine, startColumn, startOffset, sectionLength);
+ }
+
+ public SourceSection createSection(String identifier, int startLine, int startColumn, int sectionLength) {
+ checkTextMap();
+ final int lineStartOffset = textMap.lineStartOffset(startLine);
+ if (startColumn > textMap.lineLength(startLine)) {
+ throw new IllegalArgumentException("column out of range");
+ }
+ final int startOffset = lineStartOffset + startColumn - 1;
+ return new SourceSectionImpl(this, identifier, startLine, startColumn, startOffset, sectionLength);
+ }
+
+ public SourceSection createSection(String identifier, int startLine, int startColumn, int charIndex, int length) {
+ return new SourceSectionImpl(this, identifier, startLine, startColumn, charIndex, length);
+ }
+
private TextMap checkTextMap() {
if (textMap == null) {
final String code = getCode();
@@ -211,7 +237,7 @@
}
}
- public static class LiteralSourceImpl extends SourceImpl {
+ private static class LiteralSourceImpl extends SourceImpl {
private final String name; // Name used originally to describe the source
private final String code;
@@ -337,4 +363,142 @@
}
+ private static class SourceSectionImpl implements SourceSection {
+
+ private final Source source;
+ private final String identifier;
+ private final int startLine;
+ private final int startColumn;
+ private final int charIndex;
+ private final int charLength;
+
+ /**
+ * Creates a new object representing a contiguous text section within the source code of a
+ * guest language program's text.
+ *
+ * The starting location of the section is specified using two different coordinate:
+ *
+ * - (row, column): rows and columns are 1-based, so the first character in a
+ * source file is at position {@code (1,1)}.
+ * - character index: 0-based offset of the character from the beginning of the
+ * source, so the first character in a file is at index {@code 0}.
+ *
+ * The newline that terminates each line counts as a single character for the purpose
+ * of a character index. The (row,column) coordinates of a newline character should never
+ * appear in a text section.
+ *
+ *
+ * @param source object representing the complete source program that contains this section
+ * @param identifier an identifier used when printing the section
+ * @param startLine the 1-based number of the start line of the section
+ * @param startColumn the 1-based number of the start column of the section
+ * @param charIndex the 0-based index of the first character of the section
+ * @param charLength the length of the section in number of characters
+ */
+ public SourceSectionImpl(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) {
+ this.source = source;
+ this.identifier = identifier;
+ this.startLine = startLine;
+ this.startColumn = startColumn;
+ this.charIndex = charIndex;
+ this.charLength = charLength;
+ }
+
+ public final Source getSource() {
+ return source;
+ }
+
+ public final int getStartLine() {
+ return startLine;
+ }
+
+ public final int getStartColumn() {
+ return startColumn;
+ }
+
+ public final int getCharIndex() {
+ return charIndex;
+ }
+
+ public final int getCharLength() {
+ return charLength;
+ }
+
+ public final int getCharEndIndex() {
+ return charIndex + charLength;
+ }
+
+ public final String getIdentifier() {
+ return identifier;
+ }
+
+ public final String getCode() {
+ return getSource().getCode().substring(charIndex, charIndex + charLength);
+ }
+
+ public final String getShortDescription() {
+ return String.format("%s:%d", source.getShortName(), startLine);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s:%d", source.getName(), startLine);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + charIndex;
+ result = prime * result + charLength;
+ result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
+ result = prime * result + ((source == null) ? 0 : source.hashCode());
+ result = prime * result + startColumn;
+ result = prime * result + startLine;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof SourceSectionImpl)) {
+ return false;
+ }
+ SourceSectionImpl other = (SourceSectionImpl) obj;
+ if (charIndex != other.charIndex) {
+ return false;
+ }
+ if (charLength != other.charLength) {
+ return false;
+ }
+ if (identifier == null) {
+ if (other.identifier != null) {
+ return false;
+ }
+ } else if (!identifier.equals(other.identifier)) {
+ return false;
+ }
+ if (source == null) {
+ if (other.source != null) {
+ return false;
+ }
+ } else if (!source.equals(other.source)) {
+ return false;
+ }
+ if (startColumn != other.startColumn) {
+ return false;
+ }
+ if (startLine != other.startLine) {
+ return false;
+ }
+ return true;
+ }
+
+ }
+
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java Wed May 21 11:45:50 2014 +0200
@@ -112,7 +112,7 @@
/**
* Support JDK8 langtools.
- *
+ *
* @param annotationType
*/
public A[] getAnnotationsByType(Class annotationType) {
@@ -121,7 +121,7 @@
/**
* Support for some JDK8 builds. (remove after jdk8 is released)
- *
+ *
* @param annotationType
*/
public A[] getAnnotations(Class annotationType) {
@@ -130,7 +130,7 @@
/**
* Support for some JDK8 builds. (remove after jdk8 is released)
- *
+ *
* @param annotationType
*/
public A getAnnotation(Class annotationType) {
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java Wed May 21 11:45:50 2014 +0200
@@ -35,6 +35,7 @@
* type system for all subclasses.
*/
@TypeSystemReference(SLTypes.class)
+@NodeInfo(description = "The abstract base node for all expressions")
public abstract class SLExpressionNode extends SLStatementNode {
/**
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed May 21 11:45:50 2014 +0200
@@ -33,6 +33,7 @@
* builtin functions, the {@link #bodyNode} is a subclass of {@link SLBuiltinNode}. For user-defined
* functions, the {@link #bodyNode} is a {@link SLFunctionBodyNode}.
*/
+@NodeInfo(language = "Simple Language", description = "The root of all Simple Language execution trees")
public final class SLRootNode extends RootNode {
/** The function body that is executed, and specialized during execution. */
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java Wed May 21 11:45:50 2014 +0200
@@ -30,6 +30,7 @@
* statements, i.e., without returning a value. The {@link VirtualFrame} provides access to the
* local variables.
*/
+@NodeInfo(language = "Simple Language", description = "The abstract base node for all statements")
public abstract class SLStatementNode extends Node {
/**
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Wed May 21 11:45:50 2014 +0200
@@ -30,7 +30,7 @@
/**
* A statement node that just executes a list of other statements.
*/
-@NodeInfo(shortName = "block")
+@NodeInfo(shortName = "block", description = "The node implementing a source code block")
public final class SLBlockNode extends SLStatementNode {
/**
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java Wed May 21 11:45:50 2014 +0200
@@ -32,7 +32,7 @@
* breaking out. This is done by throwing an {@link SLBreakException exception} that is caught by
* the {@link SLWhileNode#executeVoid loop node}.
*/
-@NodeInfo(shortName = "break")
+@NodeInfo(shortName = "break", description = "The node implementing a break statement")
public final class SLBreakNode extends SLStatementNode {
@Override
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java Wed May 21 11:45:50 2014 +0200
@@ -32,7 +32,7 @@
* are continuing. This is done by throwing an {@link SLContinueException exception} that is caught
* by the {@link SLWhileNode#executeVoid loop node}.
*/
-@NodeInfo(shortName = "continue")
+@NodeInfo(shortName = "continue", description = "The node implementing a continue statement")
public final class SLContinueNode extends SLStatementNode {
@Override
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Wed May 21 11:45:50 2014 +0200
@@ -28,7 +28,7 @@
import com.oracle.truffle.api.utilities.*;
import com.oracle.truffle.sl.nodes.*;
-@NodeInfo(shortName = "if")
+@NodeInfo(shortName = "if", description = "The node implementing a condional statement")
public final class SLIfNode extends SLStatementNode {
/**
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java Wed May 21 11:45:50 2014 +0200
@@ -34,7 +34,7 @@
* caught by the {@link SLFunctionBodyNode#executeGeneric function body}. The exception transports
* the return value.
*/
-@NodeInfo(shortName = "return")
+@NodeInfo(shortName = "return", description = "The node implementing a return statement")
public final class SLReturnNode extends SLStatementNode {
@Child private SLExpressionNode valueNode;
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java Wed May 21 11:45:50 2014 +0200
@@ -29,7 +29,7 @@
import com.oracle.truffle.api.utilities.*;
import com.oracle.truffle.sl.nodes.*;
-@NodeInfo(shortName = "while")
+@NodeInfo(shortName = "while", description = "The node implementing a while loop")
public final class SLWhileNode extends SLStatementNode {
/**
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Wed May 21 11:45:50 2014 +0200
@@ -25,6 +25,7 @@
import java.math.*;
import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.*;
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.nodes.*;
import com.oracle.truffle.sl.nodes.*;
@@ -41,6 +42,7 @@
}
@Specialization
+ @SlowPath
protected BigInteger mul(BigInteger left, BigInteger right) {
return left.multiply(right);
}
diff -r a43ff5d18350 -r a6eeb3750238 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java Tue May 13 19:19:27 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java Wed May 21 11:45:50 2014 +0200
@@ -27,7 +27,6 @@
import com.oracle.truffle.api.*;
import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.impl.*;
import com.oracle.truffle.api.nodes.*;
import com.oracle.truffle.sl.nodes.*;
import com.oracle.truffle.sl.nodes.call.*;
@@ -243,7 +242,7 @@
int startLine = t.line;
int startColumn = t.col;
int charLength = t.val.length();
- SourceSection sourceSection = new DefaultSourceSection(source, functionName, startLine, startColumn, 0, charLength);
+ SourceSection sourceSection = source.createSection(functionName, startLine, startColumn, 0, charLength);
node.assignSourceSection(sourceSection);
return node;
diff -r a43ff5d18350 -r a6eeb3750238 make/bsd/makefiles/vm.make
--- a/make/bsd/makefiles/vm.make Tue May 13 19:19:27 2014 +0200
+++ b/make/bsd/makefiles/vm.make Wed May 21 11:45:50 2014 +0200
@@ -229,6 +229,7 @@
else
GRAAL_SPECIFIC_FILES :=
GRAAL_SPECIFIC_GPU_FILES :=
+ Src_Dirs_I += $(HS_COMMON_SRC)/../graal/com.oracle.graal.hotspot/src_gen/hotspot
endif
# Always exclude these.
diff -r a43ff5d18350 -r a6eeb3750238 make/linux/makefiles/vm.make
--- a/make/linux/makefiles/vm.make Tue May 13 19:19:27 2014 +0200
+++ b/make/linux/makefiles/vm.make Wed May 21 11:45:50 2014 +0200
@@ -211,6 +211,7 @@
else
GRAAL_SPECIFIC_FILES :=
GRAAL_SPECIFIC_GPU_FILES :=
+ Src_Dirs_I += $(HS_COMMON_SRC)/../graal/com.oracle.graal.hotspot/src_gen/hotspot
endif
# Always exclude these.
diff -r a43ff5d18350 -r a6eeb3750238 make/solaris/makefiles/vm.make
--- a/make/solaris/makefiles/vm.make Tue May 13 19:19:27 2014 +0200
+++ b/make/solaris/makefiles/vm.make Wed May 21 11:45:50 2014 +0200
@@ -229,6 +229,7 @@
else
GRAAL_SPECIFIC_FILES :=
GRAAL_SPECIFIC_GPU_FILES :=
+ Src_Dirs_I += $(HS_COMMON_SRC)/../graal/com.oracle.graal.hotspot/src_gen/hotspot
endif
# Always exclude these.
diff -r a43ff5d18350 -r a6eeb3750238 make/windows/makefiles/projectcreator.make
--- a/make/windows/makefiles/projectcreator.make Tue May 13 19:19:27 2014 +0200
+++ b/make/windows/makefiles/projectcreator.make Wed May 21 11:45:50 2014 +0200
@@ -57,6 +57,7 @@
-relativeInclude src\os_cpu\windows_$(Platform_arch)\vm \
-relativeInclude src\cpu\$(Platform_arch)\vm \
-relativeInclude src\gpu \
+ -relativeInclude graal\com.oracle.graal.hotspot\src_gen\hotspot \
-absoluteInclude $(HOTSPOTBUILDSPACE)/%f/generated \
-relativeSrcInclude src \
-absoluteSrcInclude $(HOTSPOTBUILDSPACE) \
@@ -151,7 +152,7 @@
ProjectCreatorIDEOptionsIgnoreGraal=\
-ignorePath_TARGET src/share/vm/graal \
- -ignorePath_TARGET graal/generated \
+ -ignorePath_TARGET graal\com.oracle.graal.hotspot\src_gen\hotspot \
-ignorePath_TARGET vm/graal
ProjectCreatorIDEOptionsIgnoreCompiler2=\
@@ -175,7 +176,6 @@
ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \
-define_compiler1 COMPILER1 \
-define_compiler1 GRAAL \
- -ignorePath_compiler1 graal/generated \
$(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=compiler1)
##################################################
@@ -195,7 +195,6 @@
-define_compiler2 COMPILER1 \
-define_compiler2 COMPILER2 \
-define_compiler2 GRAAL \
- -ignorePath_compiler2 graal/generated \
-additionalFile_compiler2 $(Platform_arch_model).ad \
-additionalFile_compiler2 ad_$(Platform_arch_model).cpp \
-additionalFile_compiler2 ad_$(Platform_arch_model).hpp \
diff -r a43ff5d18350 -r a6eeb3750238 mx/mx_graal.py
--- a/mx/mx_graal.py Tue May 13 19:19:27 2014 +0200
+++ b/mx/mx_graal.py Wed May 21 11:45:50 2014 +0200
@@ -690,7 +690,7 @@
mustBuild = False
timestamp = os.path.getmtime(timestampFile)
sources = []
- for d in ['src', 'make']:
+ for d in ['src', 'make', 'graal/com.oracle.graal.hotspot/src_gen/hotspot']:
for root, dirnames, files in os.walk(join(_graal_home, d)):
# ignore /src/share/tools
if root == join(_graal_home, 'src', 'share'):
@@ -957,7 +957,7 @@
f_testfile.close()
harness(projectscp, vmArgs)
-def _unittest(args, annotations, prefixcp="", whitelist=None, verbose=False, enable_timing=False, regex=None):
+def _unittest(args, annotations, prefixcp="", whitelist=None, verbose=False, enable_timing=False, regex=None, color=False, eager_stacktrace=False):
mxdir = dirname(__file__)
name = 'JUnitWrapper'
javaSource = join(mxdir, name + '.java')
@@ -976,6 +976,10 @@
coreArgs.append('-JUnitVerbose')
if enable_timing:
coreArgs.append('-JUnitEnableTiming')
+ if color:
+ coreArgs.append('-JUnitColor')
+ if eager_stacktrace:
+ coreArgs.append('-JUnitEagerStackTrace')
def harness(projectscp, vmArgs):
@@ -1006,6 +1010,8 @@
--verbose enable verbose JUnit output
--enable-timing enable JUnit test timing
--regex run only testcases matching a regular expression
+ --color enable colors output
+ --eager-stacktrace print stacktrace eagerly
To avoid conflicts with VM options '--' can be used as delimiter.
@@ -1046,6 +1052,8 @@
parser.add_argument('--verbose', help='enable verbose JUnit output', action='store_true')
parser.add_argument('--enable-timing', help='enable JUnit test timing', action='store_true')
parser.add_argument('--regex', help='run only testcases matching a regular expression', metavar='')
+ parser.add_argument('--color', help='enable color output', action='store_true')
+ parser.add_argument('--eager-stacktrace', help='print stacktrace eagerly', action='store_true')
ut_args = []
delimiter = False
@@ -1064,15 +1072,14 @@
# parse all know arguments
parsed_args, args = parser.parse_known_args(ut_args)
- whitelist = None
if parsed_args.whitelist:
try:
with open(join(_graal_home, parsed_args.whitelist)) as fp:
- whitelist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
+ parsed_args.whitelist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
except IOError:
mx.log('warning: could not read whitelist: ' + parsed_args.whitelist)
- _unittest(args, ['@Test', '@Parameters'], whitelist=whitelist, verbose=parsed_args.verbose, enable_timing=parsed_args.enable_timing, regex=parsed_args.regex)
+ _unittest(args, ['@Test', '@Parameters'], **parsed_args.__dict__)
def shortunittest(args):
"""alias for 'unittest --whitelist test/whitelist_shortunittest.txt'{0}"""
@@ -1535,7 +1542,7 @@
if not mx.library(name, fatalIfMissing=False):
mx.log('Skipping ' + groupId + '.' + artifactId + '.jar as ' + name + ' cannot be resolved')
return
- d = mx.Distribution(graalSuite, name=artifactId, path=path, sourcesPath=path, deps=deps, excludedDependencies=[])
+ d = mx.Distribution(graalSuite, name=artifactId, path=path, sourcesPath=path, deps=deps, excludedDependencies=[], distDependencies=[])
d.make_archive()
cmd = ['mvn', 'install:install-file', '-DgroupId=' + groupId, '-DartifactId=' + artifactId,
'-Dversion=1.0-SNAPSHOT', '-Dpackaging=jar', '-Dfile=' + d.path]
diff -r a43ff5d18350 -r a6eeb3750238 mx/projects
--- a/mx/projects Tue May 13 19:19:27 2014 +0200
+++ b/mx/projects Wed May 21 11:45:50 2014 +0200
@@ -2,8 +2,7 @@
mxversion=1.0
suite=graal
-library@JDK_TOOLS@path=${JAVA_HOME}/lib/tools.jar
-library@JDK_TOOLS@optional=true
+jrelibrary@JFR@jar=jfr.jar
library@JUNIT@path=lib/junit-4.11.jar
library@JUNIT@urls=http://repo1.maven.org/maven2/junit/junit/4.11/junit-4.11.jar
@@ -33,12 +32,12 @@
library@DACAPO@sha1=2626a9546df09009f6da0df854e6dc1113ef7dd4
library@JACOCOAGENT@path=lib/jacocoagent.jar
-library@JACOCOAGENT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoagent.jar
-library@JACOCOAGENT@sha1=9e2c835289356d86afbf31840f05a0f9007c4e44
+library@JACOCOAGENT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoagent-0.7.1-1.jar
+library@JACOCOAGENT@sha1=2f73a645b02e39290e577ce555f00b02004650b0
library@JACOCOREPORT@path=lib/jacocoreport.jar
-library@JACOCOREPORT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoreport.jar
-library@JACOCOREPORT@sha1=32fb5ba2f12d86c4feb74bcefc17a4e6fad8a323
+library@JACOCOREPORT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoreport-0.7.1-1.jar
+library@JACOCOREPORT@sha1=0c5db714804416dd1df4d8110762136ce3d5c7dc
library@DACAPO_SCALA@path=lib/dacapo-scala-0.1.0-20120216.jar
library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
@@ -75,6 +74,7 @@
com.oracle.graal.truffle.hotspot.amd64,\
com.oracle.graal.hotspot.sparc,\
com.oracle.graal.hotspot,\
+com.oracle.graal.hotspot.jfr,\
com.oracle.graal.hotspot.hsail
distribution@GRAAL@exclude=FINDBUGS
@@ -87,7 +87,7 @@
distribution@TRUFFLE-DSL-PROCESSOR@sourcesPath=truffle-dsl-processor-sources.jar
distribution@TRUFFLE-DSL-PROCESSOR@dependencies=\
com.oracle.truffle.dsl.processor
-distribution@TRUFFLE-DSL-PROCESSOR@distDependency=TRUFFLE
+distribution@TRUFFLE-DSL-PROCESSOR@distDependencies=TRUFFLE
# graal.api.collections
project@com.oracle.graal.api.collections@subDir=graal
@@ -182,15 +182,35 @@
project@com.oracle.graal.sparc@javaCompliance=1.8
project@com.oracle.graal.sparc@workingSets=Graal,SPARC
+# graal.hotspotvmconfig
+project@com.oracle.graal.hotspotvmconfig@subDir=graal
+project@com.oracle.graal.hotspotvmconfig@sourceDirs=src
+project@com.oracle.graal.hotspotvmconfig@dependencies=com.oracle.graal.compiler.common
+project@com.oracle.graal.hotspotvmconfig@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.hotspotvmconfig@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.hotspotvmconfig@annotationProcessorForDependents=true
+project@com.oracle.graal.hotspotvmconfig@javaCompliance=1.8
+project@com.oracle.graal.hotspotvmconfig@workingSets=Graal,HotSpot
+
# graal.hotspot
project@com.oracle.graal.hotspot@subDir=graal
project@com.oracle.graal.hotspot@sourceDirs=src
-project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.runtime,com.oracle.graal.printer,com.oracle.graal.baseline
+project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.runtime,com.oracle.graal.printer,com.oracle.graal.baseline,com.oracle.graal.hotspotvmconfig
project@com.oracle.graal.hotspot@checkstyle=com.oracle.graal.graph
project@com.oracle.graal.hotspot@annotationProcessors=com.oracle.graal.replacements.verifier,com.oracle.graal.service.processor
project@com.oracle.graal.hotspot@javaCompliance=1.8
project@com.oracle.graal.hotspot@workingSets=Graal,HotSpot
+# graal.hotspot.jfr
+project@com.oracle.graal.hotspot.jfr@subDir=graal
+project@com.oracle.graal.hotspot.jfr@sourceDirs=src
+project@com.oracle.graal.hotspot.jfr@dependencies=com.oracle.graal.hotspot,JFR
+project@com.oracle.graal.hotspot.jfr@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.hotspot.jfr@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.hotspot.jfr@javaCompliance=1.8
+project@com.oracle.graal.hotspot.jfr@profile=
+project@com.oracle.graal.hotspot.jfr@workingSets=Graal,HotSpot
+
# graal.hotspot.amd64
project@com.oracle.graal.hotspot.amd64@subDir=graal
project@com.oracle.graal.hotspot.amd64@sourceDirs=src
@@ -568,7 +588,7 @@
# graal.test
project@com.oracle.graal.test@subDir=graal
project@com.oracle.graal.test@sourceDirs=src
-project@com.oracle.graal.test@dependencies=JUNIT
+project@com.oracle.graal.test@dependencies=JUNIT,com.oracle.graal.debug
project@com.oracle.graal.test@checkstyle=com.oracle.graal.graph
project@com.oracle.graal.test@javaCompliance=1.8
project@com.oracle.graal.test@workingSets=Graal,Test
@@ -652,7 +672,7 @@
# graal.compiler.hsail.test.infra - HSAIL compiler test infrastructure
project@com.oracle.graal.compiler.hsail.test.infra@subDir=graal
project@com.oracle.graal.compiler.hsail.test.infra@sourceDirs=src
-project@com.oracle.graal.compiler.hsail.test.infra@dependencies=com.oracle.graal.hotspot.hsail,JUNIT,OKRA_WITH_SIM
+project@com.oracle.graal.compiler.hsail.test.infra@dependencies=com.oracle.graal.test,com.oracle.graal.hotspot.hsail,OKRA_WITH_SIM
project@com.oracle.graal.compiler.hsail.test.infra@checkstyle=com.oracle.graal.graph
project@com.oracle.graal.compiler.hsail.test.infra@javaCompliance=1.8
diff -r a43ff5d18350 -r a6eeb3750238 mxtool/mx.py
--- a/mxtool/mx.py Tue May 13 19:19:27 2014 +0200
+++ b/mxtool/mx.py Wed May 21 11:45:50 2014 +0200
@@ -49,6 +49,7 @@
_projects = dict()
_libs = dict()
+_jreLibs = dict()
_dists = dict()
_suites = dict()
_annotationProcessors = None
@@ -62,7 +63,7 @@
A distribution is a jar or zip file containing the output from one or more Java projects.
"""
class Distribution:
- def __init__(self, suite, name, path, sourcesPath, deps, excludedDependencies, distDependency):
+ def __init__(self, suite, name, path, sourcesPath, deps, excludedDependencies, distDependencies):
self.suite = suite
self.name = name
self.path = path.replace('/', os.sep)
@@ -71,7 +72,7 @@
self.deps = deps
self.update_listeners = set()
self.excludedDependencies = excludedDependencies
- self.distDependency = distDependency
+ self.distDependencies = distDependencies
def sorted_deps(self, includeLibs=False):
try:
@@ -123,18 +124,22 @@
for arcname in lp.namelist():
overwriteCheck(srcArc.zf, arcname, lpath + '!' + arcname)
srcArc.zf.writestr(arcname, lp.read(arcname))
- else:
+ elif dep.isProject():
p = dep
- if self.distDependency and p in _dists[self.distDependency].sorted_deps():
- logv("Excluding {0} from {1} because it's provided by the dependency {2}".format(p.name, self.path, self.distDependency))
+ isCoveredByDependecy = False
+ for d in self.distDependencies:
+ if p in _dists[d].sorted_deps():
+ logv("Excluding {0} from {1} because it's provided by the dependency {2}".format(p.name, self.path, d))
+ isCoveredByDependecy = True
+ break
+
+ if isCoveredByDependecy:
continue
# skip a Java project if its Java compliance level is "higher" than the configured JDK
jdk = java(p.javaCompliance)
- if not jdk:
- log('Excluding {0} from {2} (Java compliance level {1} required)'.format(p.name, p.javaCompliance, self.path))
- continue
+ assert jdk
logv('[' + self.path + ': adding project ' + p.name + ']')
outputDir = p.output_dir()
@@ -201,6 +206,9 @@
def isLibrary(self):
return isinstance(self, Library)
+ def isJreLibrary(self):
+ return isinstance(self, JreLibrary)
+
def isProject(self):
return isinstance(self, Project)
@@ -229,7 +237,7 @@
if not exists(s):
os.mkdir(s)
- def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False):
+ def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
"""
Add the transitive set of dependencies for this project, including
libraries if 'includeLibs' is true, to the 'deps' list.
@@ -242,8 +250,8 @@
for name in childDeps:
assert name != self.name
dep = dependency(name)
- if not dep in deps and (includeLibs or not dep.isLibrary()):
- dep.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+ if not dep in deps and (dep.isProject or (dep.isLibrary() and includeLibs) or (dep.isJreLibrary() and includeJreLibs)):
+ dep.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
if not self in deps and includeSelf:
deps.append(self)
return deps
@@ -506,17 +514,74 @@
return path
-class Library(Dependency):
- def __init__(self, suite, name, path, mustExist, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps):
+class BaseLibrary(Dependency):
+ def __init__(self, suite, name, optional):
Dependency.__init__(self, suite, name)
+ self.optional = optional
+
+ def __ne__(self, other):
+ result = self.__eq__(other)
+ if result is NotImplemented:
+ return result
+ return not result
+
+"""
+A library that will be provided by the JDK but may be absent.
+Any project or normal library that depends on a missing library
+will be removed from the global project and library dictionaries
+(i.e., _projects and _libs).
+
+This mechanism exists primarily to be able to support code
+that may use functionality in one JDK (e.g., Oracle JDK)
+that is not present in another JDK (e.g., OpenJDK). A
+motivating example is the Java Flight Recorder library
+found in the Oracle JDK.
+"""
+class JreLibrary(BaseLibrary):
+ def __init__(self, suite, name, jar, optional):
+ BaseLibrary.__init__(self, suite, name, optional)
+ self.jar = jar
+
+ def __eq__(self, other):
+ if isinstance(other, JreLibrary):
+ return self.jar == other.jar
+ else:
+ return NotImplemented
+
+ def is_present_in_jdk(self, jdk):
+ for e in jdk.bootclasspath().split(os.pathsep):
+ if basename(e) == self.jar:
+ return True
+ for d in jdk.extdirs().split(os.pathsep):
+ if len(d) and self.jar in os.listdir(d):
+ return True
+ for d in jdk.endorseddirs().split(os.pathsep):
+ if len(d) and self.jar in os.listdir(d):
+ return True
+ return False
+
+ def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
+ """
+ Add the transitive set of dependencies for this JRE library to the 'deps' list.
+ """
+ if includeJreLibs and includeSelf and not self in deps:
+ deps.append(self)
+ return deps
+
+class Library(BaseLibrary):
+ def __init__(self, suite, name, path, optional, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps):
+ BaseLibrary.__init__(self, suite, name, optional)
self.path = path.replace('/', os.sep)
self.urls = urls
self.sha1 = sha1
- self.mustExist = mustExist
self.sourcePath = sourcePath
self.sourceUrls = sourceUrls
self.sourceSha1 = sourceSha1
self.deps = deps
+ abspath = _make_absolute(self.path, self.suite.dir)
+ if not optional and not exists(abspath):
+ if not len(urls):
+ abort('Non-optional library {} must either exist at {} or specify one or more URLs from which it can be retrieved'.format(name, abspath))
for url in urls:
if url.endswith('/') != self.path.endswith(os.sep):
abort('Path for dependency directory must have a URL ending with "/": path=' + self.path + ' url=' + url)
@@ -530,14 +595,6 @@
else:
return NotImplemented
-
- def __ne__(self, other):
- result = self.__eq__(other)
- if result is NotImplemented:
- return result
- return not result
-
-
def get_path(self, resolve):
path = _make_absolute(self.path, self.suite.dir)
sha1path = path + '.sha1'
@@ -546,8 +603,7 @@
if includedInJDK and java().javaCompliance >= JavaCompliance(includedInJDK):
return None
- return _download_file_with_sha1(self.name, path, self.urls, self.sha1, sha1path, resolve, self.mustExist)
-
+ return _download_file_with_sha1(self.name, path, self.urls, self.sha1, sha1path, resolve, not self.optional)
def get_source_path(self, resolve):
if self.sourcePath is None:
@@ -562,7 +618,7 @@
if path and (exists(path) or not resolve):
cp.append(path)
- def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False):
+ def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
"""
Add the transitive set of dependencies for this library to the 'deps' list.
"""
@@ -575,7 +631,7 @@
assert name != self.name
dep = library(name)
if not dep in deps:
- dep.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+ dep.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
if not self in deps and includeSelf:
deps.append(self)
return deps
@@ -631,6 +687,7 @@
self.mxDir = mxDir
self.projects = []
self.libs = []
+ self.jreLibs = []
self.dists = []
self.commands = None
self.primary = primary
@@ -648,6 +705,7 @@
def _load_projects(self):
libsMap = dict()
+ jreLibsMap = dict()
projsMap = dict()
distsMap = dict()
projectsFile = join(self.mxDir, 'projects')
@@ -697,6 +755,8 @@
m = projsMap
elif kind == 'library':
m = libsMap
+ elif kind == 'jrelibrary':
+ m = jreLibsMap
elif kind == 'distribution':
m = distsMap
else:
@@ -737,16 +797,24 @@
p.__dict__.update(attrs)
self.projects.append(p)
+ for name, attrs in jreLibsMap.iteritems():
+ jar = attrs.pop('jar')
+ # JRE libraries are optional by default
+ optional = attrs.pop('optional', 'true') != 'false'
+ l = JreLibrary(self, name, jar, optional)
+ self.jreLibs.append(l)
+
for name, attrs in libsMap.iteritems():
path = attrs.pop('path')
- mustExist = attrs.pop('optional', 'false') != 'true'
urls = pop_list(attrs, 'urls')
sha1 = attrs.pop('sha1', None)
sourcePath = attrs.pop('sourcePath', None)
sourceUrls = pop_list(attrs, 'sourceUrls')
sourceSha1 = attrs.pop('sourceSha1', None)
deps = pop_list(attrs, 'dependencies')
- l = Library(self, name, path, mustExist, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps)
+ # Add support optional libraries once we have a good use case
+ optional = False
+ l = Library(self, name, path, optional, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps)
l.__dict__.update(attrs)
self.libs.append(l)
@@ -755,8 +823,8 @@
sourcesPath = attrs.pop('sourcesPath', None)
deps = pop_list(attrs, 'dependencies')
exclDeps = pop_list(attrs, 'exclude')
- distDep = attrs.pop('distDependency', None)
- d = Distribution(self, name, path, sourcesPath, deps, exclDeps, distDep)
+ distDeps = pop_list(attrs, 'distDependencies')
+ d = Distribution(self, name, path, sourcesPath, deps, exclDeps, distDeps)
d.__dict__.update(attrs)
self.dists.append(d)
@@ -836,6 +904,12 @@
if existing is not None and existing != l:
abort('inconsistent library redefinition of ' + l.name + ' in ' + existing.suite.dir + ' and ' + l.suite.dir)
_libs[l.name] = l
+ for l in self.jreLibs:
+ existing = _jreLibs.get(l.name)
+ # Check that suites that define same library are consistent
+ if existing is not None and existing != l:
+ abort('inconsistent JRE library redefinition of ' + l.name + ' in ' + existing.suite.dir + ' and ' + l.suite.dir)
+ _jreLibs[l.name] = l
for d in self.dists:
existing = _dists.get(d.name)
if existing is not None:
@@ -844,6 +918,54 @@
warn('distribution ' + d.name + ' redefined')
d.path = existing.path
_dists[d.name] = d
+
+ # Remove projects and libraries that (recursively) depend on an optional library
+ # whose artifact does not exist or on a JRE library that is not present in the
+ # JDK for a project. Also remove projects whose Java compliance requirement
+ # cannot be satisfied by the configured JDKs.
+ #
+ # Removed projects and libraries are also removed from
+ # distributions in they are listed as dependencies.
+ for d in sorted_deps(includeLibs=True):
+ if d.isLibrary():
+ if d.optional:
+ try:
+ d.optional = False
+ path = d.get_path(resolve=True)
+ except SystemExit:
+ path = None
+ finally:
+ d.optional = True
+ if not path:
+ logv('[omitting optional library {} as {} does not exist]'.format(d, d.path))
+ del _libs[d.name]
+ self.libs.remove(d)
+ elif d.isProject():
+ if java(d.javaCompliance) is None:
+ logv('[omitting project {} as Java compliance {} cannot be satisfied by configured JDKs]'.format(d, d.javaCompliance))
+ del _projects[d.name]
+ self.projects.remove(d)
+ else:
+ for name in list(d.deps):
+ jreLib = _jreLibs.get(name)
+ if jreLib:
+ if not jreLib.is_present_in_jdk(java(d.javaCompliance)):
+ if jreLib.optional:
+ logv('[omitting project {} as dependency {} is missing]'.format(d, name))
+ del _projects[d.name]
+ self.projects.remove(d)
+ else:
+ abort('JRE library {} required by {} not found'.format(jreLib, d))
+ elif not dependency(name, fatalIfMissing=False):
+ logv('[omitting project {} as dependency {} is missing]'.format(d, name))
+ del _projects[d.name]
+ self.projects.remove(d)
+ for dist in _dists.values():
+ for name in list(dist.deps):
+ if not dependency(name, fatalIfMissing=False):
+ logv('[omitting {} from distribution {}]'.format(name, dist))
+ dist.deps.remove(name)
+
if hasattr(self, 'mx_post_parse_cmd_line'):
self.mx_post_parse_cmd_line(opts)
@@ -1025,6 +1147,8 @@
d = _projects.get(name)
if d is None:
d = _libs.get(name)
+ if d is None:
+ d = _jreLibs.get(name)
if d is None and fatalIfMissing:
if name in _opts.ignored_projects:
abort('project named ' + name + ' is ignored')
@@ -1108,7 +1232,7 @@
entryPath = zi.filename
yield zf, entryPath
-def sorted_deps(projectNames=None, includeLibs=False, includeAnnotationProcessors=False):
+def sorted_deps(projectNames=None, includeLibs=False, includeJreLibs=False, includeAnnotationProcessors=False):
"""
Gets projects and libraries sorted such that dependencies
are before the projects that depend on them. Unless 'includeLibs' is
@@ -1116,12 +1240,12 @@
"""
projects = projects_from_names(projectNames)
- return sorted_project_deps(projects, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
-
-def sorted_project_deps(projects, includeLibs=False, includeAnnotationProcessors=False):
+ return sorted_project_deps(projects, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+
+def sorted_project_deps(projects, includeLibs=False, includeJreLibs=False, includeAnnotationProcessors=False):
deps = []
for p in projects:
- p.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+ p.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
return deps
def _handle_missing_java_home():
@@ -1381,11 +1505,11 @@
sub = _addSubprocess(p, args)
if callable(out):
t = Thread(target=redirect, args=(p.stdout, out))
- t.daemon = True # thread dies with the program
+ # Don't make the reader thread a daemon otherwise output can be droppped
t.start()
if callable(err):
t = Thread(target=redirect, args=(p.stderr, err))
- t.daemon = True # thread dies with the program
+ # Don't make the reader thread a daemon otherwise output can be droppped
t.start()
if timeout is None or timeout == 0:
retcode = waitOn(p)
@@ -1540,6 +1664,8 @@
self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
self.toolsjar = join(self.jdk, 'lib', 'tools.jar')
self._bootclasspath = None
+ self._extdirs = None
+ self._endorseddirs = None
if not exists(self.java):
abort('Java launcher does not exist: ' + self.java)
@@ -1708,8 +1834,6 @@
if _opts.killwithsigquit:
_send_sigquit()
- # import traceback
- # traceback.print_stack()
for p, args in _currentSubprocesses:
try:
if get_os() == 'windows':
@@ -1719,6 +1843,9 @@
except BaseException as e:
log('error while killing subprocess {} "{}": {}'.format(p.pid, ' '.join(args), e))
+ if _opts and _opts.verbose:
+ import traceback
+ traceback.print_stack()
raise SystemExit(codeOrMessage)
def download(path, urls, verbose=False):
@@ -2024,9 +2151,7 @@
# skip building this Java project if its Java compliance level is "higher" than the configured JDK
requiredCompliance = p.javaCompliance if p.javaCompliance else JavaCompliance(args.compliance) if args.compliance else None
jdk = java(requiredCompliance)
- if not jdk:
- log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, requiredCompliance))
- continue
+ assert jdk
outputDir = prepareOutputDirs(p, args.clean)
@@ -2123,6 +2248,7 @@
failed = []
for t in tasks:
t.proc.join()
+ _removeSubprocess(t.sub)
if t.proc.exitcode != 0:
failed.append(t)
return failed
@@ -2133,7 +2259,6 @@
if t.proc.is_alive():
active.append(t)
else:
- _removeSubprocess(t.sub)
if t.proc.exitcode != 0:
return ([], joinTasks(tasks))
return (active, [])
@@ -2164,6 +2289,7 @@
cpus = multiprocessing.cpu_count()
worklist = sortWorklist(tasks.values())
active = []
+ failed = []
while len(worklist) != 0:
while True:
active, failed = checkTasks(active)
@@ -2176,7 +2302,12 @@
else:
break
+ if len(failed) != 0:
+ break
+
def executeTask(task):
+ # Clear sub-process list cloned from parent process
+ del _currentSubprocesses[:]
task.execute()
def depsDone(task):
@@ -2196,7 +2327,12 @@
break
worklist = sortWorklist(worklist)
- joinTasks(active)
+
+ failed += joinTasks(active)
+ if len(failed):
+ for t in failed:
+ log('Compiling {} failed'.format(t.proj.name))
+ abort('{} Java compilation tasks failed'.format(len(failed)))
for dist in _dists.values():
archive(['@' + dist.name])
@@ -2622,9 +2758,7 @@
# skip checking this Java project if its Java compliance level is "higher" than the configured JDK
jdk = java(p.javaCompliance)
- if not jdk:
- log('Excluding {0} from checking (Java compliance level {1} required)'.format(p.name, p.javaCompliance))
- continue
+ assert jdk
for sourceDir in sourceDirs:
javafilelist = []
@@ -2816,7 +2950,7 @@
igv.close('properties')
igv.open('graph', {'name' : 'dependencies'})
igv.open('nodes')
- for p in sorted_deps(includeLibs=True):
+ for p in sorted_deps(includeLibs=True, includeJreLibs=True):
ident = len(ids)
ids[p.name] = str(ident)
igv.open('node', {'id' : str(ident)})
@@ -2868,10 +3002,10 @@
elif dep.get_source_path(resolve=True):
memento = XMLDoc().element('archive', {'detectRoot' : 'true', 'path' : dep.get_source_path(resolve=True)}).xml(standalone='no')
slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.debug.core.containerType.externalArchive'})
- else:
+ elif dep.isProject():
memento = XMLDoc().element('javaProject', {'name' : dep.name}).xml(standalone='no')
slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.javaProject'})
- if javaCompliance is None or dep.javaCompliance < javaCompliance:
+ if javaCompliance is None or dep.javaCompliance > javaCompliance:
javaCompliance = dep.javaCompliance
if javaCompliance:
@@ -3035,9 +3169,7 @@
if p.native:
continue
- if not java(p.javaCompliance):
- log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance))
- continue
+ assert java(p.javaCompliance)
if not exists(p.dir):
os.makedirs(p.dir)
@@ -3078,7 +3210,7 @@
libraryDeps -= set(dep.all_deps([], True))
else:
libraryDeps.add(dep)
- else:
+ elif dep.isProject():
projectDeps.add(dep)
for dep in containerDeps:
@@ -3087,8 +3219,6 @@
for dep in libraryDeps:
path = dep.path
dep.get_path(resolve=True)
- if not path or (not exists(path) and not dep.mustExist):
- continue
# Relative paths for "lib" class path entries have various semantics depending on the Eclipse
# version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
@@ -3246,16 +3376,13 @@
for dep in dependency(ap).all_deps([], True):
if dep.isLibrary():
if not hasattr(dep, 'eclipse.container') and not hasattr(dep, 'eclipse.project'):
- if dep.mustExist:
- path = dep.get_path(resolve=True)
- if path:
- # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
- # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
- # safest to simply use absolute paths.
- path = _make_absolute(path, p.suite.dir)
- out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
- files.append(path)
- else:
+ # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
+ # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
+ # safest to simply use absolute paths.
+ path = _make_absolute(dep.get_path(resolve=True), p.suite.dir)
+ out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
+ files.append(path)
+ elif dep.isProject():
out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : '/' + dep.name + '/' + dep.name + '.jar', 'enabled' : 'true', 'runInBatchMode' : 'false'})
out.close('factorypath')
update_file(join(p.dir, '.factorypath'), out.xml(indent='\t', newl='\n'))
@@ -3558,10 +3685,7 @@
os.makedirs(join(p.dir, 'nbproject'))
jdk = java(p.javaCompliance)
-
- if not jdk:
- log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance))
- continue
+ assert jdk
jdks.add(jdk)
@@ -3602,7 +3726,7 @@
if dep == p:
continue
- if not dep.isLibrary():
+ if dep.isProject():
n = dep.name.replace('.', '_')
if firstDep:
out.open('references', {'xmlns' : 'http://www.netbeans.org/ns/ant-project-references/1'})
@@ -3737,8 +3861,6 @@
continue
if dep.isLibrary():
- if not dep.mustExist:
- continue
path = dep.get_path(resolve=True)
if path:
if os.sep == '\\':
@@ -3747,7 +3869,7 @@
print >> out, ref + '=' + path
libFiles.append(path)
- else:
+ elif dep.isProject():
n = dep.name.replace('.', '_')
relDepPath = os.path.relpath(dep.dir, p.dir).replace(os.sep, '/')
ref = 'reference.' + n + '.jar'
@@ -3814,9 +3936,7 @@
if p.native:
continue
- if not java(p.javaCompliance):
- log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance))
- continue
+ assert java(p.javaCompliance)
if not exists(p.dir):
os.makedirs(p.dir)
@@ -3863,10 +3983,9 @@
continue
if dep.isLibrary():
- if dep.mustExist:
- libraries.add(dep)
- moduleXml.element('orderEntry', attributes={'type': 'library', 'name': dep.name, 'level': 'project'})
- else:
+ libraries.add(dep)
+ moduleXml.element('orderEntry', attributes={'type': 'library', 'name': dep.name, 'level': 'project'})
+ elif dep.isProject():
moduleXml.element('orderEntry', attributes={'type': 'module', 'module-name': dep.name})
moduleXml.close('component')
@@ -3938,7 +4057,7 @@
for entry in pDep.all_deps([], True):
if entry.isLibrary():
compilerXml.element('entry', attributes={'name': '$PROJECT_DIR$/' + os.path.relpath(entry.path, suite.dir)})
- else:
+ elif entry.isProject():
assert entry.isProject()
compilerXml.element('entry', attributes={'name': '$PROJECT_DIR$/' + os.path.relpath(entry.output_dir(), suite.dir)})
compilerXml.close('processorPath')
diff -r a43ff5d18350 -r a6eeb3750238 src/gpu/hsail/vm/vmStructs_hsail.hpp
--- a/src/gpu/hsail/vm/vmStructs_hsail.hpp Tue May 13 19:19:27 2014 +0200
+++ b/src/gpu/hsail/vm/vmStructs_hsail.hpp Wed May 21 11:45:50 2014 +0200
@@ -53,9 +53,4 @@
declare_toplevel_type(Hsail::HSAILKernelDeoptimization) \
declare_toplevel_type(Hsail::HSAILDeoptimizationInfo)
-#define VM_INT_CONSTANTS_GPU_HSAIL(declare_constant) \
- declare_constant(sizeof(HSAILFrame)) \
- declare_constant(sizeof(Hsail::HSAILKernelDeoptimization)) \
- declare_constant(sizeof(Hsail::HSAILDeoptimizationInfo)) \
-
#endif // GPU_HSAIL_VM_VMSTRUCTS_HSAIL_HPP
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/classfile/systemDictionary.hpp
--- a/src/share/vm/classfile/systemDictionary.hpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp Wed May 21 11:45:50 2014 +0200
@@ -203,7 +203,6 @@
do_klass(HotSpotCodeInfo_klass, com_oracle_graal_hotspot_meta_HotSpotCodeInfo, Opt) \
do_klass(HotSpotInstalledCode_klass, com_oracle_graal_hotspot_meta_HotSpotInstalledCode, Opt) \
do_klass(HotSpotNmethod_klass, com_oracle_graal_hotspot_meta_HotSpotNmethod, Opt) \
- do_klass(HotSpotJavaType_klass, com_oracle_graal_hotspot_meta_HotSpotJavaType, Opt) \
do_klass(HotSpotResolvedJavaMethod_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod, Opt) \
do_klass(HotSpotResolvedObjectType_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType, Opt) \
do_klass(HotSpotMonitorValue_klass, com_oracle_graal_hotspot_meta_HotSpotMonitorValue, Opt) \
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/classfile/vmSymbols.hpp
--- a/src/share/vm/classfile/vmSymbols.hpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp Wed May 21 11:45:50 2014 +0200
@@ -312,7 +312,6 @@
template(com_oracle_graal_hotspot_meta_HotSpotCodeInfo, "com/oracle/graal/hotspot/meta/HotSpotCodeInfo") \
template(com_oracle_graal_hotspot_meta_HotSpotInstalledCode, "com/oracle/graal/hotspot/meta/HotSpotInstalledCode") \
template(com_oracle_graal_hotspot_meta_HotSpotNmethod, "com/oracle/graal/hotspot/meta/HotSpotNmethod") \
- template(com_oracle_graal_hotspot_meta_HotSpotJavaType, "com/oracle/graal/hotspot/meta/HotSpotJavaType") \
template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod, "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod") \
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") \
@@ -323,12 +322,10 @@
template(com_oracle_graal_api_meta_Constant, "com/oracle/graal/api/meta/Constant") \
template(com_oracle_graal_api_meta_PrimitiveConstant, "com/oracle/graal/api/meta/PrimitiveConstant") \
template(com_oracle_graal_api_meta_NullConstant, "com/oracle/graal/api/meta/NullConstant") \
- template(com_oracle_graal_api_meta_ConstantPool, "com/oracle/graal/api/meta/ConstantPool") \
template(com_oracle_graal_api_meta_ExceptionHandler, "com/oracle/graal/api/meta/ExceptionHandler") \
template(com_oracle_graal_api_meta_JavaMethod, "com/oracle/graal/api/meta/JavaMethod") \
template(com_oracle_graal_api_meta_JavaType, "com/oracle/graal/api/meta/JavaType") \
template(com_oracle_graal_api_meta_Kind, "com/oracle/graal/api/meta/Kind") \
- template(com_oracle_graal_api_meta_ResolvedJavaField, "com/oracle/graal/api/meta/ResolvedJavaField") \
template(com_oracle_graal_api_meta_Value, "com/oracle/graal/api/meta/Value") \
/* graal.api.code */ \
template(com_oracle_graal_api_code_Assumptions, "com/oracle/graal/api/code/Assumptions") \
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/graal/graalCodeInstaller.cpp
--- a/src/share/vm/graal/graalCodeInstaller.cpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp Wed May 21 11:45:50 2014 +0200
@@ -605,10 +605,11 @@
Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaClass(context_handle));
Klass* subtype = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaClass(subtype_handle));
- _dependencies->assert_leaf_type(subtype);
if (context != subtype) {
assert(context->is_abstract(), "");
_dependencies->assert_abstract_with_unique_concrete_subtype(context, subtype);
+ } else {
+ _dependencies->assert_leaf_type(subtype);
}
}
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/graal/graalCompilerToVM.cpp
--- a/src/share/vm/graal/graalCompilerToVM.cpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed May 21 11:45:50 2014 +0200
@@ -53,12 +53,6 @@
TRACE_graal_3("CompilerToVM::" #name); \
GRAAL_VM_ENTRY_MARK; \
-// Entry to native method implementation that calls a JNI function
-// and hence cannot transition current thread to '_thread_in_vm'.
-#define C2V_ENTRY(result_type, name, signature) \
- JNIEXPORT result_type JNICALL c2v_ ## name signature { \
- TRACE_graal_3("CompilerToVM::" #name); \
-
#define C2V_END }
extern "C" {
@@ -91,128 +85,11 @@
extern uint64_t gHotSpotVMLongConstantEntryArrayStride;
}
-// helpers used to set fields in the HotSpotVMConfig object
-static jfieldID getFieldID(JNIEnv* env, jobject obj, const char* name, const char* sig) {
- jfieldID id = env->GetFieldID(env->GetObjectClass(obj), name, sig);
- if (id == NULL) {
- fatal(err_msg("field not found: %s (%s)", name, sig));
- }
- return id;
-}
-
-C2V_ENTRY(void, initializeConfiguration, (JNIEnv *env, jobject, jobject config))
-
-#define set_boolean(name, value) do { env->SetBooleanField(config, getFieldID(env, config, name, "Z"), value); } while (0)
-#define set_int(name, value) do { env->SetIntField(config, getFieldID(env, config, name, "I"), value); } while (0)
-#define set_long(name, value) do { env->SetLongField(config, getFieldID(env, config, name, "J"), value); } while (0)
-#define set_address(name, value) do { set_long(name, (jlong) value); } while (0)
-
- guarantee(HeapWordSize == sizeof(char*), "Graal assumption that HeadWordSize == machine word size is wrong");
-
- set_address("gHotSpotVMStructs", gHotSpotVMStructs);
- set_long("gHotSpotVMStructEntryTypeNameOffset", gHotSpotVMStructEntryTypeNameOffset);
- set_long("gHotSpotVMStructEntryFieldNameOffset", gHotSpotVMStructEntryFieldNameOffset);
- set_long("gHotSpotVMStructEntryTypeStringOffset", gHotSpotVMStructEntryTypeStringOffset);
- set_long("gHotSpotVMStructEntryIsStaticOffset", gHotSpotVMStructEntryIsStaticOffset);
- set_long("gHotSpotVMStructEntryOffsetOffset", gHotSpotVMStructEntryOffsetOffset);
- set_long("gHotSpotVMStructEntryAddressOffset", gHotSpotVMStructEntryAddressOffset);
- set_long("gHotSpotVMStructEntryArrayStride", gHotSpotVMStructEntryArrayStride);
-
- set_address("gHotSpotVMTypes", gHotSpotVMTypes);
- set_long("gHotSpotVMTypeEntryTypeNameOffset", gHotSpotVMTypeEntryTypeNameOffset);
- set_long("gHotSpotVMTypeEntrySuperclassNameOffset", gHotSpotVMTypeEntrySuperclassNameOffset);
- set_long("gHotSpotVMTypeEntryIsOopTypeOffset", gHotSpotVMTypeEntryIsOopTypeOffset);
- set_long("gHotSpotVMTypeEntryIsIntegerTypeOffset", gHotSpotVMTypeEntryIsIntegerTypeOffset);
- set_long("gHotSpotVMTypeEntryIsUnsignedOffset", gHotSpotVMTypeEntryIsUnsignedOffset);
- set_long("gHotSpotVMTypeEntrySizeOffset", gHotSpotVMTypeEntrySizeOffset);
- set_long("gHotSpotVMTypeEntryArrayStride", gHotSpotVMTypeEntryArrayStride);
-
- set_address("gHotSpotVMIntConstants", gHotSpotVMIntConstants);
- set_long("gHotSpotVMIntConstantEntryNameOffset", gHotSpotVMIntConstantEntryNameOffset);
- set_long("gHotSpotVMIntConstantEntryValueOffset", gHotSpotVMIntConstantEntryValueOffset);
- set_long("gHotSpotVMIntConstantEntryArrayStride", gHotSpotVMIntConstantEntryArrayStride);
-
- set_address("gHotSpotVMLongConstants", gHotSpotVMLongConstants);
- set_long("gHotSpotVMLongConstantEntryNameOffset", gHotSpotVMLongConstantEntryNameOffset);
- set_long("gHotSpotVMLongConstantEntryValueOffset", gHotSpotVMLongConstantEntryValueOffset);
- set_long("gHotSpotVMLongConstantEntryArrayStride", gHotSpotVMLongConstantEntryArrayStride);
-
- //------------------------------------------------------------------------------------------------
-
- set_int("arrayLengthOffset", arrayOopDesc::length_offset_in_bytes());
-
- set_int("extraStackEntries", Method::extra_stack_entries());
-
- set_int("tlabAlignmentReserve", (int32_t)ThreadLocalAllocBuffer::alignment_reserve());
- set_long("heapTopAddress", (jlong)(address) Universe::heap()->top_addr());
- set_long("heapEndAddress", (jlong)(address) Universe::heap()->end_addr());
-
- set_boolean("inlineContiguousAllocationSupported", !CMSIncrementalMode && Universe::heap()->supports_inline_contig_alloc());
-
- set_long("verifyOopMask", Universe::verify_oop_mask());
- set_long("verifyOopBits", Universe::verify_oop_bits());
-
- set_int("instanceKlassVtableStartOffset", InstanceKlass::vtable_start_offset() * HeapWordSize);
-
- //------------------------------------------------------------------------------------------------
-
- set_address("registerFinalizerAddress", SharedRuntime::register_finalizer);
- set_address("exceptionHandlerForReturnAddressAddress", SharedRuntime::exception_handler_for_return_address);
- set_address("osrMigrationEndAddress", SharedRuntime::OSR_migration_end);
-
- set_address("javaTimeMillisAddress", CAST_FROM_FN_PTR(address, os::javaTimeMillis));
- set_address("javaTimeNanosAddress", CAST_FROM_FN_PTR(address, os::javaTimeNanos));
- set_address("arithmeticSinAddress", CAST_FROM_FN_PTR(address, SharedRuntime::dsin));
- set_address("arithmeticCosAddress", CAST_FROM_FN_PTR(address, SharedRuntime::dcos));
- set_address("arithmeticTanAddress", CAST_FROM_FN_PTR(address, SharedRuntime::dtan));
-
- set_address("newInstanceAddress", GraalRuntime::new_instance);
- set_address("newArrayAddress", GraalRuntime::new_array);
- set_address("newMultiArrayAddress", GraalRuntime::new_multi_array);
- set_address("dynamicNewArrayAddress", GraalRuntime::dynamic_new_array);
- set_address("dynamicNewInstanceAddress", GraalRuntime::dynamic_new_instance);
- set_address("threadIsInterruptedAddress", GraalRuntime::thread_is_interrupted);
- set_address("vmMessageAddress", GraalRuntime::vm_message);
- set_address("identityHashCodeAddress", GraalRuntime::identity_hash_code);
- set_address("exceptionHandlerForPcAddress", GraalRuntime::exception_handler_for_pc);
- set_address("monitorenterAddress", GraalRuntime::monitorenter);
- set_address("monitorexitAddress", GraalRuntime::monitorexit);
- set_address("createNullPointerExceptionAddress", GraalRuntime::create_null_exception);
- set_address("createOutOfBoundsExceptionAddress", GraalRuntime::create_out_of_bounds_exception);
- set_address("logPrimitiveAddress", GraalRuntime::log_primitive);
- set_address("logObjectAddress", GraalRuntime::log_object);
- set_address("logPrintfAddress", GraalRuntime::log_printf);
- set_address("vmErrorAddress", GraalRuntime::vm_error);
- set_address("loadAndClearExceptionAddress", GraalRuntime::load_and_clear_exception);
- set_address("writeBarrierPreAddress", GraalRuntime::write_barrier_pre);
- set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post);
- set_address("validateObject", GraalRuntime::validate_object);
-
- set_address("deoptimizationFetchUnrollInfo", Deoptimization::fetch_unroll_info);
- set_address("deoptimizationUncommonTrap", Deoptimization::uncommon_trap);
- set_address("deoptimizationUnpackFrames", Deoptimization::unpack_frames);
-
- //------------------------------------------------------------------------------------------------
-
- set_int("graalCountersThreadOffset", in_bytes(JavaThread::graal_counters_offset()));
- set_int("graalCountersSize", (jint) GraalCounterSize);
-
- //------------------------------------------------------------------------------------------------
-
- set_long("dllLoad", (jlong) os::dll_load);
- set_long("dllLookup", (jlong) os::dll_lookup);
- #if defined(TARGET_OS_FAMILY_bsd) || defined(TARGET_OS_FAMILY_linux)
- set_long("rtldDefault", (jlong) RTLD_DEFAULT);
- #endif
-
-#undef set_boolean
-#undef set_int
-#undef set_long
-#undef set_address
-
+C2V_VMENTRY(void, initializeConfiguration, (JNIEnv *, jobject, jobject config))
+ VMStructs::initHotSpotVMConfig(JNIHandles::resolve(config));
C2V_END
-C2V_ENTRY(jbyteArray, initializeBytecode, (JNIEnv *env, jobject, jlong metaspace_method, jbyteArray result))
+C2V_VMENTRY(jbyteArray, initializeBytecode, (JNIEnv *, jobject, jlong metaspace_method))
methodHandle method = asMethod(metaspace_method);
ResourceMark rm;
@@ -279,9 +156,9 @@
}
}
- env->SetByteArrayRegion(result, 0, code_size, reconstituted_code);
-
- return result;
+ typeArrayOop result_array = oopFactory::new_byteArray(code_size, CHECK_NULL);
+ memcpy(result_array->byte_at_addr(0), reconstituted_code, code_size);
+ return (jbyteArray) JNIHandles::make_local(result_array);
C2V_END
C2V_VMENTRY(jint, exceptionTableLength, (JNIEnv *, jobject, jlong metaspace_method))
@@ -350,7 +227,7 @@
return CompilerOracle::should_inline(method) || method->force_inline();
C2V_END
-C2V_VMENTRY(jlong, lookupType, (JNIEnv *env, jobject, jstring jname, jclass accessing_class, jboolean resolve))
+C2V_VMENTRY(jlong, lookupType, (JNIEnv*, jobject, jstring jname, jclass accessing_class, jboolean resolve))
ResourceMark rm;
Handle name = JNIHandles::resolve(jname);
Symbol* class_name = java_lang_String::as_symbol(name, THREAD);
@@ -375,44 +252,44 @@
return (jlong) (address) resolved_klass;
C2V_END
-C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
ConstantPool* cp = (ConstantPool*) metaspace_constant_pool;
oop result = cp->resolve_constant_at(index, CHECK_NULL);
return JNIHandles::make_local(THREAD, result);
C2V_END
-C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
ConstantPool* cp = (ConstantPool*) metaspace_constant_pool;
oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
return JNIHandles::make_local(THREAD, result);
C2V_END
-C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
return cp->name_and_type_ref_index_at(index);
C2V_END
-C2V_VMENTRY(jlong, lookupNameRefInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jlong, lookupNameRefInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
return (jlong) (address) cp->name_ref_at(index);
C2V_END
-C2V_VMENTRY(jlong, lookupSignatureRefInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jlong, lookupSignatureRefInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
return (jlong) (address) cp->signature_ref_at(index);
C2V_END
-C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
return cp->klass_ref_index_at(index);
C2V_END
-C2V_VMENTRY(jlong, constantPoolKlassAt, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jlong, constantPoolKlassAt, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
ConstantPool* cp = (ConstantPool*) metaspace_constant_pool;
return (jlong) (address) cp->klass_at(index, THREAD);
C2V_END
-C2V_VMENTRY(jlong, lookupKlassInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode))
+C2V_VMENTRY(jlong, lookupKlassInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode))
constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
KlassHandle loading_klass(cp->pool_holder());
bool is_accessible = false;
@@ -436,13 +313,13 @@
return (jlong) CompilerToVM::tag_pointer(klass());
C2V_END
-C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index);
return JNIHandles::make_local(THREAD, appendix_oop);
C2V_END
-C2V_VMENTRY(jlong, lookupMethodInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode))
+C2V_VMENTRY(jlong, lookupMethodInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode))
constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
instanceKlassHandle pool_holder(cp->pool_holder());
Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF);
@@ -450,12 +327,12 @@
return (jlong) (address) method();
C2V_END
-C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
ConstantPool* cp = (ConstantPool*) metaspace_constant_pool;
return cp->remap_instruction_operand_from_cache(index);
C2V_END
-C2V_VMENTRY(jlong, resolveField, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode, jlongArray info_handle))
+C2V_VMENTRY(jlong, resolveField, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode, jlongArray info_handle))
ResourceMark rm;
constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF);
@@ -468,11 +345,76 @@
return (jlong) (address) result.field_holder();
C2V_END
-C2V_VMENTRY(jlong, resolveMethod, (JNIEnv *, jobject, jlong metaspace_klass, jstring name, jstring signature))
+C2V_VMENTRY(jint, getVtableIndexForInterface, (JNIEnv *, jobject, jlong metaspace_klass, jlong metaspace_method))
Klass* klass = (Klass*) metaspace_klass;
- Symbol* name_symbol = java_lang_String::as_symbol(JNIHandles::resolve(name), THREAD);
- Symbol* signature_symbol = java_lang_String::as_symbol(JNIHandles::resolve(signature), THREAD);
- return (jlong) (address) klass->lookup_method(name_symbol, signature_symbol);
+ Method* method = (Method*) metaspace_method;
+ assert(!klass->is_interface(), "");
+ return LinkResolver::vtable_index_of_interface_method(klass, method);
+C2V_END
+
+C2V_VMENTRY(jlong, resolveMethod, (JNIEnv *, jobject, jlong metaspace_klass_receiver, jlong metaspace_method, jlong metaspace_klass_caller))
+ Klass* recv_klass = (Klass*) metaspace_klass_receiver;
+ Klass* caller_klass = (Klass*) metaspace_klass_caller;
+ Method* method = (Method*) metaspace_method;
+
+ if (recv_klass->oop_is_array() || (InstanceKlass::cast(recv_klass)->is_linked())) {
+ Klass* holder_klass = method->method_holder();
+ Symbol* method_name = method->name();
+ Symbol* method_signature = method->signature();
+
+
+ if (holder_klass->is_interface()) {
+ // do link-time resolution to check all access rules.
+ methodHandle resolved_method;
+ LinkResolver::linktime_resolve_interface_method(resolved_method, holder_klass, method_name, method_signature, caller_klass, true, CHECK_AND_CLEAR_0);
+ if (resolved_method->is_private()) {
+ return (jlong) NULL;
+ }
+ assert(recv_klass->is_subtype_of(holder_klass), "");
+ // do actual lookup
+ methodHandle sel_method;
+ LinkResolver::lookup_instance_method_in_klasses(sel_method, recv_klass,
+ resolved_method->name(),
+ resolved_method->signature(), CHECK_AND_CLEAR_0);
+ return (jlong) (address) sel_method();
+ } else {
+ // do link-time resolution to check all access rules.
+ methodHandle resolved_method;
+ LinkResolver::linktime_resolve_virtual_method(resolved_method, holder_klass, method_name, method_signature, caller_klass, true, CHECK_AND_CLEAR_0);
+ // do actual lookup (see LinkResolver::runtime_resolve_virtual_method)
+ int vtable_index = Method::invalid_vtable_index;
+ Method* selected_method;
+
+ if (resolved_method->method_holder()->is_interface()) { // miranda method
+ vtable_index = LinkResolver::vtable_index_of_interface_method(holder_klass, resolved_method);
+ assert(vtable_index >= 0 , "we should have valid vtable index at this point");
+
+ InstanceKlass* inst = InstanceKlass::cast(recv_klass);
+ selected_method = inst->method_at_vtable(vtable_index);
+ } else {
+ // at this point we are sure that resolved_method is virtual and not
+ // a miranda method; therefore, it must have a valid vtable index.
+ assert(!resolved_method->has_itable_index(), "");
+ vtable_index = resolved_method->vtable_index();
+ // We could get a negative vtable_index for final methods,
+ // because as an optimization they are they are never put in the vtable,
+ // unless they override an existing method.
+ // If we do get a negative, it means the resolved method is the the selected
+ // method, and it can never be changed by an override.
+ if (vtable_index == Method::nonvirtual_vtable_index) {
+ assert(resolved_method->can_be_statically_bound(), "cannot override this method");
+ selected_method = resolved_method();
+ } else {
+ // recv_klass might be an arrayKlassOop but all vtables start at
+ // the same place. The cast is to avoid virtual call and assertion.
+ InstanceKlass* inst = (InstanceKlass*)recv_klass;
+ selected_method = inst->method_at_vtable(vtable_index);
+ }
+ }
+ return (jlong) (address) selected_method;
+ }
+ }
+ return (jlong) NULL;
C2V_END
C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv *, jobject, jlong metaspace_klass))
@@ -486,7 +428,7 @@
return (jlong) (address) klass->class_initializer();
C2V_END
-C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong addr))
+C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv*, jobject, jlong addr))
address target_addr = (address) addr;
if (target_addr != 0x0) {
int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int));
@@ -622,7 +564,7 @@
return JNIHandles::make_local(result());
C2V_END
-C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv *env, jobject, jlong metaspace_method, int bci))
+C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv*, jobject, jlong metaspace_method, int bci))
ResourceMark rm;
HandleMark hm;
@@ -631,7 +573,7 @@
return JNIHandles::make_local(element);
C2V_END
-C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jobject hotspotInstalledCode))
+C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv*, jobject, jobject args, jobject hotspotInstalledCode))
ResourceMark rm;
HandleMark hm;
@@ -659,7 +601,7 @@
}
C2V_END
-C2V_ENTRY(jlongArray, getLineNumberTable, (JNIEnv *env, jobject, jlong metaspace_method))
+C2V_VMENTRY(jlongArray, getLineNumberTable, (JNIEnv *, jobject, jlong metaspace_method))
Method* method = (Method*) metaspace_method;
if (!method->has_linenumber_table()) {
return NULL;
@@ -671,19 +613,19 @@
}
CompressedLineNumberReadStream stream(method->compressed_linenumber_table());
- jlongArray result = env->NewLongArray(2 * num_entries);
+ typeArrayOop result = oopFactory::new_longArray(2 * num_entries, CHECK_NULL);
int i = 0;
jlong value;
while (stream.read_pair()) {
value = ((long) stream.bci());
- env->SetLongArrayRegion(result,i,1,&value);
+ result->long_at_put(i, value);
value = ((long) stream.line());
- env->SetLongArrayRegion(result,i + 1,1,&value);
+ result->long_at_put(i + 1, value);
i += 2;
}
- return result;
+ return (jlongArray) JNIHandles::make_local(result);
C2V_END
C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv *, jobject, jlong metaspace_method))
@@ -701,7 +643,7 @@
return method->localvariable_table_length();
C2V_END
-C2V_VMENTRY(void, reprofile, (JNIEnv *env, jobject, jlong metaspace_method))
+C2V_VMENTRY(void, reprofile, (JNIEnv*, jobject, jlong metaspace_method))
Method* method = asMethod(metaspace_method);
MethodCounters* mcs = method->method_counters();
if (mcs != NULL) {
@@ -725,7 +667,7 @@
C2V_END
-C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv *env, jobject, jobject hotspotInstalledCode))
+C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv*, jobject, jobject hotspotInstalledCode))
jlong nativeMethod = InstalledCode::address(hotspotInstalledCode);
nmethod* m = (nmethod*)nativeMethod;
if (m != NULL && !m->is_not_entrant()) {
@@ -736,32 +678,36 @@
InstalledCode::set_address(hotspotInstalledCode, 0);
C2V_END
-C2V_VMENTRY(jobject, getJavaMirror, (JNIEnv *env, jobject, jlong metaspace_klass))
+C2V_VMENTRY(jobject, getJavaMirror, (JNIEnv*, jobject, jlong metaspace_klass))
Klass* klass = asKlass(metaspace_klass);
return JNIHandles::make_local(klass->java_mirror());
C2V_END
-C2V_VMENTRY(jlong, readUnsafeKlassPointer, (JNIEnv *env, jobject, jobject o))
+C2V_VMENTRY(jlong, readUnsafeKlassPointer, (JNIEnv*, jobject, jobject o))
oop resolved_o = JNIHandles::resolve(o);
jlong klass = (jlong)(address)resolved_o->klass();
return klass;
C2V_END
-C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv *env, jobject))
+C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv*, jobject))
typeArrayOop arrayOop = oopFactory::new_longArray(GraalCounterSize, CHECK_NULL);
JavaThread::collect_counters(arrayOop);
return (jlongArray) JNIHandles::make_local(arrayOop);
C2V_END
-C2V_ENTRY(jobject, getGPUs, (JNIEnv *env, jobject))
+// In general we should avoid using regular JNI methods to interact with the JVM but this
+// particular case is just about registering JNI methods so it should be a regular native
+// method.
+JNIEXPORT jobject JNICALL c2v_getGPUs (JNIEnv* env, jobject) {
+ TRACE_graal_3("CompilerToVM::getGPUs" );
#if defined(TARGET_OS_FAMILY_bsd) || defined(TARGET_OS_FAMILY_linux) || defined(TARGET_OS_FAMILY_windows)
return Gpu::probe_gpus(env);
#else
return env->NewStringUTF("");
#endif
-C2V_END
+}
-C2V_VMENTRY(int, allocateCompileId, (JNIEnv *env, jobject, jlong metaspace_method, int entry_bci))
+C2V_VMENTRY(int, allocateCompileId, (JNIEnv*, jobject, jlong metaspace_method, int entry_bci))
HandleMark hm;
ResourceMark rm;
Method* method = (Method*) metaspace_method;
@@ -769,17 +715,17 @@
C2V_END
-C2V_VMENTRY(jboolean, isMature, (JNIEnv *env, jobject, jlong metaspace_method_data))
+C2V_VMENTRY(jboolean, isMature, (JNIEnv*, jobject, jlong metaspace_method_data))
MethodData* mdo = asMethodData(metaspace_method_data);
return mdo != NULL && mdo->is_mature();
C2V_END
-C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv *env, jobject, jlong metaspace_method, int entry_bci, int comp_level))
+C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv*, jobject, jlong metaspace_method, int entry_bci, int comp_level))
Method* method = asMethod(metaspace_method);
return method->lookup_osr_nmethod_for(entry_bci, comp_level, true) != NULL;
C2V_END
-C2V_VMENTRY(jlong, getTimeStamp, (JNIEnv *env, jobject))
+C2V_VMENTRY(jlong, getTimeStamp, (JNIEnv*, jobject))
// tty->time_stamp is the time since VM start which should be used
// for all HotSpot log output when a timestamp is required.
return tty->time_stamp().milliseconds();
@@ -796,7 +742,7 @@
return false;
}
-C2V_VMENTRY(jobject, getNextStackFrame, (JNIEnv *env, jobject compilerToVM, jobject hs_frame, jlongArray methods, jint initialSkip))
+C2V_VMENTRY(jobject, getNextStackFrame, (JNIEnv*, jobject compilerToVM, jobject hs_frame, jlongArray methods, jint initialSkip))
ResourceMark rm;
if (!thread->has_last_Java_frame()) return NULL;
@@ -931,7 +877,7 @@
return NULL;
C2V_END
-C2V_VMENTRY(void, resolveInvokeDynamic, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(void, resolveInvokeDynamic, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
ConstantPool* cp = (ConstantPool*)metaspace_constant_pool;
CallInfo callInfo;
LinkResolver::resolve_invokedynamic(callInfo, cp, index, CHECK);
@@ -940,7 +886,7 @@
C2V_END
// public native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
-C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv *env, jobject, jobject hs_frame, bool invalidate))
+C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame, bool invalidate))
ResourceMark rm;
if (hs_frame == NULL) {
@@ -1058,58 +1004,59 @@
#define METASPACE_SYMBOL "J"
JNINativeMethod CompilerToVM_methods[] = {
- {CC"initializeBytecode", CC"("METASPACE_METHOD"[B)[B", FN_PTR(initializeBytecode)},
- {CC"exceptionTableStart", CC"("METASPACE_METHOD")J", FN_PTR(exceptionTableStart)},
- {CC"exceptionTableLength", CC"("METASPACE_METHOD")I", FN_PTR(exceptionTableLength)},
- {CC"hasBalancedMonitors", CC"("METASPACE_METHOD")Z", FN_PTR(hasBalancedMonitors)},
- {CC"findUniqueConcreteMethod", CC"("METASPACE_METHOD")"METASPACE_METHOD, FN_PTR(findUniqueConcreteMethod)},
- {CC"getKlassImplementor", CC"("METASPACE_KLASS")"METASPACE_KLASS, FN_PTR(getKlassImplementor)},
- {CC"getStackTraceElement", CC"("METASPACE_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)},
- {CC"methodIsIgnoredBySecurityStackWalk", CC"("METASPACE_METHOD")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)},
- {CC"doNotInlineOrCompile", CC"("METASPACE_METHOD")V", FN_PTR(doNotInlineOrCompile)},
- {CC"canInlineMethod", CC"("METASPACE_METHOD")Z", FN_PTR(canInlineMethod)},
- {CC"shouldInlineMethod", CC"("METASPACE_METHOD")Z", FN_PTR(shouldInlineMethod)},
- {CC"lookupType", CC"("STRING CLASS"Z)"METASPACE_KLASS, FN_PTR(lookupType)},
- {CC"resolveConstantInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolveConstantInPool)},
- {CC"resolvePossiblyCachedConstantInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)},
- {CC"lookupNameRefInPool", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_SYMBOL, FN_PTR(lookupNameRefInPool)},
- {CC"lookupNameAndTypeRefIndexInPool", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)},
- {CC"lookupSignatureRefInPool", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_SYMBOL, FN_PTR(lookupSignatureRefInPool)},
- {CC"lookupKlassRefIndexInPool", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(lookupKlassRefIndexInPool)},
- {CC"constantPoolKlassAt", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS, FN_PTR(constantPoolKlassAt)},
- {CC"lookupKlassInPool", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS, FN_PTR(lookupKlassInPool)},
- {CC"lookupAppendixInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupAppendixInPool)},
- {CC"lookupMethodInPool", CC"("METASPACE_CONSTANT_POOL"IB)"METASPACE_METHOD, FN_PTR(lookupMethodInPool)},
- {CC"constantPoolRemapInstructionOperandFromCache", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)},
- {CC"resolveField", CC"("METASPACE_CONSTANT_POOL"IB[J)"METASPACE_KLASS, FN_PTR(resolveField)},
- {CC"resolveInvokeDynamic", CC"("METASPACE_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeDynamic)},
- {CC"resolveMethod", CC"("METASPACE_KLASS STRING STRING")"METASPACE_METHOD, FN_PTR(resolveMethod)},
- {CC"getClassInitializer", CC"("METASPACE_KLASS")"METASPACE_METHOD, FN_PTR(getClassInitializer)},
- {CC"hasFinalizableSubclass", CC"("METASPACE_KLASS")Z", FN_PTR(hasFinalizableSubclass)},
- {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)},
- {CC"getMetaspaceMethod", CC"("CLASS"I)"METASPACE_METHOD, FN_PTR(getMetaspaceMethod)},
- {CC"initializeConfiguration", CC"("HS_CONFIG")V", FN_PTR(initializeConfiguration)},
- {CC"installCode0", CC"("HS_COMPILED_CODE INSTALLED_CODE SPECULATION_LOG")I", FN_PTR(installCode0)},
- {CC"notifyCompilationStatistics", CC"(I"HS_RESOLVED_METHOD"ZIJJ"INSTALLED_CODE")V", FN_PTR(notifyCompilationStatistics)},
- {CC"printCompilationStatistics", CC"(ZZ)V", FN_PTR(printCompilationStatistics)},
- {CC"resetCompilationStatistics", CC"()V", FN_PTR(resetCompilationStatistics)},
- {CC"disassembleCodeBlob", CC"(J)"STRING, FN_PTR(disassembleCodeBlob)},
- {CC"executeCompiledMethodVarargs", CC"(["OBJECT INSTALLED_CODE")"OBJECT, FN_PTR(executeCompiledMethodVarargs)},
- {CC"getLineNumberTable", CC"("METASPACE_METHOD")[J", FN_PTR(getLineNumberTable)},
- {CC"getLocalVariableTableStart", CC"("METASPACE_METHOD")J", FN_PTR(getLocalVariableTableStart)},
- {CC"getLocalVariableTableLength", CC"("METASPACE_METHOD")I", FN_PTR(getLocalVariableTableLength)},
- {CC"reprofile", CC"("METASPACE_METHOD")V", FN_PTR(reprofile)},
- {CC"invalidateInstalledCode", CC"("INSTALLED_CODE")V", FN_PTR(invalidateInstalledCode)},
- {CC"getJavaMirror", CC"("METASPACE_KLASS")"CLASS, FN_PTR(getJavaMirror)},
- {CC"readUnsafeKlassPointer", CC"("OBJECT")J", FN_PTR(readUnsafeKlassPointer)},
- {CC"collectCounters", CC"()[J", FN_PTR(collectCounters)},
- {CC"getGPUs", CC"()"STRING, FN_PTR(getGPUs)},
- {CC"allocateCompileId", CC"("METASPACE_METHOD"I)I", FN_PTR(allocateCompileId)},
- {CC"isMature", CC"("METASPACE_METHOD_DATA")Z", FN_PTR(isMature)},
- {CC"hasCompiledCodeForOSR", CC"("METASPACE_METHOD"II)Z", FN_PTR(hasCompiledCodeForOSR)},
- {CC"getTimeStamp", CC"()J", FN_PTR(getTimeStamp)},
- {CC"getNextStackFrame", CC"("HS_STACK_FRAME_REF "[JI)"HS_STACK_FRAME_REF, FN_PTR(getNextStackFrame)},
- {CC"materializeVirtualObjects", CC"("HS_STACK_FRAME_REF"Z)V", FN_PTR(materializeVirtualObjects)},
+ {CC"initializeBytecode", CC"("METASPACE_METHOD")[B", FN_PTR(initializeBytecode)},
+ {CC"exceptionTableStart", CC"("METASPACE_METHOD")J", FN_PTR(exceptionTableStart)},
+ {CC"exceptionTableLength", CC"("METASPACE_METHOD")I", FN_PTR(exceptionTableLength)},
+ {CC"hasBalancedMonitors", CC"("METASPACE_METHOD")Z", FN_PTR(hasBalancedMonitors)},
+ {CC"findUniqueConcreteMethod", CC"("METASPACE_METHOD")"METASPACE_METHOD, FN_PTR(findUniqueConcreteMethod)},
+ {CC"getKlassImplementor", CC"("METASPACE_KLASS")"METASPACE_KLASS, FN_PTR(getKlassImplementor)},
+ {CC"getStackTraceElement", CC"("METASPACE_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)},
+ {CC"methodIsIgnoredBySecurityStackWalk", CC"("METASPACE_METHOD")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)},
+ {CC"doNotInlineOrCompile", CC"("METASPACE_METHOD")V", FN_PTR(doNotInlineOrCompile)},
+ {CC"canInlineMethod", CC"("METASPACE_METHOD")Z", FN_PTR(canInlineMethod)},
+ {CC"shouldInlineMethod", CC"("METASPACE_METHOD")Z", FN_PTR(shouldInlineMethod)},
+ {CC"lookupType", CC"("STRING CLASS"Z)"METASPACE_KLASS, FN_PTR(lookupType)},
+ {CC"resolveConstantInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolveConstantInPool)},
+ {CC"resolvePossiblyCachedConstantInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)},
+ {CC"lookupNameRefInPool", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_SYMBOL, FN_PTR(lookupNameRefInPool)},
+ {CC"lookupNameAndTypeRefIndexInPool", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)},
+ {CC"lookupSignatureRefInPool", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_SYMBOL, FN_PTR(lookupSignatureRefInPool)},
+ {CC"lookupKlassRefIndexInPool", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(lookupKlassRefIndexInPool)},
+ {CC"constantPoolKlassAt", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS, FN_PTR(constantPoolKlassAt)},
+ {CC"lookupKlassInPool", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS, FN_PTR(lookupKlassInPool)},
+ {CC"lookupAppendixInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupAppendixInPool)},
+ {CC"lookupMethodInPool", CC"("METASPACE_CONSTANT_POOL"IB)"METASPACE_METHOD, FN_PTR(lookupMethodInPool)},
+ {CC"constantPoolRemapInstructionOperandFromCache", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)},
+ {CC"resolveField", CC"("METASPACE_CONSTANT_POOL"IB[J)"METASPACE_KLASS, FN_PTR(resolveField)},
+ {CC"resolveInvokeDynamic", CC"("METASPACE_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeDynamic)},
+ {CC"resolveMethod", CC"("METASPACE_KLASS METASPACE_METHOD METASPACE_KLASS")"METASPACE_METHOD, FN_PTR(resolveMethod)},
+ {CC"getVtableIndexForInterface", CC"("METASPACE_KLASS METASPACE_METHOD")I", FN_PTR(getVtableIndexForInterface)},
+ {CC"getClassInitializer", CC"("METASPACE_KLASS")"METASPACE_METHOD, FN_PTR(getClassInitializer)},
+ {CC"hasFinalizableSubclass", CC"("METASPACE_KLASS")Z", FN_PTR(hasFinalizableSubclass)},
+ {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)},
+ {CC"getMetaspaceMethod", CC"("CLASS"I)"METASPACE_METHOD, FN_PTR(getMetaspaceMethod)},
+ {CC"initializeConfiguration", CC"("HS_CONFIG")V", FN_PTR(initializeConfiguration)},
+ {CC"installCode0", CC"("HS_COMPILED_CODE INSTALLED_CODE SPECULATION_LOG")I", FN_PTR(installCode0)},
+ {CC"notifyCompilationStatistics", CC"(I"HS_RESOLVED_METHOD"ZIJJ"INSTALLED_CODE")V", FN_PTR(notifyCompilationStatistics)},
+ {CC"printCompilationStatistics", CC"(ZZ)V", FN_PTR(printCompilationStatistics)},
+ {CC"resetCompilationStatistics", CC"()V", FN_PTR(resetCompilationStatistics)},
+ {CC"disassembleCodeBlob", CC"(J)"STRING, FN_PTR(disassembleCodeBlob)},
+ {CC"executeCompiledMethodVarargs", CC"(["OBJECT INSTALLED_CODE")"OBJECT, FN_PTR(executeCompiledMethodVarargs)},
+ {CC"getLineNumberTable", CC"("METASPACE_METHOD")[J", FN_PTR(getLineNumberTable)},
+ {CC"getLocalVariableTableStart", CC"("METASPACE_METHOD")J", FN_PTR(getLocalVariableTableStart)},
+ {CC"getLocalVariableTableLength", CC"("METASPACE_METHOD")I", FN_PTR(getLocalVariableTableLength)},
+ {CC"reprofile", CC"("METASPACE_METHOD")V", FN_PTR(reprofile)},
+ {CC"invalidateInstalledCode", CC"("INSTALLED_CODE")V", FN_PTR(invalidateInstalledCode)},
+ {CC"getJavaMirror", CC"("METASPACE_KLASS")"CLASS, FN_PTR(getJavaMirror)},
+ {CC"readUnsafeKlassPointer", CC"("OBJECT")J", FN_PTR(readUnsafeKlassPointer)},
+ {CC"collectCounters", CC"()[J", FN_PTR(collectCounters)},
+ {CC"getGPUs", CC"()"STRING, FN_PTR(getGPUs)},
+ {CC"allocateCompileId", CC"("METASPACE_METHOD"I)I", FN_PTR(allocateCompileId)},
+ {CC"isMature", CC"("METASPACE_METHOD_DATA")Z", FN_PTR(isMature)},
+ {CC"hasCompiledCodeForOSR", CC"("METASPACE_METHOD"II)Z", FN_PTR(hasCompiledCodeForOSR)},
+ {CC"getTimeStamp", CC"()J", FN_PTR(getTimeStamp)},
+ {CC"getNextStackFrame", CC"("HS_STACK_FRAME_REF "[JI)"HS_STACK_FRAME_REF, FN_PTR(getNextStackFrame)},
+ {CC"materializeVirtualObjects", CC"("HS_STACK_FRAME_REF"Z)V", FN_PTR(materializeVirtualObjects)},
};
int CompilerToVM_methods_count() {
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/graal/graalJavaAccess.hpp
--- a/src/share/vm/graal/graalJavaAccess.hpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp Wed May 21 11:45:50 2014 +0200
@@ -52,13 +52,8 @@
oop_field(HotSpotResolvedObjectType, javaClass, "Ljava/lang/Class;") \
end_class \
start_class(HotSpotResolvedJavaMethod) \
- oop_field(HotSpotResolvedJavaMethod, name, "Ljava/lang/String;") \
- oop_field(HotSpotResolvedJavaMethod, holder, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;") \
long_field(HotSpotResolvedJavaMethod, metaspaceMethod) \
end_class \
- start_class(HotSpotJavaType) \
- oop_field(HotSpotJavaType, name, "Ljava/lang/String;") \
- end_class \
start_class(InstalledCode) \
long_field(InstalledCode, address) \
long_field(InstalledCode, version) \
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/graal/vmStructs_graal.hpp
--- a/src/share/vm/graal/vmStructs_graal.hpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/graal/vmStructs_graal.hpp Wed May 21 11:45:50 2014 +0200
@@ -66,5 +66,7 @@
declare_constant(CodeInstaller::POLL_FAR) \
declare_constant(CodeInstaller::POLL_RETURN_FAR) \
declare_constant(CodeInstaller::INVOKE_INVALID) \
+ \
+ declare_constant(Method::invalid_vtable_index) \
#endif // SHARE_VM_GRAAL_VMSTRUCTS_GRAAL_HPP
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/interpreter/linkResolver.hpp
--- a/src/share/vm/interpreter/linkResolver.hpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/interpreter/linkResolver.hpp Wed May 21 11:45:50 2014 +0200
@@ -125,7 +125,13 @@
private:
static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, bool checkpolymorphism, bool in_imethod_resolve, TRAPS);
+#ifdef GRAAL
+ public:
+#endif
static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
+#ifdef GRAAL
+ private:
+#endif
static void lookup_method_in_interfaces (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
static void lookup_polymorphic_method (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature,
KlassHandle current_klass, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS);
@@ -139,8 +145,14 @@
static void linktime_resolve_static_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
static void linktime_resolve_special_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
+#ifdef GRAAL
+ public:
+#endif
static void linktime_resolve_virtual_method (methodHandle &resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature,KlassHandle current_klass, bool check_access, TRAPS);
static void linktime_resolve_interface_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
+#ifdef GRAAL
+ private:
+#endif
static void runtime_resolve_special_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, bool check_access, TRAPS);
static void runtime_resolve_virtual_method (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS);
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/runtime/deoptimization.cpp
--- a/src/share/vm/runtime/deoptimization.cpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/runtime/deoptimization.cpp Wed May 21 11:45:50 2014 +0200
@@ -1348,7 +1348,7 @@
ScopeDesc* trap_scope = cvf->scope();
if (TraceDeoptimization) {
- tty->print_cr(" bci=%d pc=%d, relative_pc=%d, method=%s" GRAAL_ONLY(", debug_id=%d"), trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name_and_sig_as_C_string()
+ tty->print_cr(" bci=%d pc=" INTPTR_FORMAT ", relative_pc=%d, method=%s" GRAAL_ONLY(", debug_id=%d"), trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name_and_sig_as_C_string()
#ifdef GRAAL
, debug_id
#endif
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/runtime/globals.cpp
--- a/src/share/vm/runtime/globals.cpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/runtime/globals.cpp Wed May 21 11:45:50 2014 +0200
@@ -477,12 +477,12 @@
}
// Search the flag table for a named flag
-Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked) {
+Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked, bool allow_constant) {
for (Flag* current = &flagTable[0]; current->_name != NULL; current++) {
if (str_equal(current->_name, name, length)) {
// Found a matching entry.
// Don't report notproduct and develop flags in product builds.
- if (current->is_constant_in_binary()) {
+ if (current->is_constant_in_binary() && !allow_constant) {
return NULL;
}
// Report locked flags only if allowed.
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/runtime/globals.hpp
--- a/src/share/vm/runtime/globals.hpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/runtime/globals.hpp Wed May 21 11:45:50 2014 +0200
@@ -256,7 +256,7 @@
// number of flags
static size_t numFlags;
- static Flag* find_flag(const char* name, size_t length, bool allow_locked = false);
+ static Flag* find_flag(const char* name, size_t length, bool allow_locked = false, bool allow_constant = false);
static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false);
void check_writable();
@@ -3058,7 +3058,7 @@
"If non-zero, maximum number of words that malloc/realloc can " \
"allocate (for testing only)") \
\
- product(intx, TypeProfileWidth, 2, \
+ product_pd(intx, TypeProfileWidth, \
"Number of receiver types to record in call/cast profile") \
\
product_pd(intx, MethodProfileWidth, \
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/runtime/java.cpp
--- a/src/share/vm/runtime/java.cpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/runtime/java.cpp Wed May 21 11:45:50 2014 +0200
@@ -462,15 +462,6 @@
#define BEFORE_EXIT_DONE 2
static jint volatile _before_exit_status = BEFORE_EXIT_NOT_RUN;
-#ifdef GRAAL
-#ifdef COMPILERGRAAL
- if (GraalCompiler::instance() != NULL) {
- GraalCompiler::instance()->shutdown();
- }
-#endif
- VMToCompiler::shutdownRuntime();
-#endif
-
// Note: don't use a Mutex to guard the entire before_exit(), as
// JVMTI post_thread_end_event and post_vm_death_event will run native code.
// A CAS or OSMutex would work just fine but then we need to manipulate
@@ -492,6 +483,15 @@
}
}
+#ifdef GRAAL
+#ifdef COMPILERGRAAL
+ if (GraalCompiler::instance() != NULL) {
+ GraalCompiler::instance()->shutdown();
+ }
+#endif
+ VMToCompiler::shutdownRuntime();
+#endif
+
// The only difference between this and Win32's _onexit procs is that
// this version is invoked before any threads get killed.
ExitProc* current = exit_procs;
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/runtime/vmStructs.cpp
--- a/src/share/vm/runtime/vmStructs.cpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/runtime/vmStructs.cpp Wed May 21 11:45:50 2014 +0200
@@ -70,6 +70,9 @@
#include "oops/constMethod.hpp"
#include "oops/constantPool.hpp"
#include "oops/cpCache.hpp"
+#ifdef GRAAL
+#include "oops/fieldStreams.hpp"
+#endif
#include "oops/instanceClassLoaderKlass.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/instanceMirrorKlass.hpp"
@@ -105,6 +108,7 @@
#include "utilities/hashtable.hpp"
#include "utilities/macros.hpp"
#ifdef GRAAL
+# include "graal/graalRuntime.hpp"
# include "graal/vmStructs_graal.hpp"
# include "hsail/vm/vmStructs_hsail.hpp"
#endif
@@ -3124,7 +3128,6 @@
VM_INT_CONSTANTS_GRAAL(GENERATE_VM_INT_CONSTANT_ENTRY,
GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
- VM_INT_CONSTANTS_GPU_HSAIL(GENERATE_VM_INT_CONSTANT_ENTRY)
#endif
#if INCLUDE_ALL_GCS
@@ -3480,3 +3483,11 @@
}
}
#endif
+
+
+#ifdef GRAAL
+// Emit intialization code for HotSpotVMConfig. It's placed here so
+// it can take advantage of the relaxed access checking enjoyed by
+// VMStructs.
+#include "HotSpotVMConfig.inline.hpp"
+#endif
diff -r a43ff5d18350 -r a6eeb3750238 src/share/vm/runtime/vmStructs.hpp
--- a/src/share/vm/runtime/vmStructs.hpp Tue May 13 19:19:27 2014 +0200
+++ b/src/share/vm/runtime/vmStructs.hpp Wed May 21 11:45:50 2014 +0200
@@ -126,6 +126,10 @@
static void test();
#endif
+#ifdef GRAAL
+ static void initHotSpotVMConfig(oop config);
+#endif
+
private:
// Look up a type in localHotSpotVMTypes using strcmp() (debug build only).
// Returns 1 if found, 0 if not.