changeset 3043:47aef13c569c

Merge
author Gilles Duboscq <gilles.duboscq@oracle.com>
date Thu, 16 Jun 2011 13:09:18 +0200
parents 183389909fe3 499851efab4d
children 0c519981c6cf
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java
diffstat 8 files changed, 240 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- 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);
         }
     }
 
--- /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);
+    }
+}
--- 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<Invoke> invokes = new ArrayDeque<Invoke>();
     private final Queue<RiMethod> methods = new ArrayDeque<RiMethod>();
+
+    private final Map<Invoke, RiMethod> parentMethod = new HashMap<Invoke, RiMethod>();
     private int inliningSize;
     private final boolean trace;
 
@@ -59,6 +61,7 @@
     static HashMap<RiMethod, Integer> methodCount = new HashMap<RiMethod, Integer>();
     @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<Node, Node> 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<Node, Node> entry : duplicates.entrySet()) {
--- 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<T> implements Iterator<T> {
+    public class TypedNodeIterator<T> implements Iterator<T> {
         private final Class<T> type;
-        private final Iterator<Node> iter;
-        private Node nextNode;
+        private int index;
 
-        public TypedNodeIterator(Class<T> type, Iterator<Node> iter) {
+        public TypedNodeIterator(Class<T> 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<T>() {
             @Override
             public Iterator<T> iterator() {
-                return new TypedNodeIterator<T>(type, nodes.iterator());
+                return new TypedNodeIterator<T>(type);
             }
         };
     }
--- 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<XirTemplate> buildTemplates(CiXirAssembler asm) {
         this.globalAsm = asm;
         List<XirTemplate> templates = new ArrayList<XirTemplate>();
--- 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)  {
--- 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) \
 
--- 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; i<profile.limit(); i++) {
+      float prob = profile.receiver_prob(i);
+      ciKlass* receiver = profile.receiver(i);
+      oop type = GraalCompiler::get_RiType(receiver, KlassHandle(), CHECK_NULL);
+
+      probabilities->float_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());