1 /* 2 * Copyright (c) 2010, 2014, 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 26 package jdk.nashorn.internal.runtime; 27 28 import static jdk.nashorn.internal.lookup.Lookup.MH; 29 30 import java.lang.invoke.MethodHandle; 31 import java.lang.invoke.MethodHandles; 32 33 /** 34 * Spill property 35 */ 36 public class SpillProperty extends AccessorProperty { 37 private static final long serialVersionUID = 3028496245198669460L; 38 39 private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 40 41 private static final MethodHandle PARRAY_GETTER = MH.asType(MH.getter(LOOKUP, ScriptObject.class, "primitiveSpill", long[].class), MH.type(long[].class, Object.class)); 42 private static final MethodHandle OARRAY_GETTER = MH.asType(MH.getter(LOOKUP, ScriptObject.class, "objectSpill", Object[].class), MH.type(Object[].class, Object.class)); 43 44 private static final MethodHandle OBJECT_GETTER = MH.filterArguments(MH.arrayElementGetter(Object[].class), 0, OARRAY_GETTER); 45 private static final MethodHandle PRIMITIVE_GETTER = MH.filterArguments(MH.arrayElementGetter(long[].class), 0, PARRAY_GETTER); 46 private static final MethodHandle OBJECT_SETTER = MH.filterArguments(MH.arrayElementSetter(Object[].class), 0, OARRAY_GETTER); 47 private static final MethodHandle PRIMITIVE_SETTER = MH.filterArguments(MH.arrayElementSetter(long[].class), 0, PARRAY_GETTER); 48 49 private static class Accessors { 50 private MethodHandle objectGetter; 51 private MethodHandle objectSetter; 52 private MethodHandle primitiveGetter; 53 private MethodHandle primitiveSetter; 54 55 private final int slot; 56 private final MethodHandle ensureSpillSize; 57 58 private static Accessors ACCESSOR_CACHE[] = new Accessors[512]; 59 60 //private static final Map<Integer, Reference<Accessors>> ACCESSOR_CACHE = Collections.synchronizedMap(new WeakHashMap<Integer, Reference<Accessors>>()); 61 Accessors(final int slot)62 Accessors(final int slot) { 63 assert slot >= 0; 64 this.slot = slot; 65 this.ensureSpillSize = MH.asType(MH.insertArguments(ScriptObject.ENSURE_SPILL_SIZE, 1, slot), MH.type(Object.class, Object.class)); 66 } 67 ensure(final int slot)68 private static void ensure(final int slot) { 69 int len = ACCESSOR_CACHE.length; 70 if (slot >= len) { 71 do { 72 len *= 2; 73 } while (slot >= len); 74 final Accessors newCache[] = new Accessors[len]; 75 System.arraycopy(ACCESSOR_CACHE, 0, newCache, 0, ACCESSOR_CACHE.length); 76 ACCESSOR_CACHE = newCache; 77 } 78 } 79 getCached(final int slot, final boolean isPrimitive, final boolean isGetter)80 static MethodHandle getCached(final int slot, final boolean isPrimitive, final boolean isGetter) { 81 //Reference<Accessors> ref = ACCESSOR_CACHE.get(slot); 82 ensure(slot); 83 Accessors acc = ACCESSOR_CACHE[slot]; 84 if (acc == null) { 85 acc = new Accessors(slot); 86 ACCESSOR_CACHE[slot] = acc; 87 } 88 89 return acc.getOrCreate(isPrimitive, isGetter); 90 } 91 primordial(final boolean isPrimitive, final boolean isGetter)92 private static MethodHandle primordial(final boolean isPrimitive, final boolean isGetter) { 93 if (isPrimitive) { 94 return isGetter ? PRIMITIVE_GETTER : PRIMITIVE_SETTER; 95 } 96 return isGetter ? OBJECT_GETTER : OBJECT_SETTER; 97 } 98 getOrCreate(final boolean isPrimitive, final boolean isGetter)99 MethodHandle getOrCreate(final boolean isPrimitive, final boolean isGetter) { 100 MethodHandle accessor; 101 102 accessor = getInner(isPrimitive, isGetter); 103 if (accessor != null) { 104 return accessor; 105 } 106 107 accessor = primordial(isPrimitive, isGetter); 108 accessor = MH.insertArguments(accessor, 1, slot); 109 if (!isGetter) { 110 accessor = MH.filterArguments(accessor, 0, ensureSpillSize); 111 } 112 setInner(isPrimitive, isGetter, accessor); 113 114 return accessor; 115 } 116 setInner(final boolean isPrimitive, final boolean isGetter, final MethodHandle mh)117 void setInner(final boolean isPrimitive, final boolean isGetter, final MethodHandle mh) { 118 if (isPrimitive) { 119 if (isGetter) { 120 primitiveGetter = mh; 121 } else { 122 primitiveSetter = mh; 123 } 124 } else { 125 if (isGetter) { 126 objectGetter = mh; 127 } else { 128 objectSetter = mh; 129 } 130 } 131 } 132 getInner(final boolean isPrimitive, final boolean isGetter)133 MethodHandle getInner(final boolean isPrimitive, final boolean isGetter) { 134 if (isPrimitive) { 135 return isGetter ? primitiveGetter : primitiveSetter; 136 } 137 return isGetter ? objectGetter : objectSetter; 138 } 139 } 140 primitiveGetter(final int slot, final int flags)141 private static MethodHandle primitiveGetter(final int slot, final int flags) { 142 return (flags & DUAL_FIELDS) == DUAL_FIELDS ? Accessors.getCached(slot, true, true) : null; 143 } primitiveSetter(final int slot, final int flags)144 private static MethodHandle primitiveSetter(final int slot, final int flags) { 145 return (flags & DUAL_FIELDS) == DUAL_FIELDS ? Accessors.getCached(slot, true, false) : null; 146 } objectGetter(final int slot)147 private static MethodHandle objectGetter(final int slot) { 148 return Accessors.getCached(slot, false, true); 149 } objectSetter(final int slot)150 private static MethodHandle objectSetter(final int slot) { 151 return Accessors.getCached(slot, false, false); 152 } 153 154 /** 155 * Constructor for spill properties. Array getters and setters will be created on demand. 156 * 157 * @param key the property key 158 * @param flags the property flags 159 * @param slot spill slot 160 */ SpillProperty(final Object key, final int flags, final int slot)161 public SpillProperty(final Object key, final int flags, final int slot) { 162 super(key, flags, slot, primitiveGetter(slot, flags), primitiveSetter(slot, flags), objectGetter(slot), objectSetter(slot)); 163 } 164 165 /** 166 * Constructor for spill properties with an initial type. 167 * @param key the property key 168 * @param flags the property flags 169 * @param slot spill slot 170 * @param initialType initial type 171 */ SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType)172 public SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) { 173 this(key, flags, slot); 174 setType(hasDualFields() ? initialType : Object.class); 175 } 176 SpillProperty(final Object key, final int flags, final int slot, final ScriptObject owner, final Object initialValue)177 SpillProperty(final Object key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) { 178 this(key, flags, slot); 179 setInitialValue(owner, initialValue); 180 } 181 182 /** 183 * Copy constructor 184 * @param property other property 185 */ SpillProperty(final SpillProperty property)186 protected SpillProperty(final SpillProperty property) { 187 super(property); 188 } 189 190 /** 191 * Copy constructor 192 * @param newType new type 193 * @param property other property 194 */ SpillProperty(final SpillProperty property, final Class<?> newType)195 protected SpillProperty(final SpillProperty property, final Class<?> newType) { 196 super(property, newType); 197 } 198 199 @Override copy()200 public Property copy() { 201 return new SpillProperty(this); 202 } 203 204 @Override copy(final Class<?> newType)205 public Property copy(final Class<?> newType) { 206 return new SpillProperty(this, newType); 207 } 208 209 @Override isSpill()210 public boolean isSpill() { 211 return true; 212 } 213 214 @Override initMethodHandles(final Class<?> structure)215 void initMethodHandles(final Class<?> structure) { 216 final int slot = getSlot(); 217 primitiveGetter = primitiveGetter(slot, getFlags()); 218 primitiveSetter = primitiveSetter(slot, getFlags()); 219 objectGetter = objectGetter(slot); 220 objectSetter = objectSetter(slot); 221 } 222 } 223