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