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 26 package jdk.nashorn.internal.runtime; 27 28 import static jdk.nashorn.internal.lookup.Lookup.MH; 29 30 import java.lang.invoke.MethodHandle; 31 import jdk.nashorn.internal.codegen.ObjectClassGenerator; 32 33 /** 34 * This class represents the result from a find property search. 35 */ 36 public final class FindProperty { 37 /** Object where search began. */ 38 private final ScriptObject self; 39 40 /** Object where search finish. */ 41 private final ScriptObject prototype; 42 43 /** Found property. */ 44 private final Property property; 45 46 /** 47 * Constructor 48 * 49 * @param self script object where search began 50 * @param prototype prototype where property was found, may be {@code self} if not inherited 51 * @param property property that was search result 52 */ 53 public FindProperty(final ScriptObject self, final ScriptObject prototype, final Property property) { 54 this.self = self; 55 this.prototype = prototype; 56 this.property = property; 57 } 58 59 /** 60 * Ask for a getter that returns the given type. The type has nothing to do with the 61 * internal representation of the property. It may be an Object (boxing primitives) or 62 * a primitive (primitive fields with -Dnashorn.fields.dual=true) 63 * @see ObjectClassGenerator 64 * 65 * @param type type of getter, e.g. int.class if we want a function with {@code get()I} signature 66 * @return method handle for the getter 67 */ 68 public MethodHandle getGetter(final Class<?> type) { 69 MethodHandle getter = property.getGetter(type); 70 if (property instanceof UserAccessorProperty) { 71 final UserAccessorProperty uc = (UserAccessorProperty)property; 72 getter = MH.insertArguments(getter, 0, isInherited() ? getOwner() : null, uc.getGetterSlot()); 73 } 74 return getter; 75 } 76 77 /** 78 * Ask for a setter that sets the given type. The type has nothing to do with the 79 * internal representation of the property. It may be an Object (boxing primitives) or 80 * a primitive (primitive fields with -Dnashorn.fields.dual=true) 81 * @see ObjectClassGenerator 82 * 83 * @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature 84 * @param strict are we in strict mode 85 * 86 * @return method handle for the getter 87 */ 88 public MethodHandle getSetter(final Class<?> type, final boolean strict) { 89 MethodHandle setter = property.getSetter(type, getOwner().getMap()); 90 if (property instanceof UserAccessorProperty) { 91 final UserAccessorProperty uc = (UserAccessorProperty) property; 92 setter = MH.insertArguments(setter, 0, isInherited() ? getOwner() : null, 93 uc.getSetterSlot(), strict? property.getKey() : null); 94 } 95 96 return setter; 97 } 98 99 /** 100 * Return the {@code ScriptObject} owning of the property: this means the prototype. 101 * @return owner of property 102 */ 103 public ScriptObject getOwner() { 104 return prototype; 105 } 106 107 /** 108 * Return the appropriate receiver for a getter. 109 * @return appropriate receiver 110 */ 111 public ScriptObject getGetterReceiver() { 112 return property != null && property.hasGetterFunction(prototype) ? self : prototype; 113 } 114 115 /** 116 * Return the appropriate receiver for a setter. 117 * @return appropriate receiver 118 */ 119 public ScriptObject getSetterReceiver() { 120 return property != null && property.hasSetterFunction(prototype) ? self : prototype; 121 } 122 123 /** 124 * Return the property that was found 125 * @return property 126 */ 127 public Property getProperty() { 128 return property; 129 } 130 131 /** 132 * Check if the property found was inherited, i.e. not directly in the self 133 * @return true if inherited property 134 */ 135 public boolean isInherited() { 136 return self != prototype; 137 } 138 139 /** 140 * Check if the property found was NOT inherited, i.e. defined in the script 141 * object, rather than in the prototype 142 * @return true if not inherited 143 */ 144 public boolean isSelf() { 145 return self == prototype; 146 } 147 148 /** 149 * Check if the property is in the scope 150 * @return true if on scope 151 */ 152 public boolean isScope() { 153 return prototype.isScope(); 154 } 155 156 /** 157 * Get the property value from self as object. 158 * 159 * @return the property value 160 */ 161 public Object getObjectValue() { 162 return property.getObjectValue(getGetterReceiver(), getOwner()); 163 } 164 165 /** 166 * Set the property value in self. 167 * 168 * @param value the new value 169 * @param strict strict flag 170 */ 171 public void setObjectValue(final Object value, final boolean strict) { 172 property.setObjectValue(getSetterReceiver(), getOwner(), value, strict); 173 } 174 175 /** 176 * Get the number of objects in the prototype chain between the {@code self} and the 177 * {@code owner} objects. 178 * @return the prototype chain length 179 */ 180 int getProtoChainLength() { 181 assert self != null; 182 int length = 0; 183 for (ScriptObject obj = self; obj != prototype; obj = obj.getProto()) { 184 assert !(obj instanceof WithObject); 185 ++length; 186 } 187 return length; 188 } 189 190 } 191