ContinuousArrayData.java revision 1062:f9ed1ca59030
1/* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.runtime.arrays; 27 28import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; 29import static jdk.nashorn.internal.lookup.Lookup.MH; 30import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex; 31import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; 32import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; 33 34import java.lang.invoke.MethodHandle; 35import java.lang.invoke.MethodHandles; 36import java.lang.invoke.MethodType; 37import java.lang.invoke.SwitchPoint; 38import jdk.internal.dynalink.CallSiteDescriptor; 39import jdk.internal.dynalink.linker.GuardedInvocation; 40import jdk.internal.dynalink.linker.LinkRequest; 41import jdk.nashorn.internal.codegen.types.Type; 42import jdk.nashorn.internal.lookup.Lookup; 43import jdk.nashorn.internal.runtime.ScriptObject; 44import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 45import jdk.nashorn.internal.runtime.logging.Logger; 46 47/** 48 * Interface implemented by all arrays that are directly accessible as underlying 49 * native arrays 50 */ 51@Logger(name="arrays") 52public abstract class ContinuousArrayData extends ArrayData { 53 54 private SwitchPoint sp; 55 56 /** 57 * Constructor 58 * @param length length (elementLength) 59 */ 60 protected ContinuousArrayData(final long length) { 61 super(length); 62 } 63 64 private SwitchPoint ensureSwitchPointExists() { 65 if (sp == null){ 66 sp = new SwitchPoint(); 67 } 68 return sp; 69 } 70 71 @Override 72 public void invalidateSetters() { 73 SwitchPoint.invalidateAll(new SwitchPoint[] { ensureSwitchPointExists() }); 74 } 75 76 /** 77 * Check if we can put one more element at the end of this continous 78 * array without reallocating, or if we are overwriting an already 79 * allocated element 80 * 81 * @param index index to check 82 * @return true if we don't need to do any array reallocation to fit an element at index 83 */ 84 public final boolean hasRoomFor(final int index) { 85 return has(index) || (index == length && ensure(index) == this); 86 } 87 88 /** 89 * Return element getter for a certain type at a certain program point 90 * @param returnType return type 91 * @param programPoint program point 92 * @return element getter or null if not supported (used to implement slow linkage instead 93 * as fast isn't possible) 94 */ 95 public abstract MethodHandle getElementGetter(final Class<?> returnType, final int programPoint); 96 97 /** 98 * Return element getter for a certain type at a certain program point 99 * @param elementType element type 100 * @return element setter or null if not supported (used to implement slow linkage instead 101 * as fast isn't possible) 102 */ 103 public abstract MethodHandle getElementSetter(final Class<?> elementType); 104 105 /** 106 * Version of has that throws a class cast exception if element does not exist 107 * used for relinking 108 * 109 * @param index index to check - currently only int indexes 110 * @return index 111 */ 112 protected int throwHas(final int index) { 113 if (!has(index)) { 114 throw new ClassCastException(); 115 } 116 return index; 117 } 118 119 /** 120 * Returns the type used to store an element in this array 121 * @return element type 122 */ 123 public abstract Class<?> getElementType(); 124 125 @Override 126 public Type getOptimisticType() { 127 return Type.typeFor(getElementType()); 128 } 129 130 /** 131 * Look up a continuous array element getter 132 * @param get getter, sometimes combined with a has check that throws CCE on failure for relink 133 * @param returnType return type 134 * @param programPoint program point 135 * @return array getter 136 */ 137 protected final MethodHandle getContinuousElementGetter(final MethodHandle get, final Class<?> returnType, final int programPoint) { 138 return getContinuousElementGetter(getClass(), get, returnType, programPoint); 139 } 140 141 /** 142 * Look up a continuous array element setter 143 * @param set setter, sometimes combined with a has check that throws CCE on failure for relink 144 * @param returnType return type 145 * @return array setter 146 */ 147 protected final MethodHandle getContinuousElementSetter(final MethodHandle set, final Class<?> returnType) { 148 return getContinuousElementSetter(getClass(), set, returnType); 149 } 150 151 /** 152 * Return element getter for a {@link ContinuousArrayData} 153 * @param clazz clazz for exact type guard 154 * @param getHas has getter 155 * @param returnType return type 156 * @param programPoint program point 157 * @return method handle for element setter 158 */ 159 protected MethodHandle getContinuousElementGetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle getHas, final Class<?> returnType, final int programPoint) { 160 final boolean isOptimistic = isValid(programPoint); 161 final int fti = getAccessorTypeIndex(getHas.type().returnType()); 162 final int ti = getAccessorTypeIndex(returnType); 163 MethodHandle mh = getHas; 164 165 if (isOptimistic) { 166 if (ti < fti) { 167 mh = MH.insertArguments(ArrayData.THROW_UNWARRANTED.methodHandle(), 1, programPoint); 168 } 169 } 170 mh = MH.asType(mh, mh.type().changeReturnType(returnType).changeParameterType(0, clazz)); 171 172 if (!isOptimistic) { 173 //for example a & array[17]; 174 return Lookup.filterReturnType(mh, returnType); 175 } 176 return mh; 177 } 178 179 /** 180 * Return element setter for a {@link ContinuousArrayData} 181 * @param clazz clazz for exact type guard 182 * @param setHas set has guard 183 * @param elementType element type 184 * @return method handle for element setter 185 */ 186 protected MethodHandle getContinuousElementSetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle setHas, final Class<?> elementType) { 187 return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, clazz)); 188 } 189 190 /** Fast access guard - it is impractical for JIT performance reasons to use only CCE asType as guard :-(, also we need 191 the null case explicitly, which is the one that CCE doesn't handle */ 192 protected static final MethodHandle FAST_ACCESS_GUARD = 193 MH.dropArguments( 194 staticCall( 195 MethodHandles.lookup(), 196 ContinuousArrayData.class, 197 "guard", 198 boolean.class, 199 Class.class, 200 ScriptObject.class).methodHandle(), 201 2, 202 int.class); 203 204 @SuppressWarnings("unused") 205 private static final boolean guard(final Class<? extends ContinuousArrayData> clazz, final ScriptObject sobj) { 206 if (sobj != null && sobj.getArray().getClass() == clazz) { 207 return true; 208 } 209 return false; 210 } 211 212 /** 213 * Return a fast linked array getter, or null if we have to dispatch to super class 214 * @param desc descriptor 215 * @param request link request 216 * @return invocation or null if needs to be sent to slow relink 217 */ 218 @Override 219 public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { 220 final MethodType callType = desc.getMethodType(); 221 final Class<?> indexType = callType.parameterType(1); 222 final Class<?> returnType = callType.returnType(); 223 224 if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) { 225 final Object[] args = request.getArguments(); 226 final int index = (int)args[args.length - 1]; 227 228 if (has(index)) { 229 final MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle(); 230 final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT; 231 MethodHandle getElement = getElementGetter(returnType, programPoint); 232 if (getElement != null) { 233 getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(clazz))); 234 final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz); 235 return new GuardedInvocation(getElement, guard, (SwitchPoint)null, ClassCastException.class); 236 } 237 } 238 } 239 240 return null; 241 } 242 243 /** 244 * Return a fast linked array setter, or null if we have to dispatch to super class 245 * @param desc descriptor 246 * @param request link request 247 * @return invocation or null if needs to be sent to slow relink 248 */ 249 @Override 250 public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value 251 final MethodType callType = desc.getMethodType(); 252 final Class<?> indexType = callType.parameterType(1); 253 final Class<?> elementType = callType.parameterType(2); 254 255 if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) { 256 final Object[] args = request.getArguments(); 257 final int index = (int)args[args.length - 2]; 258 259 //sp may be invalidated by e.g. preventExtensions before the first setter is linked 260 //then it is already created. otherwise, create it here to guard against future 261 //invalidations 262 ensureSwitchPointExists(); 263 264 if (!sp.hasBeenInvalidated() && hasRoomFor(index)) { 265 MethodHandle setElement = getElementSetter(elementType); //Z(continuousarraydata, int, int), return true if successful 266 if (setElement != null) { 267 //else we are dealing with a wider type than supported by this callsite 268 MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle(); 269 getArray = MH.asType(getArray, getArray.type().changeReturnType(getClass())); 270 setElement = MH.filterArguments(setElement, 0, getArray); 271 final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz); 272 return new GuardedInvocation(setElement, guard, sp, ClassCastException.class); //CCE if not a scriptObject anymore 273 } 274 } 275 } 276 277 return null; 278 } 279 280 /** 281 * Specialization - fast push implementation 282 * @param arg argument 283 * @return new array length 284 */ 285 public long fastPush(final int arg) { 286 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 287 } 288 289 /** 290 * Specialization - fast push implementation 291 * @param arg argument 292 * @return new array length 293 */ 294 public long fastPush(final long arg) { 295 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 296 } 297 298 /** 299 * Specialization - fast push implementation 300 * @param arg argument 301 * @return new array length 302 */ 303 public long fastPush(final double arg) { 304 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 305 } 306 307 /** 308 * Specialization - fast push implementation 309 * @param arg argument 310 * @return new array length 311 */ 312 public long fastPush(final Object arg) { 313 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 314 } 315 316 /** 317 * Specialization - fast pop implementation 318 * @return element value 319 */ 320 public int fastPopInt() { 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 long fastPopLong() { 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 double fastPopDouble() { 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 Object fastPopObject() { 345 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 346 } 347} 348