001/* 002 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package jdk.internal.jvmci.meta; 024 025import java.lang.invoke.*; 026import java.util.*; 027 028/** 029 * Class for recording assumptions made during compilation. 030 */ 031public final class Assumptions implements Iterable<Assumptions.Assumption> { 032 033 /** 034 * Abstract base class for assumptions. An assumption assumes a property of the runtime that may 035 * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing 036 * {@link NoFinalizableSubclass Object.finalize()}). 037 */ 038 public abstract static class Assumption { 039 } 040 041 /** 042 * A class for providing information that is only valid in association with a set of 043 * {@link Assumption}s. 044 * 045 * @param <T> 046 */ 047 public static class AssumptionResult<T> { 048 Assumption[] assumptions; 049 final T result; 050 051 private static final Assumption[] EMPTY = new Assumption[0]; 052 053 public AssumptionResult(T result, Assumption... assumptions) { 054 this.result = result; 055 this.assumptions = assumptions; 056 } 057 058 public AssumptionResult(T result) { 059 this(result, EMPTY); 060 } 061 062 public T getResult() { 063 return result; 064 } 065 066 public boolean isAssumptionFree() { 067 return assumptions.length == 0; 068 } 069 070 public void add(AssumptionResult<T> other) { 071 Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length); 072 System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length); 073 this.assumptions = newAssumptions; 074 } 075 } 076 077 /** 078 * An assumption that a given class has no subclasses implementing {@link Object#finalize()}). 079 */ 080 public static final class NoFinalizableSubclass extends Assumption { 081 082 private ResolvedJavaType receiverType; 083 084 public NoFinalizableSubclass(ResolvedJavaType receiverType) { 085 this.receiverType = receiverType; 086 } 087 088 @Override 089 public int hashCode() { 090 return 31 + receiverType.hashCode(); 091 } 092 093 @Override 094 public boolean equals(Object obj) { 095 if (obj instanceof NoFinalizableSubclass) { 096 NoFinalizableSubclass other = (NoFinalizableSubclass) obj; 097 return other.receiverType.equals(receiverType); 098 } 099 return false; 100 } 101 102 @Override 103 public String toString() { 104 return "NoFinalizableSubclass[receiverType=" + receiverType.toJavaName() + "]"; 105 } 106 107 } 108 109 /** 110 * An assumption that a given abstract or interface type has one direct concrete subtype. There 111 * is no requirement that the subtype is a leaf type. 112 */ 113 public static final class ConcreteSubtype extends Assumption { 114 115 /** 116 * Type the assumption is made about. 117 */ 118 public final ResolvedJavaType context; 119 120 /** 121 * Assumed concrete sub-type of the context type. 122 */ 123 public final ResolvedJavaType subtype; 124 125 public ConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) { 126 this.context = context; 127 this.subtype = subtype; 128 assert context.isAbstract(); 129 assert subtype.isConcrete() || context.isInterface() : subtype.toString() + " : " + context.toString(); 130 assert !subtype.isArray() || subtype.getElementalType().isFinalFlagSet() : subtype.toString() + " : " + context.toString(); 131 } 132 133 @Override 134 public int hashCode() { 135 final int prime = 31; 136 int result = 1; 137 result = prime * result + context.hashCode(); 138 result = prime * result + subtype.hashCode(); 139 return result; 140 } 141 142 @Override 143 public boolean equals(Object obj) { 144 if (obj instanceof ConcreteSubtype) { 145 ConcreteSubtype other = (ConcreteSubtype) obj; 146 return other.context.equals(context) && other.subtype.equals(subtype); 147 } 148 return false; 149 } 150 151 @Override 152 public String toString() { 153 return "ConcreteSubtype[context=" + context.toJavaName() + ", subtype=" + subtype.toJavaName() + "]"; 154 } 155 } 156 157 /** 158 * An assumption that a given type has no subtypes. 159 */ 160 public static final class LeafType extends Assumption { 161 162 /** 163 * Type the assumption is made about. 164 */ 165 public final ResolvedJavaType context; 166 167 public LeafType(ResolvedJavaType context) { 168 this.context = context; 169 } 170 171 @Override 172 public int hashCode() { 173 final int prime = 31; 174 int result = 1; 175 result = prime * result + context.hashCode(); 176 return result; 177 } 178 179 @Override 180 public boolean equals(Object obj) { 181 if (obj instanceof LeafType) { 182 LeafType other = (LeafType) obj; 183 return other.context.equals(context); 184 } 185 return false; 186 } 187 188 @Override 189 public String toString() { 190 return "LeafSubtype[context=" + context.toJavaName() + "]"; 191 } 192 } 193 194 /** 195 * An assumption that a given virtual method has a given unique implementation. 196 */ 197 public static final class ConcreteMethod extends Assumption { 198 199 /** 200 * A virtual (or interface) method whose unique implementation for the receiver type in 201 * {@link #context} is {@link #impl}. 202 */ 203 public final ResolvedJavaMethod method; 204 205 /** 206 * A receiver type. 207 */ 208 public final ResolvedJavaType context; 209 210 /** 211 * The unique implementation of {@link #method} for {@link #context}. 212 */ 213 public final ResolvedJavaMethod impl; 214 215 public ConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { 216 this.method = method; 217 this.context = context; 218 this.impl = impl; 219 } 220 221 @Override 222 public int hashCode() { 223 final int prime = 31; 224 int result = 1; 225 result = prime * result + method.hashCode(); 226 result = prime * result + context.hashCode(); 227 result = prime * result + impl.hashCode(); 228 return result; 229 } 230 231 @Override 232 public boolean equals(Object obj) { 233 if (obj instanceof ConcreteMethod) { 234 ConcreteMethod other = (ConcreteMethod) obj; 235 return other.method.equals(method) && other.context.equals(context) && other.impl.equals(impl); 236 } 237 return false; 238 } 239 240 @Override 241 public String toString() { 242 return "ConcreteMethod[method=" + method.format("%H.%n(%p)%r") + ", context=" + context.toJavaName() + ", impl=" + impl.format("%H.%n(%p)%r") + "]"; 243 } 244 } 245 246 /** 247 * An assumption that a given call site's method handle did not change. 248 */ 249 public static final class CallSiteTargetValue extends Assumption { 250 251 public final CallSite callSite; 252 public final MethodHandle methodHandle; 253 254 public CallSiteTargetValue(CallSite callSite, MethodHandle methodHandle) { 255 this.callSite = callSite; 256 this.methodHandle = methodHandle; 257 } 258 259 @Override 260 public int hashCode() { 261 final int prime = 31; 262 int result = 1; 263 result = prime * result + callSite.hashCode(); 264 result = prime * result + methodHandle.hashCode(); 265 return result; 266 } 267 268 @Override 269 public boolean equals(Object obj) { 270 if (obj instanceof CallSiteTargetValue) { 271 CallSiteTargetValue other = (CallSiteTargetValue) obj; 272 return callSite.equals(other.callSite) && methodHandle.equals(other.methodHandle); 273 } 274 return false; 275 } 276 277 @Override 278 public String toString() { 279 return "CallSiteTargetValue[callSite=" + callSite + ", methodHandle=" + methodHandle + "]"; 280 } 281 } 282 283 private final Set<Assumption> assumptions = new HashSet<>(); 284 285 /** 286 * Returns whether any assumptions have been registered. 287 * 288 * @return {@code true} if at least one assumption has been registered, {@code false} otherwise. 289 */ 290 public boolean isEmpty() { 291 return assumptions.isEmpty(); 292 } 293 294 @Override 295 public int hashCode() { 296 throw new UnsupportedOperationException("hashCode"); 297 } 298 299 @Override 300 public boolean equals(Object obj) { 301 if (this == obj) { 302 return true; 303 } 304 if (obj instanceof Assumptions) { 305 Assumptions that = (Assumptions) obj; 306 if (!this.assumptions.equals(that.assumptions)) { 307 return false; 308 } 309 return true; 310 } 311 return false; 312 } 313 314 @Override 315 public Iterator<Assumption> iterator() { 316 return assumptions.iterator(); 317 } 318 319 /** 320 * Records an assumption that the specified type has no finalizable subclasses. 321 * 322 * @param receiverType the type that is assumed to have no finalizable subclasses 323 */ 324 public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) { 325 record(new NoFinalizableSubclass(receiverType)); 326 } 327 328 /** 329 * Records that {@code subtype} is the only concrete subtype in the class hierarchy below 330 * {@code context}. 331 * 332 * @param context the root of the subtree of the class hierarchy that this assumptions is about 333 * @param subtype the one concrete subtype 334 */ 335 public void recordConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) { 336 record(new ConcreteSubtype(context, subtype)); 337 } 338 339 /** 340 * Records that {@code impl} is the only possible concrete target for a virtual call to 341 * {@code method} with a receiver of type {@code context}. 342 * 343 * @param method a method that is the target of a virtual call 344 * @param context the receiver type of a call to {@code method} 345 * @param impl the concrete method that is the only possible target for the virtual call 346 */ 347 public void recordConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { 348 record(new ConcreteMethod(method, context, impl)); 349 } 350 351 public void record(AssumptionResult<?> result) { 352 for (Assumption assumption : result.assumptions) { 353 record(assumption); 354 } 355 } 356 357 public void record(Assumption assumption) { 358 assumptions.add(assumption); 359 } 360 361 /** 362 * Gets a copy of the assumptions recorded in this object as an array. 363 */ 364 public Assumption[] toArray() { 365 return assumptions.toArray(new Assumption[assumptions.size()]); 366 } 367 368 /** 369 * Copies assumptions recorded by another {@link Assumptions} object into this object. 370 */ 371 public void record(Assumptions other) { 372 assert other != this; 373 assumptions.addAll(other.assumptions); 374 } 375 376 @Override 377 public String toString() { 378 return "Assumptions[" + assumptions + "]"; 379 } 380}