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

Thu, 11 Sep 2014 18:04:54 +0200

author
hannesw
date
Thu, 11 Sep 2014 18:04:54 +0200
changeset 1006
e94bfa3c6c6c
parent 991
b7a2db4de254
child 1020
9ee8fd4a7266
permissions
-rw-r--r--

8057021: UserAccessorProperty guards fail with multiple globals
Reviewed-by: attila, lagergren

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.runtime;
jlaskey@3 27
sundar@133 28 import static jdk.nashorn.internal.lookup.Lookup.MH;
attila@963 29 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
jlaskey@3 30
jlaskey@3 31 import java.lang.invoke.MethodHandle;
hannesw@1006 32 import jdk.internal.dynalink.linker.LinkRequest;
lagergren@96 33 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
hannesw@1006 34 import jdk.nashorn.internal.objects.Global;
jlaskey@3 35
jlaskey@3 36 /**
jlaskey@3 37 * This class represents the result from a find property search.
jlaskey@3 38 */
jlaskey@3 39 public final class FindProperty {
jlaskey@80 40 /** Object where search began. */
jlaskey@3 41 private final ScriptObject self;
lagergren@89 42
jlaskey@80 43 /** Object where search finish. */
jlaskey@3 44 private final ScriptObject prototype;
jlaskey@80 45
jlaskey@80 46 /** Found property. */
jlaskey@3 47 private final Property property;
jlaskey@3 48
jlaskey@3 49 /**
jlaskey@3 50 * Constructor
jlaskey@3 51 *
jlaskey@80 52 * @param self script object where search began
jlaskey@3 53 * @param prototype prototype where property was found, may be {@code self} if not inherited
jlaskey@3 54 * @param property property that was search result
jlaskey@3 55 */
jlaskey@80 56 public FindProperty(final ScriptObject self, final ScriptObject prototype, final Property property) {
jlaskey@3 57 this.self = self;
jlaskey@3 58 this.prototype = prototype;
jlaskey@3 59 this.property = property;
jlaskey@3 60 }
jlaskey@3 61
jlaskey@3 62 /**
hannesw@991 63 * Return a copy of this FindProperty with a different property.
hannesw@991 64 *
hannesw@991 65 * @param newProperty the new property
hannesw@991 66 * @return the new FindProperty instance
hannesw@991 67 */
hannesw@991 68 public FindProperty replaceProperty(final Property newProperty) {
hannesw@991 69 assert this.property.getKey().equals(newProperty.getKey());
hannesw@991 70 assert this.property.getSlot() == newProperty.getSlot();
hannesw@991 71 return new FindProperty(self, prototype, newProperty);
hannesw@991 72 }
hannesw@991 73
hannesw@991 74 /**
jlaskey@3 75 * Ask for a getter that returns the given type. The type has nothing to do with the
jlaskey@3 76 * internal representation of the property. It may be an Object (boxing primitives) or
jlaskey@3 77 * a primitive (primitive fields with -Dnashorn.fields.dual=true)
jlaskey@3 78 * @see ObjectClassGenerator
jlaskey@3 79 *
jlaskey@3 80 * @param type type of getter, e.g. int.class if we want a function with {@code get()I} signature
attila@963 81 * @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic
jlaskey@3 82 * @return method handle for the getter
jlaskey@3 83 */
hannesw@1006 84 public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) {
attila@963 85 final MethodHandle getter;
attila@963 86 if (isValid(programPoint)) {
attila@963 87 getter = property.getOptimisticGetter(type, programPoint);
attila@963 88 } else {
attila@963 89 getter = property.getGetter(type);
attila@963 90 }
jlaskey@3 91 if (property instanceof UserAccessorProperty) {
hannesw@1006 92 return insertAccessorsGetter((UserAccessorProperty) property, request, getter);
jlaskey@3 93 }
jlaskey@3 94 return getter;
jlaskey@3 95 }
jlaskey@3 96
jlaskey@3 97 /**
jlaskey@80 98 * Ask for a setter that sets the given type. The type has nothing to do with the
jlaskey@80 99 * internal representation of the property. It may be an Object (boxing primitives) or
jlaskey@80 100 * a primitive (primitive fields with -Dnashorn.fields.dual=true)
jlaskey@80 101 * @see ObjectClassGenerator
jlaskey@80 102 *
jlaskey@80 103 * @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature
jlaskey@80 104 * @param strict are we in strict mode
jlaskey@80 105 *
jlaskey@80 106 * @return method handle for the getter
jlaskey@3 107 */
hannesw@1006 108 public MethodHandle getSetter(final Class<?> type, final boolean strict, final LinkRequest request) {
hannesw@1006 109 MethodHandle setter = property.getSetter(type, getOwner().getMap());
jlaskey@80 110 if (property instanceof UserAccessorProperty) {
hannesw@1006 111 setter = MH.insertArguments(setter, 1, strict ? property.getKey() : null);
hannesw@1006 112 return insertAccessorsGetter((UserAccessorProperty) property, request, setter);
jlaskey@80 113 }
jlaskey@80 114
jlaskey@80 115 return setter;
jlaskey@3 116 }
jlaskey@3 117
hannesw@1006 118 // Fold an accessor getter into the method handle of a user accessor property.
hannesw@1006 119 private MethodHandle insertAccessorsGetter(final UserAccessorProperty uap, final LinkRequest request, final MethodHandle mh) {
hannesw@1006 120 MethodHandle superGetter = uap.getAccessorsGetter();
hannesw@1006 121 if (isInherited()) {
hannesw@1006 122 superGetter = ScriptObject.addProtoFilter(superGetter, getProtoChainLength());
hannesw@1006 123 }
hannesw@1006 124 if (request != null && !(request.getReceiver() instanceof ScriptObject)) {
hannesw@1006 125 final MethodHandle wrapFilter = Global.getPrimitiveWrapFilter(request.getReceiver());
hannesw@1006 126 superGetter = MH.filterArguments(superGetter, 0, wrapFilter.asType(wrapFilter.type().changeReturnType(superGetter.type().parameterType(0))));
hannesw@1006 127 }
hannesw@1006 128 superGetter = MH.asType(superGetter, superGetter.type().changeParameterType(0, Object.class));
hannesw@1006 129
hannesw@1006 130 return MH.foldArguments(mh, superGetter);
hannesw@1006 131 }
hannesw@1006 132
jlaskey@3 133 /**
jlaskey@80 134 * Return the {@code ScriptObject} owning of the property: this means the prototype.
jlaskey@80 135 * @return owner of property
jlaskey@3 136 */
jlaskey@80 137 public ScriptObject getOwner() {
jlaskey@80 138 return prototype;
jlaskey@3 139 }
jlaskey@3 140
jlaskey@3 141 /**
jlaskey@212 142 * Return the appropriate receiver for a getter.
jlaskey@212 143 * @return appropriate receiver
jlaskey@212 144 */
jlaskey@212 145 public ScriptObject getGetterReceiver() {
hannesw@1006 146 return property != null && property instanceof UserAccessorProperty ? self : prototype;
jlaskey@212 147 }
jlaskey@212 148
hannesw@753 149 /**
jlaskey@212 150 * Return the appropriate receiver for a setter.
jlaskey@212 151 * @return appropriate receiver
jlaskey@212 152 */
jlaskey@212 153 public ScriptObject getSetterReceiver() {
jlaskey@379 154 return property != null && property.hasSetterFunction(prototype) ? self : prototype;
jlaskey@212 155 }
jlaskey@212 156
jlaskey@212 157 /**
jlaskey@3 158 * Return the property that was found
jlaskey@3 159 * @return property
jlaskey@3 160 */
jlaskey@3 161 public Property getProperty() {
jlaskey@3 162 return property;
jlaskey@3 163 }
jlaskey@3 164
jlaskey@3 165 /**
jlaskey@3 166 * Check if the property found was inherited, i.e. not directly in the self
jlaskey@3 167 * @return true if inherited property
jlaskey@3 168 */
jlaskey@3 169 public boolean isInherited() {
jlaskey@3 170 return self != prototype;
jlaskey@3 171 }
jlaskey@3 172
jlaskey@3 173 /**
jlaskey@3 174 * Check if the property found was NOT inherited, i.e. defined in the script
jlaskey@3 175 * object, rather than in the prototype
jlaskey@3 176 * @return true if not inherited
jlaskey@3 177 */
jlaskey@3 178 public boolean isSelf() {
jlaskey@3 179 return self == prototype;
jlaskey@3 180 }
jlaskey@3 181
jlaskey@3 182 /**
jlaskey@3 183 * Check if the property is in the scope
jlaskey@3 184 * @return true if on scope
jlaskey@3 185 */
jlaskey@3 186 public boolean isScope() {
jlaskey@80 187 return prototype.isScope();
jlaskey@3 188 }
jlaskey@3 189
hannesw@291 190 /**
hannesw@291 191 * Get the property value from self as object.
attila@963 192 * @return the property value
attila@963 193 */
attila@963 194 public int getIntValue() {
attila@963 195 return property.getIntValue(getGetterReceiver(), getOwner());
attila@963 196 }
attila@963 197 /**
attila@963 198 * Get the property value from self as object.
attila@963 199 * @return the property value
attila@963 200 */
attila@963 201 public long getLongValue() {
attila@963 202 return property.getLongValue(getGetterReceiver(), getOwner());
attila@963 203 }
attila@963 204 /**
attila@963 205 * Get the property value from self as object.
attila@963 206 * @return the property value
attila@963 207 */
attila@963 208 public double getDoubleValue() {
attila@963 209 return property.getDoubleValue(getGetterReceiver(), getOwner());
attila@963 210 }
attila@963 211 /**
attila@963 212 * Get the property value from self as object.
hannesw@291 213 * @return the property value
hannesw@291 214 */
hannesw@291 215 public Object getObjectValue() {
hannesw@291 216 return property.getObjectValue(getGetterReceiver(), getOwner());
hannesw@291 217 }
hannesw@291 218
hannesw@291 219 /**
hannesw@291 220 * Set the property value in self.
hannesw@291 221 *
hannesw@291 222 * @param value the new value
hannesw@291 223 * @param strict strict flag
hannesw@291 224 */
attila@963 225 public void setValue(final int value, final boolean strict) {
attila@963 226 property.setValue(getSetterReceiver(), getOwner(), value, strict);
attila@963 227 }
attila@963 228
attila@963 229 /**
attila@963 230 * Set the property value in self.
attila@963 231 *
attila@963 232 * @param value the new value
attila@963 233 * @param strict strict flag
attila@963 234 */
attila@963 235 public void setValue(final long value, final boolean strict) {
attila@963 236 property.setValue(getSetterReceiver(), getOwner(), value, strict);
attila@963 237 }
attila@963 238
attila@963 239 /**
attila@963 240 * Set the property value in self.
attila@963 241 *
attila@963 242 * @param value the new value
attila@963 243 * @param strict strict flag
attila@963 244 */
attila@963 245 public void setValue(final double value, final boolean strict) {
attila@963 246 property.setValue(getSetterReceiver(), getOwner(), value, strict);
attila@963 247 }
attila@963 248
attila@963 249 /**
attila@963 250 * Set the property value in self.
attila@963 251 *
attila@963 252 * @param value the new value
attila@963 253 * @param strict strict flag
attila@963 254 */
attila@963 255 public void setValue(final Object value, final boolean strict) {
attila@963 256 property.setValue(getSetterReceiver(), getOwner(), value, strict);
hannesw@291 257 }
hannesw@291 258
hannesw@753 259 /**
hannesw@753 260 * Get the number of objects in the prototype chain between the {@code self} and the
hannesw@753 261 * {@code owner} objects.
hannesw@753 262 * @return the prototype chain length
hannesw@753 263 */
hannesw@753 264 int getProtoChainLength() {
hannesw@753 265 assert self != null;
hannesw@753 266 int length = 0;
hannesw@753 267 for (ScriptObject obj = self; obj != prototype; obj = obj.getProto()) {
hannesw@753 268 assert !(obj instanceof WithObject);
hannesw@753 269 ++length;
hannesw@753 270 }
hannesw@753 271 return length;
hannesw@753 272 }
hannesw@753 273
attila@963 274 @Override
attila@963 275 public String toString() {
attila@963 276 return "[FindProperty: " + property.getKey() + ']';
attila@963 277 }
attila@963 278
jlaskey@3 279 }
jlaskey@3 280

mercurial