aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/runtime/UserAccessorProperty.java')
-rw-r--r--src/jdk/nashorn/internal/runtime/UserAccessorProperty.java368
1 files changed, 243 insertions, 125 deletions
diff --git a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
index 5b21f6ee..d14dd8e7 100644
--- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
@@ -25,165 +25,214 @@
package jdk.nashorn.internal.runtime;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
+import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
+
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
-import java.util.concurrent.Callable;
-
-import jdk.nashorn.internal.codegen.CompilerConstants;
+import java.lang.invoke.MethodType;
import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
-
-import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
-import jdk.nashorn.internal.objects.Global;
-import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* Property with user defined getters/setters. Actual getter and setter
* functions are stored in underlying ScriptObject. Only the 'slot' info is
* stored in the property.
- *
- * The slots here denote either ScriptObject embed field number or spill
- * array index. For spill array index, we use slot value of
- * (index + ScriptObject.embedSize). See also ScriptObject.getEmbedOrSpill
- * method. Negative slot value means that the corresponding getter or setter
- * is null. Note that always two slots are allocated in ScriptObject - but
- * negative (less by 1) slot number is stored for null getter or setter.
- * This is done so that when the property is redefined with a different
- * getter and setter (say, both non-null), we'll have spill slots to store
- * those. When a slot is negative, (-slot - 1) is the embed/spill index.
*/
-public final class UserAccessorProperty extends Property {
+public final class UserAccessorProperty extends SpillProperty {
- /** User defined getter function slot. */
- private final int getterSlot;
+ private static final long serialVersionUID = -5928687246526840321L;
- /** User defined setter function slot. */
- private final int setterSlot;
+ static final class Accessors {
+ Object getter;
+ Object setter;
- /** Getter method handle */
- private final static CompilerConstants.Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
- "userAccessorGetter", Object.class, ScriptObject.class, int.class, Object.class);
+ Accessors(final Object getter, final Object setter) {
+ set(getter, setter);
+ }
- /** Setter method handle */
- private final static CompilerConstants.Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
- "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class);
+ final void set(final Object getter, final Object setter) {
+ this.getter = getter;
+ this.setter = setter;
+ }
+
+ @Override
+ public String toString() {
+ return "[getter=" + getter + " setter=" + setter + ']';
+ }
+ }
- /** Dynamic invoker for getter */
- private static final Object INVOKE_UA_GETTER = new Object();
+ private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
- private static MethodHandle getINVOKE_UA_GETTER() {
+ /** Getter method handle */
+ private final static MethodHandle INVOKE_OBJECT_GETTER = findOwnMH_S("invokeObjectGetter", Object.class, Accessors.class, MethodHandle.class, Object.class);
+ private final static MethodHandle INVOKE_INT_GETTER = findOwnMH_S("invokeIntGetter", int.class, Accessors.class, MethodHandle.class, int.class, Object.class);
+ private final static MethodHandle INVOKE_LONG_GETTER = findOwnMH_S("invokeLongGetter", long.class, Accessors.class, MethodHandle.class, int.class, Object.class);
+ private final static MethodHandle INVOKE_NUMBER_GETTER = findOwnMH_S("invokeNumberGetter", double.class, Accessors.class, MethodHandle.class, int.class, Object.class);
- return Context.getGlobal().getDynamicInvoker(INVOKE_UA_GETTER,
- new Callable<MethodHandle>() {
- @Override
- public MethodHandle call() {
- return Bootstrap.createDynamicInvoker("dyn:call", Object.class,
- Object.class, Object.class);
- }
- });
+ /** Setter method handle */
+ private final static MethodHandle INVOKE_OBJECT_SETTER = findOwnMH_S("invokeObjectSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, Object.class);
+ private final static MethodHandle INVOKE_INT_SETTER = findOwnMH_S("invokeIntSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, int.class);
+ private final static MethodHandle INVOKE_LONG_SETTER = findOwnMH_S("invokeLongSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, long.class);
+ private final static MethodHandle INVOKE_NUMBER_SETTER = findOwnMH_S("invokeNumberSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, double.class);
+
+
+ static MethodHandle getINVOKE_UA_GETTER(final Class<?> returnType, final int programPoint) {
+ if (UnwarrantedOptimismException.isValid(programPoint)) {
+ final int flags = NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC | programPoint << CALLSITE_PROGRAM_POINT_SHIFT;
+ return Bootstrap.createDynamicInvoker("dyn:call", flags, returnType, Object.class, Object.class);
+ } else {
+ return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class, Object.class);
+ }
}
- /** Dynamic invoker for setter */
- private static Object INVOKE_UA_SETTER = new Object();
- private static MethodHandle getINVOKE_UA_SETTER() {
- return Context.getGlobal().getDynamicInvoker(INVOKE_UA_SETTER,
- new Callable<MethodHandle>() {
- @Override
- public MethodHandle call() {
- return Bootstrap.createDynamicInvoker("dyn:call", void.class,
- Object.class, Object.class, Object.class);
- }
- });
+ static MethodHandle getINVOKE_UA_SETTER(final Class<?> valueType) {
+ return Bootstrap.createDynamicInvoker("dyn:call", void.class, Object.class, Object.class, valueType);
}
/**
* Constructor
*
- * @param key property key
- * @param flags property flags
- * @param getterSlot getter slot, starting at first embed
- * @param setterSlot setter slot, starting at first embed
+ * @param key property key
+ * @param flags property flags
+ * @param slot spill slot
*/
- UserAccessorProperty(final String key, final int flags, final int getterSlot, final int setterSlot) {
- super(key, flags, -1);
- this.getterSlot = getterSlot;
- this.setterSlot = setterSlot;
+ UserAccessorProperty(final String key, final int flags, final int slot) {
+ super(key, flags, slot);
}
private UserAccessorProperty(final UserAccessorProperty property) {
super(property);
- this.getterSlot = property.getterSlot;
- this.setterSlot = property.setterSlot;
- }
-
- /**
- * Return getter spill slot for this UserAccessorProperty.
- * @return getter slot
- */
- public int getGetterSlot() {
- return getterSlot;
}
- /**
- * Return setter spill slot for this UserAccessorProperty.
- * @return setter slot
- */
- public int getSetterSlot() {
- return setterSlot;
+ private UserAccessorProperty(final UserAccessorProperty property, final Class<?> newType) {
+ super(property, newType);
}
@Override
- protected Property copy() {
+ public Property copy() {
return new UserAccessorProperty(this);
}
@Override
- public boolean equals(final Object other) {
- if (!super.equals(other)) {
- return false;
+ public Property copy(final Class<?> newType) {
+ return new UserAccessorProperty(this, newType);
+ }
+
+ void setAccessors(final ScriptObject sobj, final PropertyMap map, final Accessors gs) {
+ try {
+ //invoke the getter and find out
+ super.getSetter(Object.class, map).invokeExact((Object)sobj, (Object)gs);
+ } catch (final Error | RuntimeException t) {
+ throw t;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
}
+ }
- final UserAccessorProperty uc = (UserAccessorProperty) other;
- return getterSlot == uc.getterSlot && setterSlot == uc.setterSlot;
+ //pick the getter setter out of the correct spill slot in sobj
+ Accessors getAccessors(final ScriptObject sobj) {
+ try {
+ //invoke the super getter with this spill slot
+ //get the getter setter from the correct spill slot
+ final Object gs = super.getGetter(Object.class).invokeExact((Object)sobj);
+ return (Accessors)gs;
+ } catch (final Error | RuntimeException t) {
+ throw t;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
}
@Override
- public int hashCode() {
- return super.hashCode() ^ getterSlot ^ setterSlot;
+ protected Class<?> getLocalType() {
+ return Object.class;
+ }
+
+ @Override
+ public boolean hasGetterFunction(final ScriptObject sobj) {
+ return getAccessors(sobj).getter != null;
+ }
+
+ @Override
+ public boolean hasSetterFunction(final ScriptObject sobj) {
+ return getAccessors(sobj).setter != null;
}
- /*
- * Accessors.
- */
@Override
- public int getSpillCount() {
- return 2;
+ public int getIntValue(final ScriptObject self, final ScriptObject owner) {
+ return (int)getObjectValue(self, owner);
}
@Override
- public boolean hasGetterFunction(final ScriptObject obj) {
- return obj.getSpill(getterSlot) != null;
+ public long getLongValue(final ScriptObject self, final ScriptObject owner) {
+ return (long)getObjectValue(self, owner);
}
@Override
- public boolean hasSetterFunction(final ScriptObject obj) {
- return obj.getSpill(setterSlot) != null;
+ public double getDoubleValue(final ScriptObject self, final ScriptObject owner) {
+ return (double)getObjectValue(self, owner);
}
@Override
public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
- return userAccessorGetter(owner, getGetterSlot(), self);
+ try {
+ return invokeObjectGetter(getAccessors((owner != null) ? owner : self), getINVOKE_UA_GETTER(Object.class, INVALID_PROGRAM_POINT), self);
+ } catch (final Error | RuntimeException t) {
+ throw t;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ @Override
+ public void setValue(final ScriptObject self, final ScriptObject owner, final int value, final boolean strict) {
+ setValue(self, owner, (Object) value, strict);
+ }
+
+ @Override
+ public void setValue(final ScriptObject self, final ScriptObject owner, final long value, final boolean strict) {
+ setValue(self, owner, (Object) value, strict);
+ }
+
+ @Override
+ public void setValue(final ScriptObject self, final ScriptObject owner, final double value, final boolean strict) {
+ setValue(self, owner, (Object) value, strict);
}
@Override
- public void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
- userAccessorSetter(owner, getSetterSlot(), strict ? getKey() : null, self, value);
+ public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
+ try {
+ invokeObjectSetter(getAccessors((owner != null) ? owner : self), getINVOKE_UA_SETTER(Object.class), strict ? getKey() : null, self, value);
+ } catch (final Error | RuntimeException t) {
+ throw t;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
}
@Override
public MethodHandle getGetter(final Class<?> type) {
- return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type);
+ //this returns a getter on the format (Accessors, Object receiver)
+ return Lookup.filterReturnType(INVOKE_OBJECT_GETTER, type);
+ }
+
+ @Override
+ public MethodHandle getOptimisticGetter(final Class<?> type, final int programPoint) {
+ if (type == int.class) {
+ return INVOKE_INT_GETTER;
+ } else if (type == long.class) {
+ return INVOKE_LONG_GETTER;
+ } else if (type == double.class) {
+ return INVOKE_NUMBER_GETTER;
+ } else {
+ assert type == Object.class;
+ return INVOKE_OBJECT_GETTER;
+ }
}
@Override
@@ -192,58 +241,127 @@ public final class UserAccessorProperty extends Property {
}
@Override
- public ScriptFunction getGetterFunction(final ScriptObject obj) {
- final Object value = obj.getSpill(getterSlot);
- return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
+ public ScriptFunction getGetterFunction(final ScriptObject sobj) {
+ final Object value = getAccessors(sobj).getter;
+ return (value instanceof ScriptFunction) ? (ScriptFunction)value : null;
}
@Override
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
- return USER_ACCESSOR_SETTER.methodHandle();
+ if (type == int.class) {
+ return INVOKE_INT_SETTER;
+ } else if (type == long.class) {
+ return INVOKE_LONG_SETTER;
+ } else if (type == double.class) {
+ return INVOKE_NUMBER_SETTER;
+ } else {
+ assert type == Object.class;
+ return INVOKE_OBJECT_SETTER;
+ }
}
@Override
- public ScriptFunction getSetterFunction(final ScriptObject obj) {
- final Object value = obj.getSpill(setterSlot);
- return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
+ public ScriptFunction getSetterFunction(final ScriptObject sobj) {
+ final Object value = getAccessors(sobj).setter;
+ return (value instanceof ScriptFunction) ? (ScriptFunction)value : null;
+ }
+
+ /**
+ * Get the getter for the {@code Accessors} object.
+ * This is the the super {@code Object} type getter with {@code Accessors} return type.
+ *
+ * @return The getter handle for the Accessors
+ */
+ MethodHandle getAccessorsGetter() {
+ return super.getGetter(Object.class).asType(MethodType.methodType(Accessors.class, Object.class));
}
// User defined getter and setter are always called by "dyn:call". Note that the user
// getter/setter may be inherited. If so, proto is bound during lookup. In either
// inherited or self case, slot is also bound during lookup. Actual ScriptFunction
// to be called is retrieved everytime and applied.
- static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) {
- final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
- final Object func = container.getSpill(slot);
-
+ @SuppressWarnings("unused")
+ private static Object invokeObjectGetter(final Accessors gs, final MethodHandle invoker, final Object self) throws Throwable {
+ final Object func = gs.getter;
if (func instanceof ScriptFunction) {
- try {
- return getINVOKE_UA_GETTER().invokeExact(func, self);
- } catch(final Error|RuntimeException t) {
- throw t;
- } catch(final Throwable t) {
- throw new RuntimeException(t);
- }
+ return invoker.invokeExact(func, self);
}
return UNDEFINED;
}
- static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) {
- final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
- final Object func = container.getSpill(slot);
+ @SuppressWarnings("unused")
+ private static int invokeIntGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
+ final Object func = gs.getter;
+ if (func instanceof ScriptFunction) {
+ return (int) invoker.invokeExact(func, self);
+ }
+
+ throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
+ }
+
+ @SuppressWarnings("unused")
+ private static long invokeLongGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
+ final Object func = gs.getter;
+ if (func instanceof ScriptFunction) {
+ return (long) invoker.invokeExact(func, self);
+ }
+
+ throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
+ }
+
+ @SuppressWarnings("unused")
+ private static double invokeNumberGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
+ final Object func = gs.getter;
+ if (func instanceof ScriptFunction) {
+ return (double) invoker.invokeExact(func, self);
+ }
+
+ throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
+ }
+
+ @SuppressWarnings("unused")
+ private static void invokeObjectSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final Object value) throws Throwable {
+ final Object func = gs.setter;
+ if (func instanceof ScriptFunction) {
+ invoker.invokeExact(func, self, value);
+ } else if (name != null) {
+ throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void invokeIntSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final int value) throws Throwable {
+ final Object func = gs.setter;
+ if (func instanceof ScriptFunction) {
+ invoker.invokeExact(func, self, value);
+ } else if (name != null) {
+ throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
+ }
+ }
+ @SuppressWarnings("unused")
+ private static void invokeLongSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final long value) throws Throwable {
+ final Object func = gs.setter;
if (func instanceof ScriptFunction) {
- try {
- getINVOKE_UA_SETTER().invokeExact(func, self, value);
- } catch(final Error|RuntimeException t) {
- throw t;
- } catch(final Throwable t) {
- throw new RuntimeException(t);
- }
- } else if (name != null) {
+ invoker.invokeExact(func, self, value);
+ } else if (name != null) {
throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
}
}
+ @SuppressWarnings("unused")
+ private static void invokeNumberSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final double value) throws Throwable {
+ final Object func = gs.setter;
+ if (func instanceof ScriptFunction) {
+ invoker.invokeExact(func, self, value);
+ } else if (name != null) {
+ throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
+ }
+ }
+
+ private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
+ return MH.findStatic(LOOKUP, UserAccessorProperty.class, name, MH.type(rtype, types));
+ }
+
}