# HG changeset patch
# User Michael Van De Vanter
# Date 1400545290 25200
# Node ID bdf260d8e1639c9e0b8da7e6d444b988defc91b2
# Parent 8c34e2cc4add5e203601764f1a226066540202cb# Parent 9ae1d2f3bda60f9d91243c883c5aa7812e2ab256
Merge with 9ae1d2f3bda60f9d91243c883c5aa7812e2ab256
diff -r 8c34e2cc4add -r bdf260d8e163 CHANGELOG.md
--- a/CHANGELOG.md Mon May 19 17:14:36 2014 -0700
+++ b/CHANGELOG.md Mon May 19 17:21:30 2014 -0700
@@ -3,6 +3,8 @@
## `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.
### Truffle
* `truffle.jar`: strip out build-time only dependency into a seperated JAR file (`truffle-dsl-processor.jar`)
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Mon May 19 17:21:30 2014 -0700
@@ -214,7 +214,7 @@
* @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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCallTest.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Mon May 19 17:21:30 2014 -0700
@@ -197,4 +197,9 @@
public boolean contains(Node node) {
return isMarked(node);
}
+
+ @Override
+ public String toString() {
+ return snapshot().toString();
+ }
}
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon May 19 17:21:30 2014 -0700
@@ -737,6 +737,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;
@@ -1064,6 +1066,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;
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Mon May 19 17:21:30 2014 -0700
@@ -248,7 +248,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 +353,6 @@
void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
void resolveInvokeDynamic(long metaspaceConstantPool, int index);
+
+ int getVtableIndexForInterface(long metaspaceKlass, long metaspaceMethod);
}
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Mon May 19 17:21:30 2014 -0700
@@ -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.*;
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java Mon May 19 17:21:30 2014 -0700
@@ -163,7 +163,7 @@
}
@Override
- public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
+ public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
return null;
}
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/ArithmeticLIRGenerator.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampJoinTest.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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.assertNotSame(StampFactory.object(), 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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Mon May 19 17:21:30 2014 -0700
@@ -187,6 +187,10 @@
} while (false);
}
+ if (checkForUnsignedCompare(tool)) {
+ return;
+ }
+
if (condition() instanceof LogicConstantNode) {
LogicConstantNode c = (LogicConstantNode) condition();
if (c.getValue()) {
@@ -219,7 +223,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);
@@ -243,6 +247,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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Mon May 19 17:21:30 2014 -0700
@@ -54,10 +54,6 @@
@Override
public boolean inferStamp() {
- return inferPhiStamp();
- }
-
- public boolean inferPhiStamp() {
return updateStamp(StampTool.meet(values()));
}
}
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java Mon May 19 17:21:30 2014 -0700
@@ -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,85 @@
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;
- }
- if (deopt.getSpeculation() != null && !deopt.getSpeculation().equals(Constant.NULL_OBJECT)) {
+ private static void tryUseTrappingNullCheck(MetaAccessProvider metaAccessProvider, DynamicDeoptimizeNode deopt) {
+ ValueNode speculation = deopt.getSpeculation();
+ if (!speculation.isConstant() || !speculation.asConstant().equals(Constant.NULL_OBJECT)) {
return;
}
Node predecessor = deopt.predecessor();
+ if (predecessor instanceof MergeNode) {
+ MergeNode merge = (MergeNode) predecessor;
+
+ if (merge.phis().isEmpty()) {
+ // Process each predecessor at the merge, unpacking the reasons as needed.
+ ValueNode reason = deopt.getActionAndReason();
+ List values = reason instanceof ValuePhiNode ? ((ValuePhiNode) reason).values().snapshot() : null;
+
+ int index = 0;
+ for (AbstractEndNode end : merge.cfgPredecessors().snapshot()) {
+ ValueNode thisReason = values != null ? values.get(index++) : reason;
+ if (thisReason.isConstant()) {
+ DeoptimizationReason deoptimizationReason = metaAccessProvider.decodeDeoptReason(thisReason.asConstant());
+ tryUseTrappingNullCheck(deopt, end.predecessor(), deoptimizationReason, null);
+ }
+ }
+ }
+ }
+ }
+
+ private static void tryUseTrappingNullCheck(AbstractDeoptimizeNode deopt, Node predecessor, DeoptimizationReason deoptimizationReason, Constant speculation) {
+ if (deoptimizationReason != DeoptimizationReason.NullCheckException && deoptimizationReason != DeoptimizationReason.UnreachedCode) {
+ return;
+ }
+ 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 +135,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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ /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 8c34e2cc4add -r bdf260d8e163 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/DepthSearchUtil.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/DepthSearchUtil.java Mon May 19 17:14:36 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +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.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.tiers.HighTierContext;
-
-import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
-
-/**
- * The workings of {@link InliningPhase#run(StructuredGraph, HighTierContext)} include delving into
- * a callsite to explore inlining opportunities. The utilities used for that are grouped in this
- * class.
- */
-public class DepthSearchUtil {
-
- private DepthSearchUtil() {
- // no instances
- }
-
- static InliningUtil.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 InliningUtil.InlineableMacroNode(macroNodeClass);
- } else {
- return new InliningUtil.InlineableGraph(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;
- }
-}
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ /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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java Mon May 19 17:21:30 2014 -0700
@@ -22,36 +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.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")
@@ -65,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);
}
@@ -95,16 +74,17 @@
/**
*
* The space of inlining decisions is explored depth-first with the help of a stack realized by
- * {@link InliningData}. At any point in time, its topmost element consist of:
+ * {@link com.oracle.graal.phases.common.inlining.walker.InliningData}. At any point in time,
+ * its topmost element consist of:
*
* -
- * one or more {@link GraphInfo}s of inlining candidates, all of them corresponding to a single
- * callsite (details below). For example, "exact inline" leads to a single candidate.
+ * 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 MethodInvocation#totalGraphs()} and {@link MethodInvocation#processedGraphs()}
- * indicates the topmost {@link GraphInfo}s that might be delved-into to explore inlining
- * opportunities.
+ * 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.
*
*
*
@@ -112,10 +92,11 @@
* The bottom-most element in the stack consists of:
*
* -
- * a single {@link GraphInfo} (the root one, for the method on which inlining was called)
+ * a single {@link CallsiteHolder} (the root one, for the method on which inlining was called)
* -
- * a single {@link MethodInvocation} (the {@link MethodInvocation#isRoot} one, ie the unknown
- * caller of the root graph)
+ * a single {@link MethodInvocation} (the
+ * {@link com.oracle.graal.phases.common.inlining.walker.MethodInvocation#isRoot} one, ie the
+ * unknown caller of the root graph)
*
*
*
@@ -132,7 +113,8 @@
*
* 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 InliningData}, and then remove such callsite.
+ * element of {@link com.oracle.graal.phases.common.inlining.walker.InliningData}, and then
+ * remove such callsite.
*
*
*
@@ -141,12 +123,12 @@
*
* -
* the first step amounts to backtracking, the 2nd one to delving, and the 3rd one also involves
- * bakctraking (however after may-be inlining).
+ * 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 one aren't picked
+ * 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.
@@ -156,35 +138,12 @@
*/
@Override
protected void run(final StructuredGraph graph, final HighTierContext context) {
- final InliningData data = new InliningData(graph, context.getAssumptions(), maxMethodPerInlining, canonicalizer);
- ToDoubleFunction probabilities = new FixedNodeProbabilityCache();
+ final InliningData data = new InliningData(graph, context, maxMethodPerInlining, canonicalizer, inliningPolicy);
while (data.hasUnprocessedGraphs()) {
- final MethodInvocation currentInvocation = data.currentInvocation();
- 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 (data.currentGraph().hasRemainingInvokes() && inliningPolicy.continueInlining(data.currentGraph().graph())) {
- data.processNextInvoke(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++;
}
}
@@ -192,552 +151,4 @@
assert data.graphCount() == 0;
}
- 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 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 final int maxMethodPerInlining;
- private final CanonicalizerPhase canonicalizer;
-
- private int maxGraphs;
-
- public InliningData(StructuredGraph rootGraph, Assumptions rootAssumptions, int maxMethodPerInlining, CanonicalizerPhase canonicalizer) {
- this.graphQueue = new ArrayDeque<>();
- this.invocationQueue = new ArrayDeque<>();
- this.maxMethodPerInlining = maxMethodPerInlining;
- this.canonicalizer = canonicalizer;
- this.maxGraphs = 1;
-
- invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
- pushGraph(rootGraph, 1.0, 1.0);
- }
-
- /**
- * Process the next invoke and enqueue all its graphs for processing.
- */
- void processNextInvoke(HighTierContext context) {
- GraphInfo graphInfo = currentGraph();
- Invoke invoke = graphInfo.popInvoke();
- MethodInvocation callerInvocation = currentInvocation();
- Assumptions parentAssumptions = callerInvocation.assumptions();
- InlineInfo info = InliningUtil.getInlineInfo(this, invoke, maxMethodPerInlining, context.getReplacements(), parentAssumptions, context.getOptimisticOptimizations());
-
- if (info != null) {
- double invokeProbability = graphInfo.invokeProbability(invoke);
- double invokeRelevance = graphInfo.invokeRelevance(invoke);
- MethodInvocation calleeInvocation = pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance);
-
- for (int i = 0; i < info.numberOfMethods(); i++) {
- Inlineable elem = DepthSearchUtil.getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeInvocation.assumptions()), canonicalizer);
- info.setInlinableElement(i, elem);
- if (elem instanceof InlineableGraph) {
- pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
- } else {
- assert elem instanceof InlineableMacroNode;
- pushDummyGraph();
- }
- }
- }
- }
-
- 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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon May 19 17:21:30 2014 -0700
@@ -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;
@@ -52,14 +47,11 @@
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.*;
+import com.oracle.graal.phases.common.inlining.walker.InliningData;
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,13 +60,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();
@@ -155,22 +140,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 +166,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 +228,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,44 +243,56 @@
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) {
+ 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";
+ }
+ 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 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 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;
}
- private static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) {
+ public static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) {
+ String failureMessage = null;
if (method == null) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method is not resolved");
+ failureMessage = "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");
+ failureMessage = "it is a non-intrinsic native method";
} else if (method.isAbstract()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is an abstract method");
+ failureMessage = "it is an abstract method";
} else if (!method.getDeclaringClass().isInitialized()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method's class is not initialized");
+ failureMessage = "the method's class is not initialized";
} else if (!method.canBeInlined()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is marked non-inlinable");
+ failureMessage = "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");
+ failureMessage = "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");
+ failureMessage = "the callee uses less optimistic optimizations than caller";
+ }
+ if (failureMessage == null) {
+ return true;
} else {
- return true;
+ logNotInlined(invoke, data.inliningDepth(), method, failureMessage);
+ return false;
}
}
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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.InliningUtil.Inlineable;
+import com.oracle.graal.phases.common.inlining.InliningUtil.InlineableMacroNode;
+import com.oracle.graal.phases.common.inlining.InliningUtil.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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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.util.Providers;
+import com.oracle.graal.phases.common.inlining.InliningUtil.Inlineable;
+
+/**
+ * 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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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.InliningUtil;
+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);
+
+ InliningUtil.Inlineable inlineableElementAt(int index);
+
+ double probabilityAt(int index);
+
+ double relevanceAt(int index);
+
+ void setInlinableElement(int index, InliningUtil.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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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.InliningUtil.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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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.util.Providers;
+import com.oracle.graal.phases.common.inlining.InliningUtil.Inlineable;
+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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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.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 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++) {
+ InliningUtil.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++) {
+ InliningUtil.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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/DepthSearchUtil.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/DepthSearchUtil.java Mon May 19 17:21:30 2014 -0700
@@ -0,0 +1,149 @@
+/*
+ * 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.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;
+
+/**
+ * The workings of {@link InliningData} include delving into a callsite to explore inlining
+ * opportunities. The utilities used for that are grouped in this class.
+ */
+public class DepthSearchUtil {
+
+ private DepthSearchUtil() {
+ // no instances
+ }
+
+ public static InliningUtil.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 InliningUtil.InlineableMacroNode(macroNodeClass);
+ } else {
+ return new InliningUtil.InlineableGraph(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;
+ }
+}
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -0,0 +1,553 @@
+/*
+ * 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.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.MegamorphicInliningMinMethodProbability;
+import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
+
+/**
+ * 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);
+ }
+
+ /**
+ * 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 (!InliningUtil.checkTargetConditions(this, context.getReplacements(), invoke, concrete, optimisticOpts)) {
+ 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 (!InliningUtil.checkTargetConditions(this, context.getReplacements(), invoke, concrete, optimisticOpts)) {
+ 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 (!InliningUtil.checkTargetConditions(this, context.getReplacements(), invoke, concrete, context.getOptimisticOptimizations())) {
+ return null;
+ }
+ return new AssumptionInlineInfo(invoke, concrete, takenAssumption);
+ }
+
+ private InlineInfo getExactInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) {
+ assert !targetMethod.isAbstract();
+ if (!InliningUtil.checkTargetConditions(this, context.getReplacements(), invoke, targetMethod, context.getOptimisticOptimizations())) {
+ return null;
+ }
+ return new ExactInlineInfo(invoke, targetMethod);
+ }
+
+ private void doInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInfo, Assumptions callerAssumptions) {
+ StructuredGraph callerGraph = callerCallsiteHolder.graph();
+ Graph.Mark markBeforeInlining = callerGraph.getMark();
+ InlineInfo callee = calleeInfo.callee();
+ try {
+ try (Debug.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()) {
+ 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(callee.toString());
+ } catch (GraalInternalError e) {
+ throw e.addContext(callee.toString());
+ }
+ }
+
+ /**
+ * @return true iff inlining was actually performed
+ */
+ private boolean tryToInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInfo, MethodInvocation parentInvocation, int inliningDepth) {
+ InlineInfo callee = calleeInfo.callee();
+ Assumptions callerAssumptions = parentInvocation.assumptions();
+ metricInliningConsidered.increment();
+
+ if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), callee, inliningDepth, calleeInfo.probability(), calleeInfo.relevance(), true)) {
+ doInline(callerCallsiteHolder, calleeInfo, callerAssumptions);
+ return true;
+ }
+
+ if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
+ callee.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();
+ InlineInfo info = getInlineInfo(invoke, parentAssumptions);
+
+ if (info != null) {
+ double invokeProbability = callsiteHolder.invokeProbability(invoke);
+ double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
+ MethodInvocation calleeInvocation = pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance);
+
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ InliningUtil.Inlineable elem = DepthSearchUtil.getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeInvocation.assumptions()), canonicalizer);
+ info.setInlinableElement(i, elem);
+ if (elem instanceof InliningUtil.InlineableGraph) {
+ pushGraph(((InliningUtil.InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
+ } else {
+ assert elem instanceof InliningUtil.InlineableMacroNode;
+ pushDummyGraph();
+ }
+ }
+ }
+ }
+
+ 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 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;
+ }
+
+ 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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/SinglePassNodeIterator.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Mon May 19 17:21:30 2014 -0700
@@ -136,6 +136,8 @@
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.assertEquals(message, expected, actual);
}
} else {
Assert.assertEquals(message, expected, actual);
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalVerboseTextListener.java Mon May 19 17:21:30 2014 -0700
@@ -65,8 +65,7 @@
@Override
public void testFailed(Failure failure) {
- getWriter().println("FAILED");
- failure.getException().printStackTrace(getWriter());
+ getWriter().print("FAILED");
}
@Override
diff -r 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/ExactMathSubstitutions.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExactMath.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 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 Mon May 19 17:14:36 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 mx/mx_graal.py
--- a/mx/mx_graal.py Mon May 19 17:14:36 2014 -0700
+++ b/mx/mx_graal.py Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 mx/projects
--- a/mx/projects Mon May 19 17:14:36 2014 -0700
+++ b/mx/projects Mon May 19 17:21:30 2014 -0700
@@ -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
@@ -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
@@ -191,6 +191,16 @@
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 +578,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
diff -r 8c34e2cc4add -r bdf260d8e163 mxtool/mx.py
--- a/mxtool/mx.py Mon May 19 17:14:36 2014 -0700
+++ b/mxtool/mx.py Mon May 19 17:21:30 2014 -0700
@@ -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')
@@ -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)
@@ -2622,9 +2747,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 = []
@@ -2868,10 +2991,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 +3158,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 +3199,7 @@
libraryDeps -= set(dep.all_deps([], True))
else:
libraryDeps.add(dep)
- else:
+ elif dep.isProject():
projectDeps.add(dep)
for dep in containerDeps:
@@ -3087,8 +3208,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 +3365,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 +3674,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 +3715,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 +3850,6 @@
continue
if dep.isLibrary():
- if not dep.mustExist:
- continue
path = dep.get_path(resolve=True)
if path:
if os.sep == '\\':
@@ -3747,7 +3858,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 +3925,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 +3972,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 +4046,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 8c34e2cc4add -r bdf260d8e163 src/share/vm/graal/graalCodeInstaller.cpp
--- a/src/share/vm/graal/graalCodeInstaller.cpp Mon May 19 17:14:36 2014 -0700
+++ b/src/share/vm/graal/graalCodeInstaller.cpp Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 src/share/vm/graal/graalCompilerToVM.cpp
--- a/src/share/vm/graal/graalCompilerToVM.cpp Mon May 19 17:14:36 2014 -0700
+++ b/src/share/vm/graal/graalCompilerToVM.cpp Mon May 19 17:21:30 2014 -0700
@@ -468,11 +468,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;
+
+ 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))
@@ -1058,58 +1123,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)[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 8c34e2cc4add -r bdf260d8e163 src/share/vm/graal/vmStructs_graal.hpp
--- a/src/share/vm/graal/vmStructs_graal.hpp Mon May 19 17:14:36 2014 -0700
+++ b/src/share/vm/graal/vmStructs_graal.hpp Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 src/share/vm/interpreter/linkResolver.hpp
--- a/src/share/vm/interpreter/linkResolver.hpp Mon May 19 17:14:36 2014 -0700
+++ b/src/share/vm/interpreter/linkResolver.hpp Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 src/share/vm/runtime/deoptimization.cpp
--- a/src/share/vm/runtime/deoptimization.cpp Mon May 19 17:14:36 2014 -0700
+++ b/src/share/vm/runtime/deoptimization.cpp Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 src/share/vm/runtime/globals.hpp
--- a/src/share/vm/runtime/globals.hpp Mon May 19 17:14:36 2014 -0700
+++ b/src/share/vm/runtime/globals.hpp Mon May 19 17:21:30 2014 -0700
@@ -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 8c34e2cc4add -r bdf260d8e163 src/share/vm/runtime/java.cpp
--- a/src/share/vm/runtime/java.cpp Mon May 19 17:14:36 2014 -0700
+++ b/src/share/vm/runtime/java.cpp Mon May 19 17:21:30 2014 -0700
@@ -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;