diff options
Diffstat (limited to 'src/jdk/nashorn/internal/runtime/UserAccessorProperty.java')
-rw-r--r-- | src/jdk/nashorn/internal/runtime/UserAccessorProperty.java | 368 |
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)); + } + } |