/* * Copyright (c) 2010-2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.lookup.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; /** * Spill property */ public class SpillProperty extends AccessorProperty { private static final long serialVersionUID = 3028496245198669460L; private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static final MethodHandle PARRAY_GETTER = MH.asType(MH.getter(LOOKUP, ScriptObject.class, "primitiveSpill", long[].class), MH.type(long[].class, Object.class)); private static final MethodHandle OARRAY_GETTER = MH.asType(MH.getter(LOOKUP, ScriptObject.class, "objectSpill", Object[].class), MH.type(Object[].class, Object.class)); private static final MethodHandle OBJECT_GETTER = MH.filterArguments(MH.arrayElementGetter(Object[].class), 0, OARRAY_GETTER); private static final MethodHandle PRIMITIVE_GETTER = MH.filterArguments(MH.arrayElementGetter(long[].class), 0, PARRAY_GETTER); private static final MethodHandle OBJECT_SETTER = MH.filterArguments(MH.arrayElementSetter(Object[].class), 0, OARRAY_GETTER); private static final MethodHandle PRIMITIVE_SETTER = MH.filterArguments(MH.arrayElementSetter(long[].class), 0, PARRAY_GETTER); private static class Accessors { private MethodHandle objectGetter; private MethodHandle objectSetter; private MethodHandle primitiveGetter; private MethodHandle primitiveSetter; private final int slot; private final MethodHandle ensureSpillSize; private static Accessors ACCESSOR_CACHE[] = new Accessors[512]; //private static final Map<Integer, Reference<Accessors>> ACCESSOR_CACHE = Collections.synchronizedMap(new WeakHashMap<Integer, Reference<Accessors>>()); Accessors(final int slot) { assert slot >= 0; this.slot = slot; this.ensureSpillSize = MH.asType(MH.insertArguments(ScriptObject.ENSURE_SPILL_SIZE, 1, slot), MH.type(Object.class, Object.class)); } private static void ensure(final int slot) { int len = ACCESSOR_CACHE.length; if (slot >= len) { do { len *= 2; } while (slot >= len); final Accessors newCache[] = new Accessors[len]; System.arraycopy(ACCESSOR_CACHE, 0, newCache, 0, ACCESSOR_CACHE.length); ACCESSOR_CACHE = newCache; } } static MethodHandle getCached(final int slot, final boolean isPrimitive, final boolean isGetter) { //Reference<Accessors> ref = ACCESSOR_CACHE.get(slot); ensure(slot); Accessors acc = ACCESSOR_CACHE[slot]; if (acc == null) { acc = new Accessors(slot); ACCESSOR_CACHE[slot] = acc; } return acc.getOrCreate(isPrimitive, isGetter); } private static MethodHandle primordial(final boolean isPrimitive, final boolean isGetter) { if (isPrimitive) { return isGetter ? PRIMITIVE_GETTER : PRIMITIVE_SETTER; } return isGetter ? OBJECT_GETTER : OBJECT_SETTER; } MethodHandle getOrCreate(final boolean isPrimitive, final boolean isGetter) { MethodHandle accessor; accessor = getInner(isPrimitive, isGetter); if (accessor != null) { return accessor; } accessor = primordial(isPrimitive, isGetter); accessor = MH.insertArguments(accessor, 1, slot); if (!isGetter) { accessor = MH.filterArguments(accessor, 0, ensureSpillSize); } setInner(isPrimitive, isGetter, accessor); return accessor; } void setInner(final boolean isPrimitive, final boolean isGetter, final MethodHandle mh) { if (isPrimitive) { if (isGetter) { primitiveGetter = mh; } else { primitiveSetter = mh; } } else { if (isGetter) { objectGetter = mh; } else { objectSetter = mh; } } } MethodHandle getInner(final boolean isPrimitive, final boolean isGetter) { if (isPrimitive) { return isGetter ? primitiveGetter : primitiveSetter; } return isGetter ? objectGetter : objectSetter; } } private static MethodHandle primitiveGetter(final int slot, final int flags) { return (flags & DUAL_FIELDS) == DUAL_FIELDS ? Accessors.getCached(slot, true, true) : null; } private static MethodHandle primitiveSetter(final int slot, final int flags) { return (flags & DUAL_FIELDS) == DUAL_FIELDS ? Accessors.getCached(slot, true, false) : null; } private static MethodHandle objectGetter(final int slot) { return Accessors.getCached(slot, false, true); } private static MethodHandle objectSetter(final int slot) { return Accessors.getCached(slot, false, false); } /** * Constructor for spill properties. Array getters and setters will be created on demand. * * @param key the property key * @param flags the property flags * @param slot spill slot */ public SpillProperty(final Object key, final int flags, final int slot) { super(key, flags, slot, primitiveGetter(slot, flags), primitiveSetter(slot, flags), objectGetter(slot), objectSetter(slot)); } /** * Constructor for spill properties with an initial type. * @param key the property key * @param flags the property flags * @param slot spill slot * @param initialType initial type */ public SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) { this(key, flags, slot); setType(hasDualFields() ? initialType : Object.class); } SpillProperty(final Object key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) { this(key, flags, slot); setInitialValue(owner, initialValue); } /** * Copy constructor * @param property other property */ protected SpillProperty(final SpillProperty property) { super(property); } /** * Copy constructor * @param newType new type * @param property other property */ protected SpillProperty(final SpillProperty property, final Class<?> newType) { super(property, newType); } @Override public Property copy() { return new SpillProperty(this); } @Override public Property copy(final Class<?> newType) { return new SpillProperty(this, newType); } @Override public boolean isSpill() { return true; } @Override void initMethodHandles(final Class<?> structure) { final int slot = getSlot(); primitiveGetter = primitiveGetter(slot, getFlags()); primitiveSetter = primitiveSetter(slot, getFlags()); objectGetter = objectGetter(slot); objectSetter = objectSetter(slot); } }