001/* 002 * Copyright (c) 2011, 2012, 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.util.*; 026 027import jdk.internal.jvmci.meta.JavaTypeProfile.*; 028 029/** 030 * This profile object represents the type profile at a specific BCI. The precision of the supplied 031 * values may vary, but a runtime that provides this information should be aware that it will be 032 * used to guide performance-critical decisions like speculative inlining, etc. 033 */ 034public final class JavaTypeProfile extends AbstractJavaProfile<ProfiledType, ResolvedJavaType> { 035 036 private static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0]; 037 038 private final TriState nullSeen; 039 040 public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType[] pitems) { 041 super(notRecordedProbability, pitems); 042 this.nullSeen = nullSeen; 043 } 044 045 /** 046 * Returns whether a null value was at the type check. 047 */ 048 public TriState getNullSeen() { 049 return nullSeen; 050 } 051 052 /** 053 * A list of types for which the runtime has recorded probability information. Note that this 054 * includes both positive and negative types where a positive type is a subtype of the checked 055 * type and a negative type is not. 056 */ 057 public ProfiledType[] getTypes() { 058 return getItems(); 059 } 060 061 public JavaTypeProfile restrict(JavaTypeProfile otherProfile) { 062 if (otherProfile.getNotRecordedProbability() > 0.0) { 063 // Not useful for restricting since there is an unknown set of types occurring. 064 return this; 065 } 066 067 if (this.getNotRecordedProbability() > 0.0) { 068 // We are unrestricted, so the other profile is always a better estimate. 069 return otherProfile; 070 } 071 072 ArrayList<ProfiledType> result = new ArrayList<>(); 073 for (int i = 0; i < getItems().length; i++) { 074 ProfiledType ptype = getItems()[i]; 075 ResolvedJavaType type = ptype.getItem(); 076 if (otherProfile.isIncluded(type)) { 077 result.add(ptype); 078 } 079 } 080 081 TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : getNullSeen(); 082 double newNotRecorded = getNotRecordedProbability(); 083 return createAdjustedProfile(result, newNullSeen, newNotRecorded); 084 } 085 086 public JavaTypeProfile restrict(ResolvedJavaType declaredType, boolean nonNull) { 087 ArrayList<ProfiledType> result = new ArrayList<>(); 088 for (int i = 0; i < getItems().length; i++) { 089 ProfiledType ptype = getItems()[i]; 090 ResolvedJavaType type = ptype.getItem(); 091 if (declaredType.isAssignableFrom(type)) { 092 result.add(ptype); 093 } 094 } 095 096 TriState newNullSeen = (nonNull) ? TriState.FALSE : getNullSeen(); 097 double newNotRecorded = this.getNotRecordedProbability(); 098 // Assume for the types not recorded, the incompatibility rate is the same. 099 if (getItems().length != 0) { 100 newNotRecorded *= ((double) result.size() / (double) getItems().length); 101 } 102 return createAdjustedProfile(result, newNullSeen, newNotRecorded); 103 } 104 105 private JavaTypeProfile createAdjustedProfile(ArrayList<ProfiledType> result, TriState newNullSeen, double newNotRecorded) { 106 if (result.size() != this.getItems().length || newNotRecorded != getNotRecordedProbability() || newNullSeen != getNullSeen()) { 107 if (result.size() == 0) { 108 return new JavaTypeProfile(newNullSeen, 1.0, EMPTY_ARRAY); 109 } 110 double factor; 111 if (result.size() == this.getItems().length) { 112 /* List of types did not change, no need to recompute probabilities. */ 113 factor = 1.0; 114 } else { 115 double probabilitySum = 0.0; 116 for (int i = 0; i < result.size(); i++) { 117 probabilitySum += result.get(i).getProbability(); 118 } 119 probabilitySum += newNotRecorded; 120 121 factor = 1.0 / probabilitySum; // Normalize to 1.0 122 assert factor >= 1.0; 123 } 124 ProfiledType[] newResult = new ProfiledType[result.size()]; 125 for (int i = 0; i < newResult.length; ++i) { 126 ProfiledType curType = result.get(i); 127 newResult[i] = new ProfiledType(curType.getItem(), Math.min(1.0, curType.getProbability() * factor)); 128 } 129 double newNotRecordedTypeProbability = Math.min(1.0, newNotRecorded * factor); 130 return new JavaTypeProfile(newNullSeen, newNotRecordedTypeProbability, newResult); 131 } 132 return this; 133 } 134 135 @Override 136 public boolean equals(Object other) { 137 return super.equals(other) && nullSeen.equals(((JavaTypeProfile) other).nullSeen); 138 } 139 140 @Override 141 public int hashCode() { 142 return nullSeen.hashCode() + super.hashCode(); 143 } 144 145 public static class ProfiledType extends AbstractProfiledItem<ResolvedJavaType> { 146 147 public ProfiledType(ResolvedJavaType type, double probability) { 148 super(type, probability); 149 assert type.isArray() || type.isConcrete() : type; 150 } 151 152 /** 153 * Returns the type for this profile entry. 154 */ 155 public ResolvedJavaType getType() { 156 return getItem(); 157 } 158 159 @Override 160 public String toString() { 161 return String.format("%.6f#%s", probability, item); 162 } 163 } 164 165 @Override 166 public String toString() { 167 StringBuilder buf = new StringBuilder("JavaTypeProfile<nullSeen=").append(getNullSeen()).append(", types=["); 168 for (int j = 0; j < getTypes().length; j++) { 169 if (j != 0) { 170 buf.append(", "); 171 } 172 ProfiledType ptype = getTypes()[j]; 173 buf.append(String.format("%.6f:%s", ptype.getProbability(), ptype.getType())); 174 } 175 return buf.append(String.format("], notRecorded:%.6f>", getNotRecordedProbability())).toString(); 176 } 177 178 /** 179 * Returns {@code true} if all types seen at this location have been recorded in the profile. 180 */ 181 public boolean allTypesRecorded() { 182 return this.getNotRecordedProbability() == 0.0; 183 } 184 185 /** 186 * Returns the single monormorphic type representing this profile or {@code null} if no such 187 * type exists. 188 */ 189 public ResolvedJavaType asSingleType() { 190 if (allTypesRecorded() && this.getTypes().length == 1) { 191 return getTypes()[0].getType(); 192 } 193 return null; 194 } 195}