aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/runtime/SpillProperty.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/runtime/SpillProperty.java')
-rw-r--r--src/jdk/nashorn/internal/runtime/SpillProperty.java217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/jdk/nashorn/internal/runtime/SpillProperty.java b/src/jdk/nashorn/internal/runtime/SpillProperty.java
new file mode 100644
index 00000000..7b42b2bf
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/SpillProperty.java
@@ -0,0 +1,217 @@
+/*
+ * 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.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
+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) {
+ return OBJECT_FIELDS_ONLY ? null : Accessors.getCached(slot, true, true);
+ }
+ private static MethodHandle primitiveSetter(final int slot) {
+ return OBJECT_FIELDS_ONLY ? null : Accessors.getCached(slot, true, false);
+ }
+ 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 String key, final int flags, final int slot) {
+ super(key, flags, slot, primitiveGetter(slot), primitiveSetter(slot), objectGetter(slot), objectSetter(slot));
+ assert !OBJECT_FIELDS_ONLY || getLocalType() == Object.class;
+ }
+
+ SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) {
+ this(key, flags, slot);
+ setType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
+ }
+
+ SpillProperty(final String 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);
+ primitiveSetter = primitiveSetter(slot);
+ objectGetter = objectGetter(slot);
+ objectSetter = objectSetter(slot);
+ }
+}