FindProperty.java revision 1036:f0b5e3900a10
1169691Skan/* 2169691Skan * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3169691Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4169691Skan * 5169691Skan * This code is free software; you can redistribute it and/or modify it 6169691Skan * under the terms of the GNU General Public License version 2 only, as 7169691Skan * published by the Free Software Foundation. Oracle designates this 8169691Skan * particular file as subject to the "Classpath" exception as provided 9169691Skan * by Oracle in the LICENSE file that accompanied this code. 10169691Skan * 11169691Skan * This code is distributed in the hope that it will be useful, but WITHOUT 12169691Skan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13169691Skan * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14169691Skan * version 2 for more details (a copy is included in the LICENSE file that 15169691Skan * accompanied this code). 16169691Skan * 17169691Skan * You should have received a copy of the GNU General Public License version 18169691Skan * 2 along with this work; if not, write to the Free Software Foundation, 19169691Skan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20169691Skan * 21169691Skan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22169691Skan * or visit www.oracle.com if you need additional information or have any 23169691Skan * questions. 24169691Skan */ 25169691Skan 26169691Skanpackage jdk.nashorn.internal.runtime; 27169691Skan 28169691Skanimport static jdk.nashorn.internal.lookup.Lookup.MH; 29169691Skanimport static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; 30169691Skan 31169691Skanimport java.lang.invoke.MethodHandle; 32169691Skanimport jdk.internal.dynalink.linker.LinkRequest; 33169691Skanimport jdk.nashorn.internal.codegen.ObjectClassGenerator; 34169691Skanimport jdk.nashorn.internal.objects.Global; 35169691Skan 36169691Skan/** 37169691Skan * This class represents the result from a find property search. 38169691Skan */ 39169691Skanpublic final class FindProperty { 40169691Skan /** Object where search began. */ 41169691Skan private final ScriptObject self; 42169691Skan 43169691Skan /** Object where search finish. */ 44169691Skan private final ScriptObject prototype; 45169691Skan 46169691Skan /** Found property. */ 47169691Skan private final Property property; 48169691Skan 49169691Skan /** 50169691Skan * Constructor 51169691Skan * 52169691Skan * @param self script object where search began 53169691Skan * @param prototype prototype where property was found, may be {@code self} if not inherited 54169691Skan * @param property property that was search result 55169691Skan */ 56169691Skan public FindProperty(final ScriptObject self, final ScriptObject prototype, final Property property) { 57169691Skan this.self = self; 58169691Skan this.prototype = prototype; 59169691Skan this.property = property; 60169691Skan } 61169691Skan 62169691Skan /** 63169691Skan * Return a copy of this FindProperty with a different property. 64169691Skan * 65169691Skan * @param newProperty the new property 66169691Skan * @return the new FindProperty instance 67169691Skan */ 68169691Skan public FindProperty replaceProperty(final Property newProperty) { 69169691Skan assert this.property.getKey().equals(newProperty.getKey()); 70169691Skan assert this.property.getSlot() == newProperty.getSlot(); 71169691Skan return new FindProperty(self, prototype, newProperty); 72169691Skan } 73169691Skan 74169691Skan /** 75169691Skan * Ask for a getter that returns the given type. The type has nothing to do with the 76169691Skan * internal representation of the property. It may be an Object (boxing primitives) or 77169691Skan * a primitive (primitive fields with -Dnashorn.fields.dual=true) 78169691Skan * @see ObjectClassGenerator 79169691Skan * 80169691Skan * @param type type of getter, e.g. int.class if we want a function with {@code get()I} signature 81169691Skan * @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic 82169691Skan * @param request link request 83169691Skan * 84169691Skan * @return method handle for the getter 85169691Skan */ 86169691Skan public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) { 87169691Skan final MethodHandle getter; 88169691Skan if (isValid(programPoint)) { 89169691Skan getter = property.getOptimisticGetter(type, programPoint); 90169691Skan } else { 91169691Skan getter = property.getGetter(type); 92169691Skan } 93169691Skan if (property instanceof UserAccessorProperty) { 94169691Skan return insertAccessorsGetter((UserAccessorProperty) property, request, getter); 95169691Skan } 96169691Skan return getter; 97169691Skan } 98169691Skan 99169691Skan /** 100169691Skan * 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