src/jdk/nashorn/internal/runtime/UserAccessorProperty.java

Thu, 24 May 2018 16:39:31 +0800

author
aoqi
date
Thu, 24 May 2018 16:39:31 +0800
changeset 1959
61ffdd1b89f2
parent 1720
c09b105e7be5
parent 1205
4112748288bb
permissions
-rw-r--r--

Merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package jdk.nashorn.internal.runtime;
attila@963 27 import static jdk.nashorn.internal.lookup.Lookup.MH;
attila@962 28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
attila@962 29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
hannesw@1074 30 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
hannesw@1074 31 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
attila@962 32
aoqi@0 33 import java.lang.invoke.MethodHandle;
aoqi@0 34 import java.lang.invoke.MethodHandles;
hannesw@1006 35 import java.lang.invoke.MethodType;
attila@1517 36 import java.util.concurrent.Callable;
aoqi@0 37 import jdk.nashorn.internal.lookup.Lookup;
aoqi@0 38 import jdk.nashorn.internal.runtime.linker.Bootstrap;
hannesw@1074 39 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
aoqi@0 40
aoqi@0 41 /**
aoqi@0 42 * Property with user defined getters/setters. Actual getter and setter
aoqi@0 43 * functions are stored in underlying ScriptObject. Only the 'slot' info is
aoqi@0 44 * stored in the property.
aoqi@0 45 */
attila@963 46 public final class UserAccessorProperty extends SpillProperty {
aoqi@0 47
attila@963 48 private static final long serialVersionUID = -5928687246526840321L;
aoqi@0 49
hannesw@1006 50 static final class Accessors {
attila@963 51 Object getter;
attila@963 52 Object setter;
attila@963 53
attila@963 54 Accessors(final Object getter, final Object setter) {
attila@963 55 set(getter, setter);
attila@963 56 }
attila@963 57
attila@963 58 final void set(final Object getter, final Object setter) {
attila@963 59 this.getter = getter;
attila@963 60 this.setter = setter;
attila@963 61 }
attila@963 62
attila@963 63 @Override
attila@963 64 public String toString() {
attila@963 65 return "[getter=" + getter + " setter=" + setter + ']';
attila@963 66 }
attila@963 67 }
hannesw@828 68
hannesw@1006 69 private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
aoqi@0 70
aoqi@0 71 /** Getter method handle */
hannesw@1074 72 private final static MethodHandle INVOKE_OBJECT_GETTER = findOwnMH_S("invokeObjectGetter", Object.class, Accessors.class, MethodHandle.class, Object.class);
hannesw@1074 73 private final static MethodHandle INVOKE_INT_GETTER = findOwnMH_S("invokeIntGetter", int.class, Accessors.class, MethodHandle.class, int.class, Object.class);
hannesw@1074 74 private final static MethodHandle INVOKE_NUMBER_GETTER = findOwnMH_S("invokeNumberGetter", double.class, Accessors.class, MethodHandle.class, int.class, Object.class);
aoqi@0 75
aoqi@0 76 /** Setter method handle */
hannesw@1074 77 private final static MethodHandle INVOKE_OBJECT_SETTER = findOwnMH_S("invokeObjectSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, Object.class);
hannesw@1074 78 private final static MethodHandle INVOKE_INT_SETTER = findOwnMH_S("invokeIntSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, int.class);
hannesw@1074 79 private final static MethodHandle INVOKE_NUMBER_SETTER = findOwnMH_S("invokeNumberSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, double.class);
aoqi@0 80
attila@1517 81 private static final Object OBJECT_GETTER_INVOKER_KEY = new Object();
attila@1517 82 private static MethodHandle getObjectGetterInvoker() {
attila@1517 83 return Context.getGlobal().getDynamicInvoker(OBJECT_GETTER_INVOKER_KEY, new Callable<MethodHandle>() {
attila@1517 84 @Override
attila@1517 85 public MethodHandle call() throws Exception {
attila@1517 86 return getINVOKE_UA_GETTER(Object.class, INVALID_PROGRAM_POINT);
attila@1517 87 }
attila@1517 88 });
attila@1517 89 }
aoqi@0 90
hannesw@1074 91 static MethodHandle getINVOKE_UA_GETTER(final Class<?> returnType, final int programPoint) {
hannesw@1074 92 if (UnwarrantedOptimismException.isValid(programPoint)) {
hannesw@1074 93 final int flags = NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC | programPoint << CALLSITE_PROGRAM_POINT_SHIFT;
hannesw@1074 94 return Bootstrap.createDynamicInvoker("dyn:call", flags, returnType, Object.class, Object.class);
hannesw@1074 95 } else {
hannesw@1074 96 return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class, Object.class);
hannesw@1074 97 }
aoqi@0 98 }
aoqi@0 99
attila@1517 100 private static final Object OBJECT_SETTER_INVOKER_KEY = new Object();
attila@1517 101 private static MethodHandle getObjectSetterInvoker() {
attila@1517 102 return Context.getGlobal().getDynamicInvoker(OBJECT_SETTER_INVOKER_KEY, new Callable<MethodHandle>() {
attila@1517 103 @Override
attila@1517 104 public MethodHandle call() throws Exception {
attila@1517 105 return getINVOKE_UA_SETTER(Object.class);
attila@1517 106 }
attila@1517 107 });
attila@1517 108 }
attila@1517 109
hannesw@1074 110 static MethodHandle getINVOKE_UA_SETTER(final Class<?> valueType) {
hannesw@1074 111 return Bootstrap.createDynamicInvoker("dyn:call", void.class, Object.class, Object.class, valueType);
aoqi@0 112 }
aoqi@0 113
aoqi@0 114 /**
aoqi@0 115 * Constructor
aoqi@0 116 *
attila@963 117 * @param key property key
attila@963 118 * @param flags property flags
attila@963 119 * @param slot spill slot
aoqi@0 120 */
attila@963 121 UserAccessorProperty(final String key, final int flags, final int slot) {
attila@963 122 super(key, flags, slot);
aoqi@0 123 }
aoqi@0 124
aoqi@0 125 private UserAccessorProperty(final UserAccessorProperty property) {
aoqi@0 126 super(property);
aoqi@0 127 }
aoqi@0 128
attila@963 129 private UserAccessorProperty(final UserAccessorProperty property, final Class<?> newType) {
attila@963 130 super(property, newType);
aoqi@0 131 }
aoqi@0 132
aoqi@0 133 @Override
attila@963 134 public Property copy() {
aoqi@0 135 return new UserAccessorProperty(this);
aoqi@0 136 }
aoqi@0 137
aoqi@0 138 @Override
attila@963 139 public Property copy(final Class<?> newType) {
attila@963 140 return new UserAccessorProperty(this, newType);
attila@963 141 }
attila@963 142
attila@963 143 void setAccessors(final ScriptObject sobj, final PropertyMap map, final Accessors gs) {
attila@963 144 try {
attila@963 145 //invoke the getter and find out
attila@963 146 super.getSetter(Object.class, map).invokeExact((Object)sobj, (Object)gs);
attila@963 147 } catch (final Error | RuntimeException t) {
attila@963 148 throw t;
attila@963 149 } catch (final Throwable t) {
attila@963 150 throw new RuntimeException(t);
aoqi@0 151 }
attila@963 152 }
aoqi@0 153
attila@963 154 //pick the getter setter out of the correct spill slot in sobj
attila@963 155 Accessors getAccessors(final ScriptObject sobj) {
attila@963 156 try {
attila@963 157 //invoke the super getter with this spill slot
attila@963 158 //get the getter setter from the correct spill slot
attila@963 159 final Object gs = super.getGetter(Object.class).invokeExact((Object)sobj);
attila@963 160 return (Accessors)gs;
attila@963 161 } catch (final Error | RuntimeException t) {
attila@963 162 throw t;
attila@963 163 } catch (final Throwable t) {
attila@963 164 throw new RuntimeException(t);
attila@963 165 }
aoqi@0 166 }
aoqi@0 167
aoqi@0 168 @Override
hannesw@1074 169 protected Class<?> getLocalType() {
attila@963 170 return Object.class;
aoqi@0 171 }
aoqi@0 172
aoqi@0 173 @Override
attila@963 174 public boolean hasGetterFunction(final ScriptObject sobj) {
attila@963 175 return getAccessors(sobj).getter != null;
aoqi@0 176 }
aoqi@0 177
aoqi@0 178 @Override
attila@963 179 public boolean hasSetterFunction(final ScriptObject sobj) {
attila@963 180 return getAccessors(sobj).setter != null;
attila@963 181 }
attila@963 182
attila@963 183 @Override
attila@963 184 public int getIntValue(final ScriptObject self, final ScriptObject owner) {
attila@963 185 return (int)getObjectValue(self, owner);
attila@963 186 }
attila@963 187
attila@963 188 @Override
attila@963 189 public double getDoubleValue(final ScriptObject self, final ScriptObject owner) {
attila@963 190 return (double)getObjectValue(self, owner);
aoqi@0 191 }
aoqi@0 192
aoqi@0 193 @Override
aoqi@0 194 public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
hannesw@1074 195 try {
attila@1517 196 return invokeObjectGetter(getAccessors((owner != null) ? owner : self), getObjectGetterInvoker(), self);
hannesw@1074 197 } catch (final Error | RuntimeException t) {
hannesw@1074 198 throw t;
hannesw@1074 199 } catch (final Throwable t) {
hannesw@1074 200 throw new RuntimeException(t);
hannesw@1074 201 }
aoqi@0 202 }
aoqi@0 203
aoqi@0 204 @Override
attila@963 205 public void setValue(final ScriptObject self, final ScriptObject owner, final int value, final boolean strict) {
attila@963 206 setValue(self, owner, (Object) value, strict);
attila@963 207 }
attila@963 208
attila@963 209 @Override
attila@963 210 public void setValue(final ScriptObject self, final ScriptObject owner, final double value, final boolean strict) {
attila@963 211 setValue(self, owner, (Object) value, strict);
attila@963 212 }
attila@963 213
attila@963 214 @Override
attila@963 215 public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
hannesw@1074 216 try {
attila@1517 217 invokeObjectSetter(getAccessors((owner != null) ? owner : self), getObjectSetterInvoker(), strict ? getKey() : null, self, value);
hannesw@1074 218 } catch (final Error | RuntimeException t) {
hannesw@1074 219 throw t;
hannesw@1074 220 } catch (final Throwable t) {
hannesw@1074 221 throw new RuntimeException(t);
hannesw@1074 222 }
aoqi@0 223 }
aoqi@0 224
aoqi@0 225 @Override
aoqi@0 226 public MethodHandle getGetter(final Class<?> type) {
attila@963 227 //this returns a getter on the format (Accessors, Object receiver)
hannesw@1074 228 return Lookup.filterReturnType(INVOKE_OBJECT_GETTER, type);
hannesw@828 229 }
hannesw@828 230
hannesw@828 231 @Override
attila@963 232 public MethodHandle getOptimisticGetter(final Class<?> type, final int programPoint) {
hannesw@1074 233 if (type == int.class) {
hannesw@1074 234 return INVOKE_INT_GETTER;
hannesw@1074 235 } else if (type == double.class) {
hannesw@1074 236 return INVOKE_NUMBER_GETTER;
hannesw@1074 237 } else {
hannesw@1074 238 assert type == Object.class;
hannesw@1074 239 return INVOKE_OBJECT_GETTER;
attila@963 240 }
aoqi@0 241 }
aoqi@0 242
aoqi@0 243 @Override
aoqi@0 244 void initMethodHandles(final Class<?> structure) {
aoqi@0 245 throw new UnsupportedOperationException();
aoqi@0 246 }
aoqi@0 247
aoqi@0 248 @Override
attila@963 249 public ScriptFunction getGetterFunction(final ScriptObject sobj) {
attila@963 250 final Object value = getAccessors(sobj).getter;
attila@963 251 return (value instanceof ScriptFunction) ? (ScriptFunction)value : null;
aoqi@0 252 }
aoqi@0 253
aoqi@0 254 @Override
aoqi@0 255 public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
hannesw@1074 256 if (type == int.class) {
hannesw@1074 257 return INVOKE_INT_SETTER;
hannesw@1074 258 } else if (type == double.class) {
hannesw@1074 259 return INVOKE_NUMBER_SETTER;
hannesw@1074 260 } else {
hannesw@1074 261 assert type == Object.class;
hannesw@1074 262 return INVOKE_OBJECT_SETTER;
hannesw@1074 263 }
aoqi@0 264 }
aoqi@0 265
aoqi@0 266 @Override
attila@963 267 public ScriptFunction getSetterFunction(final ScriptObject sobj) {
attila@963 268 final Object value = getAccessors(sobj).setter;
attila@963 269 return (value instanceof ScriptFunction) ? (ScriptFunction)value : null;
hannesw@828 270 }
hannesw@828 271
hannesw@1006 272 /**
hannesw@1006 273 * Get the getter for the {@code Accessors} object.
hannesw@1006 274 * This is the the super {@code Object} type getter with {@code Accessors} return type.
hannesw@1006 275 *
hannesw@1006 276 * @return The getter handle for the Accessors
hannesw@1006 277 */
hannesw@1006 278 MethodHandle getAccessorsGetter() {
hannesw@1006 279 return super.getGetter(Object.class).asType(MethodType.methodType(Accessors.class, Object.class));
aoqi@0 280 }
aoqi@0 281
aoqi@0 282 // User defined getter and setter are always called by "dyn:call". Note that the user
aoqi@0 283 // getter/setter may be inherited. If so, proto is bound during lookup. In either
aoqi@0 284 // inherited or self case, slot is also bound during lookup. Actual ScriptFunction
aoqi@0 285 // to be called is retrieved everytime and applied.
hannesw@1074 286 @SuppressWarnings("unused")
hannesw@1074 287 private static Object invokeObjectGetter(final Accessors gs, final MethodHandle invoker, final Object self) throws Throwable {
attila@963 288 final Object func = gs.getter;
aoqi@0 289 if (func instanceof ScriptFunction) {
hannesw@1074 290 return invoker.invokeExact(func, self);
aoqi@0 291 }
aoqi@0 292
aoqi@0 293 return UNDEFINED;
aoqi@0 294 }
aoqi@0 295
hannesw@1074 296 @SuppressWarnings("unused")
hannesw@1074 297 private static int invokeIntGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
hannesw@1074 298 final Object func = gs.getter;
hannesw@1074 299 if (func instanceof ScriptFunction) {
hannesw@1074 300 return (int) invoker.invokeExact(func, self);
hannesw@1074 301 }
aoqi@0 302
hannesw@1074 303 throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
hannesw@1074 304 }
hannesw@1074 305
hannesw@1074 306 @SuppressWarnings("unused")
hannesw@1074 307 private static double invokeNumberGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
hannesw@1074 308 final Object func = gs.getter;
hannesw@1074 309 if (func instanceof ScriptFunction) {
hannesw@1074 310 return (double) invoker.invokeExact(func, self);
hannesw@1074 311 }
hannesw@1074 312
hannesw@1074 313 throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
hannesw@1074 314 }
hannesw@1074 315
hannesw@1074 316 @SuppressWarnings("unused")
hannesw@1074 317 private static void invokeObjectSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final Object value) throws Throwable {
attila@963 318 final Object func = gs.setter;
hannesw@828 319 if (func instanceof ScriptFunction) {
hannesw@1074 320 invoker.invokeExact(func, self, value);
hannesw@1074 321 } else if (name != null) {
aoqi@0 322 throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
aoqi@0 323 }
aoqi@0 324 }
aoqi@0 325
hannesw@1074 326 @SuppressWarnings("unused")
hannesw@1074 327 private static void invokeIntSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final int value) throws Throwable {
hannesw@1074 328 final Object func = gs.setter;
hannesw@1074 329 if (func instanceof ScriptFunction) {
hannesw@1074 330 invoker.invokeExact(func, self, value);
hannesw@1074 331 } else if (name != null) {
hannesw@1074 332 throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
hannesw@1074 333 }
hannesw@1074 334 }
hannesw@1074 335
hannesw@1074 336 @SuppressWarnings("unused")
hannesw@1074 337 private static void invokeNumberSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final double value) throws Throwable {
hannesw@1074 338 final Object func = gs.setter;
hannesw@1074 339 if (func instanceof ScriptFunction) {
hannesw@1074 340 invoker.invokeExact(func, self, value);
attila@963 341 } else if (name != null) {
hannesw@828 342 throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
hannesw@828 343 }
hannesw@828 344 }
hannesw@828 345
hannesw@1006 346 private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
hannesw@1006 347 return MH.findStatic(LOOKUP, UserAccessorProperty.class, name, MH.type(rtype, types));
hannesw@1006 348 }
hannesw@1006 349
aoqi@0 350 }

mercurial