/* * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.cri.ci; import java.io.*; import java.util.*; import com.sun.cri.ri.*; /** * Records optimistic assumptions made during compilation. * * Each instance of this class is capable of recording a list of {@link Assumption assumptions} that can be retrieved * using {@link #iterator()}. * * A fixed set of standard {@linkplain Assumption assumptions} are defined here along with methods to record them. * Processing the assumptions is the responsibility of a specific VM/compiler combination and is not addressed here. */ public final class CiAssumptions implements Serializable, Iterable<CiAssumptions.Assumption> { public abstract static class Assumption implements Serializable { } public abstract static class ContextAssumption extends Assumption { /** * Type the assumption is made about. */ public final RiResolvedType context; public ContextAssumption(RiResolvedType context) { this.context = context; } protected static final int prime = 31; @Override public int hashCode() { return prime + context.hashCode(); } } /** * An assumption about a unique subtype of a given type. */ public static final class ConcreteSubtype extends ContextAssumption { /** * Assumed unique concrete sub-type of the context type. */ public final RiResolvedType subtype; public ConcreteSubtype(RiResolvedType context, RiResolvedType subtype) { super(context); this.subtype = subtype; } @Override public int hashCode() { return super.hashCode() * prime + subtype.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof ConcreteSubtype) { ConcreteSubtype other = (ConcreteSubtype) obj; return other.context == context && other.subtype == subtype; } return false; } } /** * Captures a generic dependency between two methods. */ public static abstract class DependentMethod extends ContextAssumption { public final RiResolvedMethod method; /** * A {@link RiResolvedMethod} that {@link #dependee} depends on in some way. */ public final RiResolvedMethod dependee; public DependentMethod(RiResolvedMethod method, RiResolvedType context, RiResolvedMethod dependee) { super(context); this.method = method; this.dependee = dependee; } @Override public int hashCode() { int result = super.hashCode(); result = prime * result + method.hashCode(); return prime * result + dependee.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof DependentMethod) { DependentMethod other = (DependentMethod) obj; return other.method == method && other.context == context && other.dependee == dependee; } return false; } } /** * An assumption about a unique implementation of a virtual method. */ public static final class ConcreteMethod extends DependentMethod { /** * * @param method a virtual (or interface) method whose unique implementation for the receiver type * in {@link #context} is {@link #dependee}. * @param context * @param impl the unique implementation of {@link #method} for {@link #context} */ public ConcreteMethod(RiResolvedMethod method, RiResolvedType context, RiResolvedMethod impl) { // dependee == impl super(method, context, impl); } @Override public boolean equals(Object obj) { if (obj instanceof ConcreteMethod) { return super.equals(obj); } return false; } } /** * An assumption about a inlined method. */ public static final class InlinedMethod extends DependentMethod { /** * * @param method the method in which {@code includee} is being inlined into * @param context {@code method.holder()} * @param includee the method being inlined */ public InlinedMethod(RiResolvedMethod method, RiResolvedType context, RiResolvedMethod includee) { // dependee == includee super(method, context, includee); } @Override public boolean equals(Object obj) { if (obj instanceof InlinedMethod) { return super.equals(obj); } return false; } } /** * Array with the assumptions. This field is directly accessed from C++ code in the Graal/HotSpot implementation. */ private Assumption[] list; private int count; /** * Returns whether any assumptions have been registered. * @return {@code true} if at least one assumption has been registered, {@code false} otherwise. */ public boolean isEmpty() { return count == 0; } @Override public Iterator<Assumption> iterator() { return new Iterator<CiAssumptions.Assumption>() { int index; public void remove() { throw new UnsupportedOperationException(); } public Assumption next() { if (index >= count) { throw new NoSuchElementException(); } return list[index++]; } public boolean hasNext() { return index < count; } }; } /** * Records an assumption that the specified type has no finalizable subclasses. * * @param receiverType the type that is assumed to have no finalizable subclasses * @return {@code true} if the assumption was recorded and can be assumed; {@code false} otherwise */ public boolean recordNoFinalizableSubclassAssumption(RiResolvedType receiverType) { return false; } /** * 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 */ public void recordConcreteSubtype(RiResolvedType context, RiResolvedType subtype) { record(new ConcreteSubtype(context, subtype)); } /** * 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 */ public void recordConcreteMethod(RiResolvedMethod method, RiResolvedType context, RiResolvedMethod impl) { record(new ConcreteMethod(method, context, impl)); } /** * Record that {@code inlinee} has been inlined into {@code method}. * @param method the method that is inlining the inlinee * @param inlinee the method being inlined */ public void recordInlinedMethod(RiResolvedMethod method, RiResolvedMethod inlinee) { record(new InlinedMethod(method, method.holder(), inlinee)); } public void record(Assumption assumption) { if (list == null) { list = new Assumption[4]; } else { for (int i = 0; i < count; ++i) { if (assumption.equals(list[i])) { return; } } } if (list.length == count) { Assumption[] newList = new Assumption[list.length * 2]; for (int i = 0; i < list.length; ++i) { newList[i] = list[i]; } list = newList; } list[count] = assumption; count++; } }