/*
 * 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 jdk.vm.ci.meta;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

Class for recording assumptions made during compilation.
/** * Class for recording assumptions made during compilation. */
public final class Assumptions implements Iterable<Assumptions.Assumption> {
Abstract base class for assumptions. An assumption assumes a property of the runtime that may be invalidated by subsequent execution (e.g., that a class has no subclasses implementing Object.finalize()).
/** * Abstract base class for assumptions. An assumption assumes a property of the runtime that may * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing * {@link NoFinalizableSubclass Object.finalize()}). */
public abstract static class Assumption { }
A class for providing information that is only valid in association with a set of Assumptions. It is permissible for AssumptionResults to have no assumptions at all. For instance, if ResolvedJavaType.isLeaf() returns true for a type ResolvedJavaType.findLeafConcreteSubtype() can return an AssumptionResult with no assumptions since the leaf information is statically true.
Type parameters:
  • <T> –
/** * A class for providing information that is only valid in association with a set of * {@link Assumption}s. It is permissible for AssumptionResults to have no assumptions at all. * For instance, if {@link ResolvedJavaType#isLeaf()} returns true for a type * {@link ResolvedJavaType#findLeafConcreteSubtype()} can return an AssumptionResult with no * assumptions since the leaf information is statically true. * * @param <T> */
public static class AssumptionResult<T> { Assumption[] assumptions; final T result; private static final Assumption[] EMPTY = new Assumption[0]; public AssumptionResult(T result, Assumption... assumptions) { this.result = result; this.assumptions = assumptions; } public AssumptionResult(T result) { this(result, EMPTY); } public T getResult() { return result; } public boolean isAssumptionFree() { return assumptions.length == 0; } public void add(AssumptionResult<T> other) { Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length); System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length); this.assumptions = newAssumptions; } public boolean canRecordTo(Assumptions target) { /* * We can use the result if it is either assumption free, or if we have a valid * Assumptions object where we can record assumptions. */ return assumptions.length == 0 || target != null; } public void recordTo(Assumptions target) { assert canRecordTo(target); if (assumptions.length > 0) { for (Assumption assumption : assumptions) { target.record(assumption); } } } }
An assumption that a given class has no subclasses implementing Object.finalize()).
/** * An assumption that a given class has no subclasses implementing {@link Object#finalize()}). */
public static final class NoFinalizableSubclass extends Assumption { private ResolvedJavaType receiverType; public NoFinalizableSubclass(ResolvedJavaType receiverType) { this.receiverType = receiverType; } @Override public int hashCode() { return 31 + receiverType.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof NoFinalizableSubclass) { NoFinalizableSubclass other = (NoFinalizableSubclass) obj; return other.receiverType.equals(receiverType); } return false; } @Override public String toString() { return "NoFinalizableSubclass[receiverType=" + receiverType.toJavaName() + "]"; } }
An assumption that a given abstract or interface type has one direct concrete subtype. There is no requirement that the subtype is a leaf type.
/** * An assumption that a given abstract or interface type has one direct concrete subtype. There * is no requirement that the subtype is a leaf type. */
public static final class ConcreteSubtype extends Assumption {
Type the assumption is made about.
/** * Type the assumption is made about. */
public final ResolvedJavaType context;
Assumed concrete sub-type of the context type.
/** * Assumed concrete sub-type of the context type. */
public final ResolvedJavaType subtype; public ConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) { this.context = context; this.subtype = subtype; assert context.isAbstract(); assert subtype.isConcrete() || context.isInterface() : subtype.toString() + " : " + context.toString(); assert !subtype.isArray() || subtype.getElementalType().isFinalFlagSet() : subtype.toString() + " : " + context.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + context.hashCode(); result = prime * result + subtype.hashCode(); return result; } @Override public boolean equals(Object obj) { if (obj instanceof ConcreteSubtype) { ConcreteSubtype other = (ConcreteSubtype) obj; return other.context.equals(context) && other.subtype.equals(subtype); } return false; } @Override public String toString() { return "ConcreteSubtype[context=" + context.toJavaName() + ", subtype=" + subtype.toJavaName() + "]"; } }
An assumption that a given type has no subtypes.
/** * An assumption that a given type has no subtypes. */
public static final class LeafType extends Assumption {
Type the assumption is made about.
/** * Type the assumption is made about. */
public final ResolvedJavaType context; public LeafType(ResolvedJavaType context) { assert !context.isLeaf() : "assumption isn't required for leaf types"; this.context = context; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + context.hashCode(); return result; } @Override public boolean equals(Object obj) { if (obj instanceof LeafType) { LeafType other = (LeafType) obj; return other.context.equals(context); } return false; } @Override public String toString() { return "LeafSubtype[context=" + context.toJavaName() + "]"; } }
An assumption that a given virtual method has a given unique implementation.
/** * An assumption that a given virtual method has a given unique implementation. */
public static final class ConcreteMethod extends Assumption {
A virtual (or interface) method whose unique implementation for the receiver type in context is impl.
/** * A virtual (or interface) method whose unique implementation for the receiver type in * {@link #context} is {@link #impl}. */
public final ResolvedJavaMethod method;
A receiver type.
/** * A receiver type. */
public final ResolvedJavaType context;
The unique implementation of method for context.
/** * The unique implementation of {@link #method} for {@link #context}. */
public final ResolvedJavaMethod impl; public ConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { this.method = method; this.context = context; this.impl = impl; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + method.hashCode(); result = prime * result + context.hashCode(); result = prime * result + impl.hashCode(); return result; } @Override public boolean equals(Object obj) { if (obj instanceof ConcreteMethod) { ConcreteMethod other = (ConcreteMethod) obj; return other.method.equals(method) && other.context.equals(context) && other.impl.equals(impl); } return false; } @Override public String toString() { return "ConcreteMethod[method=" + method.format("%H.%n(%p)%r") + ", context=" + context.toJavaName() + ", impl=" + impl.format("%H.%n(%p)%r") + "]"; } }
An assumption that a given call site's method handle did not change.
/** * An assumption that a given call site's method handle did not change. */
public static final class CallSiteTargetValue extends Assumption { public final JavaConstant callSite; public final JavaConstant methodHandle; public CallSiteTargetValue(JavaConstant callSite, JavaConstant methodHandle) { this.callSite = callSite; this.methodHandle = methodHandle; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + callSite.hashCode(); result = prime * result + methodHandle.hashCode(); return result; } @Override public boolean equals(Object obj) { if (obj instanceof CallSiteTargetValue) { CallSiteTargetValue other = (CallSiteTargetValue) obj; return callSite.equals(other.callSite) && methodHandle.equals(other.methodHandle); } return false; } @Override public String toString() { return "CallSiteTargetValue[callSite=" + callSite + ", methodHandle=" + methodHandle + "]"; } } private final Set<Assumption> assumptions = new HashSet<>();
Returns whether any assumptions have been registered.
Returns:true if at least one assumption has been registered, false otherwise.
/** * 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 assumptions.isEmpty(); } @Override public int hashCode() { throw new UnsupportedOperationException("hashCode"); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof Assumptions) { Assumptions that = (Assumptions) obj; if (!this.assumptions.equals(that.assumptions)) { return false; } return true; } return false; } @Override public Iterator<Assumption> iterator() { return assumptions.iterator(); }
Records an assumption that the specified type has no finalizable subclasses.
Params:
  • receiverType – the type that is assumed to have no finalizable subclasses
/** * 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) { record(new NoFinalizableSubclass(receiverType)); }
Records that subtype is the only concrete subtype in the class hierarchy below context.
Params:
  • context – the root of the subtree of the class hierarchy that this assumptions is about
  • subtype – the one concrete subtype
/** * 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(ResolvedJavaType context, ResolvedJavaType subtype) { record(new ConcreteSubtype(context, subtype)); }
Records that impl is the only possible concrete target for a virtual call to method with a receiver of type context.
Params:
  • method – a method that is the target of a virtual call
  • context – the receiver type of a call to method
  • impl – the concrete method that is the only possible target for the virtual call
/** * 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(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { record(new ConcreteMethod(method, context, impl)); } public void record(Assumption assumption) { assumptions.add(assumption); }
Gets a copy of the assumptions recorded in this object as an array.
/** * Gets a copy of the assumptions recorded in this object as an array. */
public Assumption[] toArray() { return assumptions.toArray(new Assumption[assumptions.size()]); }
Copies assumptions recorded by another Assumptions object into this object.
/** * Copies assumptions recorded by another {@link Assumptions} object into this object. */
public void record(Assumptions other) { assert other != this; assumptions.addAll(other.assumptions); } @Override public String toString() { return "Assumptions[" + assumptions + "]"; } }