FindProperty.java revision 1033:c1f651636d9c
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 * @return method handle for the getter 83 */ 84 public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) { 85 final MethodHandle getter; 86 if (isValid(programPoint)) { 87 getter = property.getOptimisticGetter(type, programPoint); 88 } else { 89 getter = property.getGetter(type); 90 } 91 if (property instanceof UserAccessorProperty) { 92 return insertAccessorsGetter((UserAccessorProperty) property, request, getter); 93 } 94 return getter; 95 } 96 97 /** 98 * Ask for a setter that sets the given type. The type has nothing to do with the 99 * internal representation of the property. It may be an Object (boxing primitives) or 100 * a primitive (primitive fields with -Dnashorn.fields.dual=true) 101 * @see ObjectClassGenerator 102 * 103 * @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature 104 * @param strict are we in strict mode 105 * 106 * @return method handle for the getter 107 */ 108 public MethodHandle getSetter(final Class<?> type, final boolean strict, final LinkRequest request) { 109 MethodHandle setter = property.getSetter(type, getOwner().getMap()); 110 if (property instanceof UserAccessorProperty) { 111 setter = MH.insertArguments(setter, 1, strict ? property.getKey() : null); 112 return insertAccessorsGetter((UserAccessorProperty) property, request, setter); 113 } 114 115 return setter; 116 } 117 118 // Fold an accessor getter into the method handle of a user accessor property. 119 private MethodHandle insertAccessorsGetter(final UserAccessorProperty uap, final LinkRequest request, final MethodHandle mh) { 120 MethodHandle superGetter = uap.getAccessorsGetter(); 121 if (isInherited()) { 122 superGetter = ScriptObject.addProtoFilter(superGetter, getProtoChainLength()); 123 } 124 if (request != null && !(request.getReceiver() instanceof ScriptObject)) { 125 final MethodHandle wrapFilter = Global.getPrimitiveWrapFilter(request.getReceiver()); 126 superGetter = MH.filterArguments(superGetter, 0, wrapFilter.asType(wrapFilter.type().changeReturnType(superGetter.type().parameterType(0)))); 127 } 128 superGetter = MH.asType(superGetter, superGetter.type().changeParameterType(0, Object.class)); 129 130 return MH.foldArguments(mh, superGetter); 131 } 132 133 /** 134 * Return the {@code ScriptObject} owning of the property: this means the prototype. 135 * @return owner of property 136 */ 137 public ScriptObject getOwner() { 138 return prototype; 139 } 140 141 /** 142 * Return the {@code ScriptObject} where the search started. This is usually the ScriptObject the 143 * operation was started on, except for properties found inside a 'with' statement, where it is the 144 * top-level 'with' expression object. 145 * 146 * @return the start object. 147 */ 148 public ScriptObject getSelf() { 149 return self; 150 } 151 152 /** 153 * Return the appropriate receiver for a getter. 154 * @return appropriate receiver 155 */ 156 public ScriptObject getGetterReceiver() { 157 return property != null && property instanceof UserAccessorProperty ? self : prototype; 158 } 159 160 /** 161 * Return the appropriate receiver for a setter. 162 * @return appropriate receiver 163 */ 164 public ScriptObject getSetterReceiver() { 165 return property != null && property.hasSetterFunction(prototype) ? self : prototype; 166 } 167 168 /** 169 * Return the property that was found 170 * @return property 171 */ 172 public Property getProperty() { 173 return property; 174 } 175 176 /** 177 * Check if the property found was inherited, i.e. not directly in the self 178 * @return true if inherited property 179 */ 180 public boolean isInherited() { 181 return self != prototype; 182 } 183 184 /** 185 * Check if the property found was NOT inherited, i.e. defined in the script 186 * object, rather than in the prototype 187 * @return true if not inherited 188 */ 189 public boolean isSelf() { 190 return self == prototype; 191 } 192 193 /** 194 * Check if the property is in the scope 195 * @return true if on scope 196 */ 197 public boolean isScope() { 198 return prototype.isScope(); 199 } 200 201 /** 202 * Get the property value from self as object. 203 * @return the property value 204 */ 205 public int getIntValue() { 206 return property.getIntValue(getGetterReceiver(), getOwner()); 207 } 208 /** 209 * Get the property value from self as object. 210 * @return the property value 211 */ 212 public long getLongValue() { 213 return property.getLongValue(getGetterReceiver(), getOwner()); 214 } 215 /** 216 * Get the property value from self as object. 217 * @return the property value 218 */ 219 public double getDoubleValue() { 220 return property.getDoubleValue(getGetterReceiver(), getOwner()); 221 } 222 /** 223 * Get the property value from self as object. 224 * @return the property value 225 */ 226 public Object getObjectValue() { 227 return property.getObjectValue(getGetterReceiver(), getOwner()); 228 } 229 230 /** 231 * Set the property value in self. 232 * 233 * @param value the new value 234 * @param strict strict flag 235 */ 236 public void setValue(final int value, final boolean strict) { 237 property.setValue(getSetterReceiver(), getOwner(), value, strict); 238 } 239 240 /** 241 * Set the property value in self. 242 * 243 * @param value the new value 244 * @param strict strict flag 245 */ 246 public void setValue(final long value, final boolean strict) { 247 property.setValue(getSetterReceiver(), getOwner(), value, strict); 248 } 249 250 /** 251 * Set the property value in self. 252 * 253 * @param value the new value 254 * @param strict strict flag 255 */ 256 public void setValue(final double value, final boolean strict) { 257 property.setValue(getSetterReceiver(), getOwner(), value, strict); 258 } 259 260 /** 261 * Set the property value in self. 262 * 263 * @param value the new value 264 * @param strict strict flag 265 */ 266 public void setValue(final Object value, final boolean strict) { 267 property.setValue(getSetterReceiver(), getOwner(), value, strict); 268 } 269 270 /** 271 * Get the number of objects in the prototype chain between the {@code self} and the 272 * {@code owner} objects. 273 * @return the prototype chain length 274 */ 275 int getProtoChainLength() { 276 assert self != null; 277 int length = 0; 278 for (ScriptObject obj = self; obj != prototype; obj = obj.getProto()) { 279 assert !(obj instanceof WithObject); 280 ++length; 281 } 282 return length; 283 } 284 285 @Override 286 public String toString() { 287 return "[FindProperty: " + property.getKey() + ']'; 288 } 289 290} 291 292