FindProperty.java revision 1015:8a4af0397070
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 appropriate receiver for a getter. 143 * @return appropriate receiver 144 */ 145 public ScriptObject getGetterReceiver() { 146 return property != null && property instanceof UserAccessorProperty ? self : prototype; 147 } 148 149 /** 150 * Return the appropriate receiver for a setter. 151 * @return appropriate receiver 152 */ 153 public ScriptObject getSetterReceiver() { 154 return property != null && property.hasSetterFunction(prototype) ? self : prototype; 155 } 156 157 /** 158 * Return the property that was found 159 * @return property 160 */ 161 public Property getProperty() { 162 return property; 163 } 164 165 /** 166 * Check if the property found was inherited, i.e. not directly in the self 167 * @return true if inherited property 168 */ 169 public boolean isInherited() { 170 return self != prototype; 171 } 172 173 /** 174 * Check if the property found was NOT inherited, i.e. defined in the script 175 * object, rather than in the prototype 176 * @return true if not inherited 177 */ 178 public boolean isSelf() { 179 return self == prototype; 180 } 181 182 /** 183 * Check if the property is in the scope 184 * @return true if on scope 185 */ 186 public boolean isScope() { 187 return prototype.isScope(); 188 } 189 190 /** 191 * Get the property value from self as object. 192 * @return the property value 193 */ 194 public int getIntValue() { 195 return property.getIntValue(getGetterReceiver(), getOwner()); 196 } 197 /** 198 * Get the property value from self as object. 199 * @return the property value 200 */ 201 public long getLongValue() { 202 return property.getLongValue(getGetterReceiver(), getOwner()); 203 } 204 /** 205 * Get the property value from self as object. 206 * @return the property value 207 */ 208 public double getDoubleValue() { 209 return property.getDoubleValue(getGetterReceiver(), getOwner()); 210 } 211 /** 212 * Get the property value from self as object. 213 * @return the property value 214 */ 215 public Object getObjectValue() { 216 return property.getObjectValue(getGetterReceiver(), getOwner()); 217 } 218 219 /** 220 * Set the property value in self. 221 * 222 * @param value the new value 223 * @param strict strict flag 224 */ 225 public void setValue(final int value, final boolean strict) { 226 property.setValue(getSetterReceiver(), getOwner(), value, strict); 227 } 228 229 /** 230 * Set the property value in self. 231 * 232 * @param value the new value 233 * @param strict strict flag 234 */ 235 public void setValue(final long value, final boolean strict) { 236 property.setValue(getSetterReceiver(), getOwner(), value, strict); 237 } 238 239 /** 240 * Set the property value in self. 241 * 242 * @param value the new value 243 * @param strict strict flag 244 */ 245 public void setValue(final double value, final boolean strict) { 246 property.setValue(getSetterReceiver(), getOwner(), value, strict); 247 } 248 249 /** 250 * Set the property value in self. 251 * 252 * @param value the new value 253 * @param strict strict flag 254 */ 255 public void setValue(final Object value, final boolean strict) { 256 property.setValue(getSetterReceiver(), getOwner(), value, strict); 257 } 258 259 /** 260 * Get the number of objects in the prototype chain between the {@code self} and the 261 * {@code owner} objects. 262 * @return the prototype chain length 263 */ 264 int getProtoChainLength() { 265 assert self != null; 266 int length = 0; 267 for (ScriptObject obj = self; obj != prototype; obj = obj.getProto()) { 268 assert !(obj instanceof WithObject); 269 ++length; 270 } 271 return length; 272 } 273 274 @Override 275 public String toString() { 276 return "[FindProperty: " + property.getKey() + ']'; 277 } 278 279} 280 281