ContinuousArrayData.java revision 1101:be3f5ca1edbf
191094Sdes/* 2115619Sdes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3228690Sdes * 491094Sdes * This code is free software; you can redistribute it and/or modify it 591094Sdes * under the terms of the GNU General Public License version 2 only, as 691094Sdes * published by the Free Software Foundation. Oracle designates this 799158Sdes * particular file as subject to the "Classpath" exception as provided 899158Sdes * by Oracle in the LICENSE file that accompanied this code. 999158Sdes * 1091094Sdes * This code is distributed in the hope that it will be useful, but WITHOUT 1191094Sdes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1291094Sdes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1391094Sdes * version 2 for more details (a copy is included in the LICENSE file that 1491094Sdes * accompanied this code). 1591094Sdes * 1691094Sdes * You should have received a copy of the GNU General Public License version 1791094Sdes * 2 along with this work; if not, write to the Free Software Foundation, 1891094Sdes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1991094Sdes * 2091094Sdes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2191094Sdes * or visit www.oracle.com if you need additional information or have any 2291094Sdes * questions. 2391094Sdes */ 2491094Sdes 2591094Sdespackage jdk.nashorn.internal.runtime.arrays; 2691094Sdes 2791094Sdesimport static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; 2891094Sdesimport static jdk.nashorn.internal.lookup.Lookup.MH; 2991094Sdesimport static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex; 3091094Sdesimport static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; 3191094Sdesimport static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; 3291094Sdesimport java.lang.invoke.MethodHandle; 3391094Sdesimport java.lang.invoke.MethodHandles; 3491094Sdesimport java.lang.invoke.MethodType; 35228690Sdesimport java.lang.invoke.SwitchPoint; 3691094Sdesimport jdk.internal.dynalink.CallSiteDescriptor; 3791094Sdesimport jdk.internal.dynalink.linker.GuardedInvocation; 38228690Sdesimport jdk.internal.dynalink.linker.LinkRequest; 39228690Sdesimport jdk.nashorn.internal.codegen.types.Type; 40228690Sdesimport jdk.nashorn.internal.lookup.Lookup; 41228690Sdesimport jdk.nashorn.internal.runtime.ScriptObject; 4291094Sdesimport jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 4391094Sdesimport jdk.nashorn.internal.runtime.logging.Logger; 4491094Sdes 4591094Sdes/** 4691094Sdes * Interface implemented by all arrays that are directly accessible as underlying 4791094Sdes * native arrays 48115619Sdes */ 49115619Sdes@Logger(name="arrays") 5091094Sdespublic abstract class ContinuousArrayData extends ArrayData { 5191094Sdes /** 5291094Sdes * Constructor 5391094Sdes * @param length length (elementLength) 5491094Sdes */ 5591094Sdes protected ContinuousArrayData(final long length) { 5691094Sdes super(length); 57174832Sdes } 5891094Sdes 5999158Sdes /** 6091094Sdes * Check if we can put one more element at the end of this continous 6191094Sdes * array without reallocating, or if we are overwriting an already 6291094Sdes * allocated element 6391094Sdes * 6491094Sdes * @param index index to check 65115619Sdes * @return true if we don't need to do any array reallocation to fit an element at index 6691094Sdes */ 6791094Sdes public final boolean hasRoomFor(final int index) { 6891100Sdes return has(index) || (index == length() && ensure(index) == this); 6991100Sdes } 7091100Sdes 7191100Sdes /** 7291100Sdes * Check if an arraydata is empty 7391100Sdes * @return true if empty 7491100Sdes */ 7591100Sdes public boolean isEmpty() { 7691100Sdes return length() == 0L; 7791100Sdes } 7891100Sdes 7991100Sdes /** 8091684Sdes * Return element getter for a certain type at a certain program point 8191100Sdes * @param returnType return type 8291100Sdes * @param programPoint program point 8391100Sdes * @return element getter or null if not supported (used to implement slow linkage instead 8491100Sdes * as fast isn't possible) 85 */ 86 public abstract MethodHandle getElementGetter(final Class<?> returnType, final int programPoint); 87 88 /** 89 * Return element getter for a certain type at a certain program point 90 * @param elementType element type 91 * @return element setter or null if not supported (used to implement slow linkage instead 92 * as fast isn't possible) 93 */ 94 public abstract MethodHandle getElementSetter(final Class<?> elementType); 95 96 /** 97 * Version of has that throws a class cast exception if element does not exist 98 * used for relinking 99 * 100 * @param index index to check - currently only int indexes 101 * @return index 102 */ 103 protected final int throwHas(final int index) { 104 if (!has(index)) { 105 throw new ClassCastException(); 106 } 107 return index; 108 } 109 110 @Override 111 public abstract ContinuousArrayData copy(); 112 113 /** 114 * Returns the type used to store an element in this array 115 * @return element type 116 */ 117 public abstract Class<?> getElementType(); 118 119 @Override 120 public Type getOptimisticType() { 121 return Type.typeFor(getElementType()); 122 } 123 124 /** 125 * Returns the boxed type of the type used to store an element in this array 126 * @return element type 127 */ 128 public abstract Class<?> getBoxedElementType(); 129 130 /** 131 * Get the widest element type of two arrays. This can be done faster in subclasses, but 132 * this works for all ContinuousArrayDatas and for where more optimal checks haven't been 133 * implemented. 134 * 135 * @param otherData another ContinuousArrayData 136 * @return the widest boxed element type 137 */ 138 public ContinuousArrayData widest(final ContinuousArrayData otherData) { 139 final Class<?> elementType = getElementType(); 140 return Type.widest(elementType, otherData.getElementType()) == elementType ? this : otherData; 141 } 142 143 /** 144 * Look up a continuous array element getter 145 * @param get getter, sometimes combined with a has check that throws CCE on failure for relink 146 * @param returnType return type 147 * @param programPoint program point 148 * @return array getter 149 */ 150 protected final MethodHandle getContinuousElementGetter(final MethodHandle get, final Class<?> returnType, final int programPoint) { 151 return getContinuousElementGetter(getClass(), get, returnType, programPoint); 152 } 153 154 /** 155 * Look up a continuous array element setter 156 * @param set setter, sometimes combined with a has check that throws CCE on failure for relink 157 * @param returnType return type 158 * @return array setter 159 */ 160 protected final MethodHandle getContinuousElementSetter(final MethodHandle set, final Class<?> returnType) { 161 return getContinuousElementSetter(getClass(), set, returnType); 162 } 163 164 /** 165 * Return element getter for a {@link ContinuousArrayData} 166 * @param clazz clazz for exact type guard 167 * @param getHas has getter 168 * @param returnType return type 169 * @param programPoint program point 170 * @return method handle for element setter 171 */ 172 protected MethodHandle getContinuousElementGetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle getHas, final Class<?> returnType, final int programPoint) { 173 final boolean isOptimistic = isValid(programPoint); 174 final int fti = getAccessorTypeIndex(getHas.type().returnType()); 175 final int ti = getAccessorTypeIndex(returnType); 176 MethodHandle mh = getHas; 177 178 if (isOptimistic) { 179 if (ti < fti) { 180 mh = MH.insertArguments(ArrayData.THROW_UNWARRANTED.methodHandle(), 1, programPoint); 181 } 182 } 183 mh = MH.asType(mh, mh.type().changeReturnType(returnType).changeParameterType(0, clazz)); 184 185 if (!isOptimistic) { 186 //for example a & array[17]; 187 return Lookup.filterReturnType(mh, returnType); 188 } 189 return mh; 190 } 191 192 /** 193 * Return element setter for a {@link ContinuousArrayData} 194 * @param clazz clazz for exact type guard 195 * @param setHas set has guard 196 * @param elementType element type 197 * @return method handle for element setter 198 */ 199 protected MethodHandle getContinuousElementSetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle setHas, final Class<?> elementType) { 200 return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, clazz)); 201 } 202 203 /** Fast access guard - it is impractical for JIT performance reasons to use only CCE asType as guard :-(, also we need 204 the null case explicitly, which is the one that CCE doesn't handle */ 205 protected static final MethodHandle FAST_ACCESS_GUARD = 206 MH.dropArguments( 207 staticCall( 208 MethodHandles.lookup(), 209 ContinuousArrayData.class, 210 "guard", 211 boolean.class, 212 Class.class, 213 ScriptObject.class).methodHandle(), 214 2, 215 int.class); 216 217 @SuppressWarnings("unused") 218 private static final boolean guard(final Class<? extends ContinuousArrayData> clazz, final ScriptObject sobj) { 219 if (sobj != null && sobj.getArray().getClass() == clazz) { 220 return true; 221 } 222 return false; 223 } 224 225 /** 226 * Return a fast linked array getter, or null if we have to dispatch to super class 227 * @param desc descriptor 228 * @param request link request 229 * @return invocation or null if needs to be sent to slow relink 230 */ 231 @Override 232 public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { 233 final MethodType callType = desc.getMethodType(); 234 final Class<?> indexType = callType.parameterType(1); 235 final Class<?> returnType = callType.returnType(); 236 237 if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) { 238 final Object[] args = request.getArguments(); 239 final int index = (int)args[args.length - 1]; 240 241 if (has(index)) { 242 final MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle(); 243 final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT; 244 MethodHandle getElement = getElementGetter(returnType, programPoint); 245 if (getElement != null) { 246 getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(clazz))); 247 final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz); 248 return new GuardedInvocation(getElement, guard, (SwitchPoint)null, ClassCastException.class); 249 } 250 } 251 } 252 253 return null; 254 } 255 256 /** 257 * Return a fast linked array setter, or null if we have to dispatch to super class 258 * @param desc descriptor 259 * @param request link request 260 * @return invocation or null if needs to be sent to slow relink 261 */ 262 @Override 263 public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value 264 final MethodType callType = desc.getMethodType(); 265 final Class<?> indexType = callType.parameterType(1); 266 final Class<?> elementType = callType.parameterType(2); 267 268 if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) { 269 final Object[] args = request.getArguments(); 270 final int index = (int)args[args.length - 2]; 271 272 if (hasRoomFor(index)) { 273 MethodHandle setElement = getElementSetter(elementType); //Z(continuousarraydata, int, int), return true if successful 274 if (setElement != null) { 275 //else we are dealing with a wider type than supported by this callsite 276 MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle(); 277 getArray = MH.asType(getArray, getArray.type().changeReturnType(getClass())); 278 setElement = MH.filterArguments(setElement, 0, getArray); 279 final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz); 280 return new GuardedInvocation(setElement, guard, (SwitchPoint)null, ClassCastException.class); //CCE if not a scriptObject anymore 281 } 282 } 283 } 284 285 return null; 286 } 287 288 /** 289 * Specialization - fast push implementation 290 * @param arg argument 291 * @return new array length 292 */ 293 public long fastPush(final int arg) { 294 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 295 } 296 297 /** 298 * Specialization - fast push implementation 299 * @param arg argument 300 * @return new array length 301 */ 302 public long fastPush(final long arg) { 303 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 304 } 305 306 /** 307 * Specialization - fast push implementation 308 * @param arg argument 309 * @return new array length 310 */ 311 public long fastPush(final double arg) { 312 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 313 } 314 315 /** 316 * Specialization - fast push implementation 317 * @param arg argument 318 * @return new array length 319 */ 320 public long fastPush(final Object arg) { 321 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 322 } 323 324 /** 325 * Specialization - fast pop implementation 326 * @return element value 327 */ 328 public int fastPopInt() { 329 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 330 } 331 332 /** 333 * Specialization - fast pop implementation 334 * @return element value 335 */ 336 public long fastPopLong() { 337 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 338 } 339 340 /** 341 * Specialization - fast pop implementation 342 * @return element value 343 */ 344 public double fastPopDouble() { 345 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 346 } 347 348 /** 349 * Specialization - fast pop implementation 350 * @return element value 351 */ 352 public Object fastPopObject() { 353 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 354 } 355 356 /** 357 * Specialization - fast concat implementation 358 * @param otherData data to concat 359 * @return new arraydata 360 */ 361 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 362 throw new ClassCastException(String.valueOf(getClass()) + " != " + String.valueOf(otherData.getClass())); 363 } 364} 365