Wed, 05 Nov 2014 12:34:06 +0100
8057825: Bug in apply specialization - if an apply specialization that is available doesn't fit, a new one wouldn't be installed, if the new code generated as a specialization didn't manage to do the apply specialization. Basically changing a conditional to an unconditional.
Reviewed-by: attila, hannesw
attila@963 | 1 | /* |
attila@963 | 2 | * Copyright (c) 2010-2014, Oracle and/or its affiliates. All rights reserved. |
attila@963 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
attila@963 | 4 | * |
attila@963 | 5 | * This code is free software; you can redistribute it and/or modify it |
attila@963 | 6 | * under the terms of the GNU General Public License version 2 only, as |
attila@963 | 7 | * published by the Free Software Foundation. Oracle designates this |
attila@963 | 8 | * particular file as subject to the "Classpath" exception as provided |
attila@963 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
attila@963 | 10 | * |
attila@963 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
attila@963 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
attila@963 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
attila@963 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
attila@963 | 15 | * accompanied this code). |
attila@963 | 16 | * |
attila@963 | 17 | * You should have received a copy of the GNU General Public License version |
attila@963 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
attila@963 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
attila@963 | 20 | * |
attila@963 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
attila@963 | 22 | * or visit www.oracle.com if you need additional information or have any |
attila@963 | 23 | * questions. |
attila@963 | 24 | */ |
attila@963 | 25 | |
attila@963 | 26 | package jdk.nashorn.internal.runtime; |
attila@963 | 27 | |
attila@963 | 28 | import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY; |
attila@963 | 29 | import static jdk.nashorn.internal.lookup.Lookup.MH; |
attila@963 | 30 | |
attila@963 | 31 | import java.lang.invoke.MethodHandle; |
attila@963 | 32 | import java.lang.invoke.MethodHandles; |
attila@963 | 33 | |
attila@963 | 34 | /** |
attila@963 | 35 | * Spill property |
attila@963 | 36 | */ |
attila@963 | 37 | public class SpillProperty extends AccessorProperty { |
attila@963 | 38 | private static final long serialVersionUID = 3028496245198669460L; |
attila@963 | 39 | |
attila@963 | 40 | private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); |
attila@963 | 41 | |
attila@963 | 42 | private static final MethodHandle PARRAY_GETTER = MH.asType(MH.getter(LOOKUP, ScriptObject.class, "primitiveSpill", long[].class), MH.type(long[].class, Object.class)); |
attila@963 | 43 | private static final MethodHandle OARRAY_GETTER = MH.asType(MH.getter(LOOKUP, ScriptObject.class, "objectSpill", Object[].class), MH.type(Object[].class, Object.class)); |
attila@963 | 44 | |
attila@963 | 45 | private static final MethodHandle OBJECT_GETTER = MH.filterArguments(MH.arrayElementGetter(Object[].class), 0, OARRAY_GETTER); |
attila@963 | 46 | private static final MethodHandle PRIMITIVE_GETTER = MH.filterArguments(MH.arrayElementGetter(long[].class), 0, PARRAY_GETTER); |
attila@963 | 47 | private static final MethodHandle OBJECT_SETTER = MH.filterArguments(MH.arrayElementSetter(Object[].class), 0, OARRAY_GETTER); |
attila@963 | 48 | private static final MethodHandle PRIMITIVE_SETTER = MH.filterArguments(MH.arrayElementSetter(long[].class), 0, PARRAY_GETTER); |
attila@963 | 49 | |
attila@963 | 50 | private static class Accessors { |
attila@963 | 51 | private MethodHandle objectGetter; |
attila@963 | 52 | private MethodHandle objectSetter; |
attila@963 | 53 | private MethodHandle primitiveGetter; |
attila@963 | 54 | private MethodHandle primitiveSetter; |
attila@963 | 55 | |
attila@963 | 56 | private final int slot; |
attila@963 | 57 | private final MethodHandle ensureSpillSize; |
attila@963 | 58 | |
attila@963 | 59 | private static Accessors ACCESSOR_CACHE[] = new Accessors[512]; |
attila@963 | 60 | |
attila@963 | 61 | //private static final Map<Integer, Reference<Accessors>> ACCESSOR_CACHE = Collections.synchronizedMap(new WeakHashMap<Integer, Reference<Accessors>>()); |
attila@963 | 62 | |
attila@963 | 63 | Accessors(final int slot) { |
attila@963 | 64 | assert slot >= 0; |
attila@963 | 65 | this.slot = slot; |
attila@963 | 66 | this.ensureSpillSize = MH.asType(MH.insertArguments(ScriptObject.ENSURE_SPILL_SIZE, 1, slot), MH.type(Object.class, Object.class)); |
attila@963 | 67 | } |
attila@963 | 68 | |
attila@963 | 69 | private static void ensure(final int slot) { |
attila@963 | 70 | int len = ACCESSOR_CACHE.length; |
attila@963 | 71 | if (slot >= len) { |
attila@963 | 72 | do { |
attila@963 | 73 | len *= 2; |
attila@963 | 74 | } while (slot >= len); |
attila@963 | 75 | final Accessors newCache[] = new Accessors[len]; |
attila@963 | 76 | System.arraycopy(ACCESSOR_CACHE, 0, newCache, 0, ACCESSOR_CACHE.length); |
attila@963 | 77 | ACCESSOR_CACHE = newCache; |
attila@963 | 78 | } |
attila@963 | 79 | } |
attila@963 | 80 | |
attila@963 | 81 | static MethodHandle getCached(final int slot, final boolean isPrimitive, final boolean isGetter) { |
attila@963 | 82 | //Reference<Accessors> ref = ACCESSOR_CACHE.get(slot); |
attila@963 | 83 | ensure(slot); |
attila@963 | 84 | Accessors acc = ACCESSOR_CACHE[slot]; |
attila@963 | 85 | if (acc == null) { |
attila@963 | 86 | acc = new Accessors(slot); |
attila@963 | 87 | ACCESSOR_CACHE[slot] = acc; |
attila@963 | 88 | } |
attila@963 | 89 | |
attila@963 | 90 | return acc.getOrCreate(isPrimitive, isGetter); |
attila@963 | 91 | } |
attila@963 | 92 | |
attila@963 | 93 | private static MethodHandle primordial(final boolean isPrimitive, final boolean isGetter) { |
attila@963 | 94 | if (isPrimitive) { |
attila@963 | 95 | return isGetter ? PRIMITIVE_GETTER : PRIMITIVE_SETTER; |
attila@963 | 96 | } |
attila@963 | 97 | return isGetter ? OBJECT_GETTER : OBJECT_SETTER; |
attila@963 | 98 | } |
attila@963 | 99 | |
attila@963 | 100 | MethodHandle getOrCreate(final boolean isPrimitive, final boolean isGetter) { |
attila@963 | 101 | MethodHandle accessor; |
attila@963 | 102 | |
attila@963 | 103 | accessor = getInner(isPrimitive, isGetter); |
attila@963 | 104 | if (accessor != null) { |
attila@963 | 105 | return accessor; |
attila@963 | 106 | } |
attila@963 | 107 | |
attila@963 | 108 | accessor = primordial(isPrimitive, isGetter); |
attila@963 | 109 | accessor = MH.insertArguments(accessor, 1, slot); |
attila@963 | 110 | if (!isGetter) { |
attila@963 | 111 | accessor = MH.filterArguments(accessor, 0, ensureSpillSize); |
attila@963 | 112 | } |
attila@963 | 113 | setInner(isPrimitive, isGetter, accessor); |
attila@963 | 114 | |
attila@963 | 115 | return accessor; |
attila@963 | 116 | } |
attila@963 | 117 | |
attila@963 | 118 | void setInner(final boolean isPrimitive, final boolean isGetter, final MethodHandle mh) { |
attila@963 | 119 | if (isPrimitive) { |
attila@963 | 120 | if (isGetter) { |
attila@963 | 121 | primitiveGetter = mh; |
attila@963 | 122 | } else { |
attila@963 | 123 | primitiveSetter = mh; |
attila@963 | 124 | } |
attila@963 | 125 | } else { |
attila@963 | 126 | if (isGetter) { |
attila@963 | 127 | objectGetter = mh; |
attila@963 | 128 | } else { |
attila@963 | 129 | objectSetter = mh; |
attila@963 | 130 | } |
attila@963 | 131 | } |
attila@963 | 132 | } |
attila@963 | 133 | |
attila@963 | 134 | MethodHandle getInner(final boolean isPrimitive, final boolean isGetter) { |
attila@963 | 135 | if (isPrimitive) { |
attila@963 | 136 | return isGetter ? primitiveGetter : primitiveSetter; |
attila@963 | 137 | } |
attila@963 | 138 | return isGetter ? objectGetter : objectSetter; |
attila@963 | 139 | } |
attila@963 | 140 | } |
attila@963 | 141 | |
attila@963 | 142 | private static MethodHandle primitiveGetter(final int slot) { |
attila@963 | 143 | return OBJECT_FIELDS_ONLY ? null : Accessors.getCached(slot, true, true); |
attila@963 | 144 | } |
attila@963 | 145 | private static MethodHandle primitiveSetter(final int slot) { |
attila@963 | 146 | return OBJECT_FIELDS_ONLY ? null : Accessors.getCached(slot, true, false); |
attila@963 | 147 | } |
attila@963 | 148 | private static MethodHandle objectGetter(final int slot) { |
attila@963 | 149 | return Accessors.getCached(slot, false, true); |
attila@963 | 150 | } |
attila@963 | 151 | private static MethodHandle objectSetter(final int slot) { |
attila@963 | 152 | return Accessors.getCached(slot, false, false); |
attila@963 | 153 | } |
attila@963 | 154 | |
attila@963 | 155 | /** |
attila@963 | 156 | * Constructor for spill properties. Array getters and setters will be created on demand. |
attila@963 | 157 | * |
attila@963 | 158 | * @param key the property key |
attila@963 | 159 | * @param flags the property flags |
attila@963 | 160 | * @param slot spill slot |
attila@963 | 161 | */ |
attila@963 | 162 | public SpillProperty(final String key, final int flags, final int slot) { |
attila@963 | 163 | super(key, flags, slot, primitiveGetter(slot), primitiveSetter(slot), objectGetter(slot), objectSetter(slot)); |
hannesw@1074 | 164 | assert !OBJECT_FIELDS_ONLY || getLocalType() == Object.class; |
attila@963 | 165 | } |
attila@963 | 166 | |
attila@963 | 167 | SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) { |
attila@963 | 168 | this(key, flags, slot); |
hannesw@1074 | 169 | setType(OBJECT_FIELDS_ONLY ? Object.class : initialType); |
attila@963 | 170 | } |
attila@963 | 171 | |
attila@963 | 172 | SpillProperty(final String key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) { |
attila@963 | 173 | this(key, flags, slot); |
attila@963 | 174 | setInitialValue(owner, initialValue); |
attila@963 | 175 | } |
attila@963 | 176 | |
attila@963 | 177 | /** |
attila@963 | 178 | * Copy constructor |
attila@963 | 179 | * @param property other property |
attila@963 | 180 | */ |
attila@963 | 181 | protected SpillProperty(final SpillProperty property) { |
attila@963 | 182 | super(property); |
attila@963 | 183 | } |
attila@963 | 184 | |
attila@963 | 185 | /** |
attila@963 | 186 | * Copy constructor |
attila@963 | 187 | * @param newType new type |
attila@963 | 188 | * @param property other property |
attila@963 | 189 | */ |
attila@963 | 190 | protected SpillProperty(final SpillProperty property, final Class<?> newType) { |
attila@963 | 191 | super(property, newType); |
attila@963 | 192 | } |
attila@963 | 193 | |
attila@963 | 194 | @Override |
attila@963 | 195 | public Property copy() { |
attila@963 | 196 | return new SpillProperty(this); |
attila@963 | 197 | } |
attila@963 | 198 | |
attila@963 | 199 | @Override |
attila@963 | 200 | public Property copy(final Class<?> newType) { |
attila@963 | 201 | return new SpillProperty(this, newType); |
attila@963 | 202 | } |
attila@963 | 203 | |
attila@963 | 204 | @Override |
attila@963 | 205 | public boolean isSpill() { |
attila@963 | 206 | return true; |
attila@963 | 207 | } |
attila@963 | 208 | |
attila@963 | 209 | @Override |
attila@963 | 210 | void initMethodHandles(final Class<?> structure) { |
attila@963 | 211 | final int slot = getSlot(); |
attila@963 | 212 | primitiveGetter = primitiveGetter(slot); |
attila@963 | 213 | primitiveSetter = primitiveSetter(slot); |
attila@963 | 214 | objectGetter = objectGetter(slot); |
attila@963 | 215 | objectSetter = objectSetter(slot); |
attila@963 | 216 | } |
attila@963 | 217 | } |