ContinuousArrayData.java revision 1040:cc3000241e57
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; 33import java.lang.invoke.MethodHandle; 34import java.lang.invoke.MethodHandles; 35import java.lang.invoke.MethodType; 36import java.lang.invoke.SwitchPoint; 37import jdk.internal.dynalink.CallSiteDescriptor; 38import jdk.internal.dynalink.linker.GuardedInvocation; 39import jdk.internal.dynalink.linker.LinkRequest; 40import jdk.nashorn.internal.lookup.Lookup; 41import jdk.nashorn.internal.runtime.ScriptObject; 42import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 43import jdk.nashorn.internal.runtime.logging.Logger; 44 45/** 46 * Interface implemented by all arrays that are directly accessible as underlying 47 * native arrays 48 */ 49@Logger(name="arrays") 50public abstract class ContinuousArrayData extends ArrayData { 51 52 private SwitchPoint sp; 53 54 /** 55 * Constructor 56 * @param length length (elementLength) 57 */ 58 protected ContinuousArrayData(final long length) { 59 super(length); 60 } 61 62 private SwitchPoint ensureSwitchPointExists() { 63 if (sp == null){ 64 sp = new SwitchPoint(); 65 } 66 return sp; 67 } 68 69 @Override 70 public void invalidateSetters() { 71 SwitchPoint.invalidateAll(new SwitchPoint[] { ensureSwitchPointExists() }); 72 } 73 74 /** 75 * Check if we can put one more element at the end of this continous 76 * array without reallocating, or if we are overwriting an already 77 * allocated element 78 * 79 * @param index index to check 80 * @return true if we don't need to do any array reallocation to fit an element at index 81 */ 82 public final boolean hasRoomFor(final int index) { 83 return has(index) || (index == length && ensure(index) == this); 84 } 85 86 /** 87 * Return element getter for a certain type at a certain program point 88 * @param returnType return type 89 * @param programPoint program point 90 * @return element getter or null if not supported (used to implement slow linkage instead 91 * as fast isn't possible) 92 */ 93 public abstract MethodHandle getElementGetter(final Class<?> returnType, final int programPoint); 94 95 /** 96 * Return element getter for a certain type at a certain program point 97 * @param elementType element type 98 * @return element setter or null if not supported (used to implement slow linkage instead 99 * as fast isn't possible) 100 */ 101 public abstract MethodHandle getElementSetter(final Class<?> elementType); 102 103 /** 104 * Version of has that throws a class cast exception if element does not exist 105 * used for relinking 106 * 107 * @param index index to check - currently only int indexes 108 * @return index 109 */ 110 protected int throwHas(final int index) { 111 if (!has(index)) { 112 throw new ClassCastException(); 113 } 114 return index; 115 } 116 117 /** 118 * Returns the type used to store an element in this array 119 * @return element type 120 */ 121 public abstract Class<?> getElementType(); 122 123 /** 124 * Look up a continuous array element getter 125 * @param get getter, sometimes combined with a has check that throws CCE on failure for relink 126 * @param returnType return type 127 * @param programPoint program point 128 * @return array getter 129 */ 130 protected final MethodHandle getContinuousElementGetter(final MethodHandle get, final Class<?> returnType, final int programPoint) { 131 return getContinuousElementGetter(getClass(), get, returnType, programPoint); 132 } 133 134 /** 135 * Look up a continuous array element setter 136 * @param set setter, sometimes combined with a has check that throws CCE on failure for relink 137 * @param returnType return type 138 * @return array setter 139 */ 140 protected final MethodHandle getContinuousElementSetter(final MethodHandle set, final Class<?> returnType) { 141 return getContinuousElementSetter(getClass(), set, returnType); 142 } 143 144 /** 145 * Return element getter for a {@link ContinuousArrayData} 146 * @param clazz clazz for exact type guard 147 * @param getHas has getter 148 * @param returnType return type 149 * @param programPoint program point 150 * @return method handle for element setter 151 */ 152 protected MethodHandle getContinuousElementGetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle getHas, final Class<?> returnType, final int programPoint) { 153 final boolean isOptimistic = isValid(programPoint); 154 final int fti = getAccessorTypeIndex(getHas.type().returnType()); 155 final int ti = getAccessorTypeIndex(returnType); 156 MethodHandle mh = getHas; 157 158 if (isOptimistic) { 159 if (ti < fti) { 160 mh = MH.insertArguments(ArrayData.THROW_UNWARRANTED.methodHandle(), 1, programPoint); 161 } 162 } 163 mh = MH.asType(mh, mh.type().changeReturnType(returnType).changeParameterType(0, clazz)); 164 165 if (!isOptimistic) { 166 //for example a & array[17]; 167 return Lookup.filterReturnType(mh, returnType); 168 } 169 return mh; 170 } 171 172 /** 173 * Return element setter for a {@link ContinuousArrayData} 174 * @param clazz clazz for exact type guard 175 * @param setHas set has guard 176 * @param elementType element type 177 * @return method handle for element setter 178 */ 179 protected MethodHandle getContinuousElementSetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle setHas, final Class<?> elementType) { 180 return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, clazz)); 181 } 182 183 /** Fast access guard - it is impractical for JIT performance reasons to use only CCE asType as guard :-(, also we need 184 the null case explicitly, which is the one that CCE doesn't handle */ 185 protected static final MethodHandle FAST_ACCESS_GUARD = 186 MH.dropArguments( 187 staticCall( 188 MethodHandles.lookup(), 189 ContinuousArrayData.class, 190 "guard", 191 boolean.class, 192 Class.class, 193 ScriptObject.class).methodHandle(), 194 2, 195 int.class); 196 197 @SuppressWarnings("unused") 198 private static final boolean guard(final Class<? extends ContinuousArrayData> clazz, final ScriptObject sobj) { 199 if (sobj != null && sobj.getArray().getClass() == clazz) { 200 return true; 201 } 202 return false; 203 } 204 205 /** 206 * Return a fast linked array getter, or null if we have to dispatch to super class 207 * @param desc descriptor 208 * @param request link request 209 * @return invocation or null if needs to be sent to slow relink 210 */ 211 @Override 212 public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { 213 final MethodType callType = desc.getMethodType(); 214 final Class<?> indexType = callType.parameterType(1); 215 final Class<?> returnType = callType.returnType(); 216 217 if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) { 218 final Object[] args = request.getArguments(); 219 final int index = (int)args[args.length - 1]; 220 221 if (has(index)) { 222 final MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle(); 223 final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT; 224 MethodHandle getElement = getElementGetter(returnType, programPoint); 225 if (getElement != null) { 226 getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(clazz))); 227 final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz); 228 return new GuardedInvocation(getElement, guard, (SwitchPoint)null, ClassCastException.class); 229 } 230 } 231 } 232 233 return null; 234 } 235 236 /** 237 * Return a fast linked array setter, or null if we have to dispatch to super class 238 * @param desc descriptor 239 * @param request link request 240 * @return invocation or null if needs to be sent to slow relink 241 */ 242 @Override 243 public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value 244 final MethodType callType = desc.getMethodType(); 245 final Class<?> indexType = callType.parameterType(1); 246 final Class<?> elementType = callType.parameterType(2); 247 248 if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) { 249 final Object[] args = request.getArguments(); 250 final int index = (int)args[args.length - 2]; 251 252 //sp may be invalidated by e.g. preventExtensions before the first setter is linked 253 //then it is already created. otherwise, create it here to guard against future 254 //invalidations 255 ensureSwitchPointExists(); 256 257 if (!sp.hasBeenInvalidated() && hasRoomFor(index)) { 258 MethodHandle setElement = getElementSetter(elementType); //Z(continuousarraydata, int, int), return true if successful 259 if (setElement != null) { 260 //else we are dealing with a wider type than supported by this callsite 261 MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle(); 262 getArray = MH.asType(getArray, getArray.type().changeReturnType(getClass())); 263 setElement = MH.filterArguments(setElement, 0, getArray); 264 final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz); 265 return new GuardedInvocation(setElement, guard, sp, ClassCastException.class); //CCE if not a scriptObject anymore 266 } 267 } 268 } 269 270 return null; 271 } 272 273 /** 274 * Specialization - fast push implementation 275 * @param arg argument 276 * @return new array length 277 */ 278 public long fastPush(final int arg) { 279 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 280 } 281 282 /** 283 * Specialization - fast push implementation 284 * @param arg argument 285 * @return new array length 286 */ 287 public long fastPush(final long arg) { 288 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 289 } 290 291 /** 292 * Specialization - fast push implementation 293 * @param arg argument 294 * @return new array length 295 */ 296 public long fastPush(final double arg) { 297 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 298 } 299 300 /** 301 * Specialization - fast push implementation 302 * @param arg argument 303 * @return new array length 304 */ 305 public long fastPush(final Object arg) { 306 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 307 } 308 309 /** 310 * Specialization - fast pop implementation 311 * @return element value 312 */ 313 public int fastPopInt() { 314 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 315 } 316 317 /** 318 * Specialization - fast pop implementation 319 * @return element value 320 */ 321 public long fastPopLong() { 322 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 323 } 324 325 /** 326 * Specialization - fast pop implementation 327 * @return element value 328 */ 329 public double fastPopDouble() { 330 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 331 } 332 333 /** 334 * Specialization - fast pop implementation 335 * @return element value 336 */ 337 public Object fastPopObject() { 338 throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink 339 } 340} 341