# HG changeset patch # User Gilles Duboscq # Date 1308222558 -7200 # Node ID 47aef13c569ca0a310d414b0cf84f3a4c4ca61b4 # Parent 183389909fe3ac2c6f452b63e6025105902ee4a7# Parent 499851efab4d9431bd4beaf9a17278be95599620 Merge diff -r 183389909fe3 -r 47aef13c569c graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Thu Jun 16 11:35:13 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Thu Jun 16 13:09:18 2011 +0200 @@ -45,6 +45,7 @@ import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; +import com.sun.cri.ri.RiType.*; import com.sun.cri.xir.*; import com.sun.cri.xir.CiXirAssembler.*; @@ -722,6 +723,13 @@ CiValue value = load(x.object()); LIRDebugInfo info = stateFor(x); lir.nullCheck(value, info); + } else if (comp instanceof IsType) { + IsType x = (IsType) comp; + CiValue value = load(x.object()); + LIRDebugInfo info = stateFor(x); + XirArgument clazz = toXirArgument(x.type().getEncoding(Representation.ObjectHub)); + XirSnippet typeCheck = xir.genTypeCheck(site(x), toXirArgument(x.object()), clazz, x.type()); + emitXir(typeCheck, x, info, compilation.method, false); } } diff -r 183389909fe3 -r 47aef13c569c graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java Thu Jun 16 13:09:18 2011 +0200 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009, 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.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code TypeCheck} class represents an explicit type check instruction. + */ +public final class IsType extends FloatingNode { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_OBJECT = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the object tested against null. + */ + public Value object() { + return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); + } + + public Value setObject(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); + } + + private final RiType type; + + /** + * Constructs a new IsType instruction. + * @param object the instruction producing the object to check against the given type + * @param graph + */ + public IsType(Value object, RiType type, Graph graph) { + super(CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); + assert type.isResolved(); + assert object == null || object.kind == CiKind.Object; + this.type = type; + setObject(object); + } + + public RiType type() { + return type; + } + + @Override + public void accept(ValueVisitor v) { + // Nothing to do. + } + + @Override + public int valueNumber() { + return Util.hash1(Bytecodes.CHECKCAST, object()); + } + + @Override + public boolean valueEqual(Node i) { + if (i instanceof IsType) { + IsType o = (IsType) i; + return type == o.type() && object() == o.object(); + } + return false; + } + + @Override + public RiType declaredType() { + // type check does not alter the type of the object + return object().declaredType(); + } + + @Override + public RiType exactType() { + return type; + } + + @Override + public void print(LogStream out) { + out.print("null_check(").print(object()).print(')'); + } + + @Override + public Node copy(Graph into) { + return new IsType(null, type, into); + } +} diff -r 183389909fe3 -r 47aef13c569c graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Thu Jun 16 11:35:13 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Thu Jun 16 13:09:18 2011 +0200 @@ -41,6 +41,8 @@ private final Queue invokes = new ArrayDeque(); private final Queue methods = new ArrayDeque(); + + private final Map parentMethod = new HashMap(); private int inliningSize; private final boolean trace; @@ -59,6 +61,7 @@ static HashMap methodCount = new HashMap(); @Override protected void run(Graph graph) { + float ratio = GraalOptions.MaximumInlineRatio; inliningSize = compilation.method.code().length; for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) { for (Invoke invoke : graph.getNodes(Invoke.class)) { @@ -69,7 +72,9 @@ } continue; } - if (!checkInliningConditions(invoke) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { + + RiTypeProfile profile = compilation.method.typeProfile(invoke.bci); + if (!checkInliningConditions(invoke, profile, ratio) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { continue; } if (target.canBeStaticallyBound()) { @@ -78,13 +83,29 @@ } } else { RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); - if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { - if (checkInliningConditions(concrete, iterations)) { + if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags()) && checkInliningConditions(concrete, iterations)) { + if (trace) { + System.out.println("recording concrete method assumption..."); + } + compilation.assumptions.recordConcreteMethod(invoke.target, concrete); + addToQueue(invoke, concrete); + } else if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) { + // type check and inlining... + concrete = profile.types[0].resolveMethodImpl(invoke.target); + if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags()) && checkInliningConditions(concrete, iterations)) { + IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph); + FixedGuard guard = new FixedGuard(graph); + guard.setNode(isType); + assert invoke.predecessors().size() == 1; + invoke.predecessors().get(0).successors().replace(invoke, guard); + guard.setNext(invoke); + if (trace) { - System.out.println("recording concrete method assumption..."); + System.out.println("inlining with type check, type probability: " + profile.probabilities[0]); } - compilation.assumptions.recordConcreteMethod(invoke.target, concrete); addToQueue(invoke, concrete); +// System.out.println("inlining with type check " + profile.probabilities[0] + " " + profile.morphism + " " + profile.count); +// System.out.println(invoke.target + " -> " + concrete + " (" + profile.types[0] + ")"); } } } @@ -118,6 +139,7 @@ } break; } + ratio *= GraalOptions.MaximumInlineRatio; } if (trace) { @@ -133,9 +155,13 @@ } } - private boolean checkInliningConditions(Invoke invoke) { + private boolean checkInliningConditions(Invoke invoke, RiTypeProfile profile, float ratio) { String name = !trace ? null : invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false); - if (invoke.profile() != null && invoke.profile().count < compilation.method.invocationCount() / 2) { + RiMethod parent = parentMethod.get(invoke); + if (parent == null) { + parent = compilation.method; + } + if (profile == null || profile.count < parent.invocationCount() * (1 - ratio)) { if (trace) { System.out.println("not inlining " + name + " because the invocation counter is too low"); } @@ -251,6 +277,12 @@ Map duplicates = compilation.graph.addDuplicate(nodes, replacements); + for (Node node : duplicates.values()) { + if (node instanceof Invoke) { + parentMethod.put((Invoke) node, method); + } + } + int monitorIndexDelta = stateAfter.locksSize(); if (monitorIndexDelta > 0) { for (Map.Entry entry : duplicates.entrySet()) { diff -r 183389909fe3 -r 47aef13c569c graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Graph.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Graph.java Thu Jun 16 11:35:13 2011 +0200 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Graph.java Thu Jun 16 13:09:18 2011 +0200 @@ -63,37 +63,37 @@ return Collections.unmodifiableList(nodes); } - public static class TypedNodeIterator implements Iterator { + public class TypedNodeIterator implements Iterator { private final Class type; - private final Iterator iter; - private Node nextNode; + private int index; - public TypedNodeIterator(Class type, Iterator iter) { + public TypedNodeIterator(Class type) { this.type = type; - this.iter = iter; + this.index = -1; forward(); } private void forward() { - do { - if (!iter.hasNext()) { - nextNode = null; - return; + if (index < nodes.size()) { + do { + index++; + } while (index < nodes.size() && !type.isInstance(nodes.get(index))); + if (index >= nodes.size()) { + index = Integer.MAX_VALUE; } - nextNode = iter.next(); - } while (nextNode == null || !type.isInstance(nextNode)); + } } @Override public boolean hasNext() { - return nextNode != null; + return index < nodes.size(); } @Override @SuppressWarnings("unchecked") public T next() { try { - return (T) nextNode; + return (T) nodes.get(index); } finally { forward(); } @@ -109,7 +109,7 @@ return new Iterable() { @Override public Iterator iterator() { - return new TypedNodeIterator(type, nodes.iterator()); + return new TypedNodeIterator(type); } }; } diff -r 183389909fe3 -r 47aef13c569c graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java Thu Jun 16 11:35:13 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java Thu Jun 16 13:09:18 2011 +0200 @@ -36,6 +36,7 @@ import com.sun.cri.ri.*; import com.sun.cri.ri.RiType.*; import com.sun.cri.xir.*; +import com.sun.cri.xir.CiXirAssembler.XirLabel; import com.sun.cri.xir.CiXirAssembler.*; public class HotSpotXirGenerator implements RiXirGenerator { @@ -627,7 +628,7 @@ asm.callRuntime(CiRuntimeCall.Deoptimize, null); asm.shouldNotReachHere(); - return asm.finishTemplate(object, "instanceof"); + return asm.finishTemplate(object, "checkcast"); } }; @@ -730,7 +731,7 @@ } asm.pload(CiKind.Object, result, object, asm.i(config.hubOffset), is(NULL_CHECK, flags)); asm.pload(CiKind.Object, result, result, asm.i(config.classMirrorOffset), false); - return asm.finishTemplate("currentThread"); + return asm.finishTemplate("getClass"); } }; @@ -1023,6 +1024,39 @@ } }; + private SimpleTemplates typeCheckTemplates = new SimpleTemplates(NULL_CHECK) { + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(); + XirParameter object = asm.createInputParameter("object", CiKind.Object); + XirOperand hub = asm.createConstantInputParameter("hub", CiKind.Object); + + XirOperand objHub = asm.createTemp("objHub", CiKind.Object); + + XirLabel slowPath = asm.createOutOfLineLabel("deopt"); + + if (is(NULL_CHECK, flags)) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + + asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false); + // if we get an exact match: continue + asm.jneq(slowPath, objHub, hub); + asm.shouldNotReachHere(); + + // -- out of line ------------------------------------------------------- + asm.bindOutOfLine(slowPath); + XirOperand scratch = asm.createRegisterTemp("scratch", CiKind.Word, AMD64.r10); + asm.mov(scratch, asm.createConstant(CiConstant.forWord(2))); + + asm.callRuntime(CiRuntimeCall.Deoptimize, null); + asm.shouldNotReachHere(); + + return asm.finishTemplate(object, "typeCheck"); + } + }; + @Override public XirSnippet genPrologue(XirSite site, RiMethod method) { boolean staticMethod = Modifier.isStatic(method.accessFlags()); @@ -1195,6 +1229,12 @@ } @Override + public XirSnippet genTypeCheck(XirSite site, XirArgument object, XirArgument hub, RiType type) { + assert type.isResolved(); + return new XirSnippet(typeCheckTemplates.get(site), object, hub); + } + + @Override public List buildTemplates(CiXirAssembler asm) { this.globalAsm = asm; List templates = new ArrayList(); diff -r 183389909fe3 -r 47aef13c569c src/share/vm/ci/ciCallProfile.hpp --- a/src/share/vm/ci/ciCallProfile.hpp Thu Jun 16 11:35:13 2011 +0200 +++ b/src/share/vm/ci/ciCallProfile.hpp Thu Jun 16 13:09:18 2011 +0200 @@ -60,6 +60,7 @@ // Note: The following predicates return false for invalid profiles: bool has_receiver(int i) { return _limit > i; } int morphism() { return _morphism; } + int limit() { return _limit; } int count() { return _count; } int receiver_count(int i) { diff -r 183389909fe3 -r 47aef13c569c src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Thu Jun 16 11:35:13 2011 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Thu Jun 16 13:09:18 2011 +0200 @@ -212,6 +212,7 @@ template(CiKind_klass, com_sun_cri_ci_CiKind, Opt) \ template(CiRuntimeCall_klass, com_sun_cri_ci_CiRuntimeCall, Opt) \ template(RiMethod_klass, com_sun_cri_ri_RiMethod, Opt) \ + template(RiType_klass, com_sun_cri_ri_RiType, Opt) \ template(RiExceptionHandler_klass, com_sun_cri_ri_RiExceptionHandler, Opt) \ template(RiTypeProfile_klass, com_sun_cri_ri_RiTypeProfile, Opt) \ diff -r 183389909fe3 -r 47aef13c569c src/share/vm/graal/graalVMEntries.cpp --- a/src/share/vm/graal/graalVMEntries.cpp Thu Jun 16 11:35:13 2011 +0200 +++ b/src/share/vm/graal/graalVMEntries.cpp Thu Jun 16 13:09:18 2011 +0200 @@ -186,8 +186,20 @@ RiTypeProfile::set_count(obj, cimethod->scale_count(profile.count(), 1)); RiTypeProfile::set_morphism(obj, profile.morphism()); - RiTypeProfile::set_probabilities(obj, NULL); - RiTypeProfile::set_types(obj, NULL); + typeArrayHandle probabilities = oopFactory::new_typeArray(T_FLOAT, profile.limit(), CHECK_NULL); + objArrayHandle types = oopFactory::new_objArray(SystemDictionary::RiType_klass(), profile.limit(), CHECK_NULL); + for (int i=0; ifloat_at_put(i, prob); + types->obj_at_put(i, type); + } + + RiTypeProfile::set_probabilities(obj, probabilities()); + RiTypeProfile::set_types(obj, types()); + } return JNIHandles::make_local(obj());