FindProperty.java revision 953:221a84ef44c0
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.nashorn.internal.codegen.ObjectClassGenerator;
33
34/**
35 * This class represents the result from a find property search.
36 */
37public final class FindProperty {
38    /** Object where search began. */
39    private final ScriptObject self;
40
41    /** Object where search finish. */
42    private final ScriptObject prototype;
43
44    /** Found property. */
45    private final Property     property;
46
47    /**
48     * Constructor
49     *
50     * @param self      script object where search began
51     * @param prototype prototype where property was found, may be {@code self} if not inherited
52     * @param property  property that was search result
53     */
54    public FindProperty(final ScriptObject self, final ScriptObject prototype, final Property property) {
55        this.self      = self;
56        this.prototype = prototype;
57        this.property  = property;
58    }
59
60    /**
61     * Ask for a getter that returns the given type. The type has nothing to do with the
62     * internal representation of the property. It may be an Object (boxing primitives) or
63     * a primitive (primitive fields with -Dnashorn.fields.dual=true)
64     * @see ObjectClassGenerator
65     *
66     * @param type type of getter, e.g. int.class if we want a function with {@code get()I} signature
67     * @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic
68     * @return method handle for the getter
69     */
70    public MethodHandle getGetter(final Class<?> type, final int programPoint) {
71        final MethodHandle getter;
72        if (isValid(programPoint)) {
73            getter = property.getOptimisticGetter(type, programPoint);
74        } else {
75            getter = property.getGetter(type);
76        }
77        return getGetterInner(getter);
78    }
79
80    private MethodHandle getGetterInner(final MethodHandle getter) {
81        if (property instanceof UserAccessorProperty) {
82            final UserAccessorProperty uc        = (UserAccessorProperty)property;
83            final ScriptObject         owner     = getOwner();
84            final ScriptObject         container = (owner != null) ? owner : self;
85            return MH.insertArguments(getter, 0, uc.getAccessors(container));
86        }
87        return getter;
88
89    }
90
91    /**
92     * Ask for a setter that sets the given type. The type has nothing to do with the
93     * internal representation of the property. It may be an Object (boxing primitives) or
94     * a primitive (primitive fields with -Dnashorn.fields.dual=true)
95     * @see ObjectClassGenerator
96     *
97     * @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature
98     * @param strict are we in strict mode
99     *
100     * @return method handle for the getter
101     */
102    public MethodHandle getSetter(final Class<?> type, final boolean strict) {
103        final MethodHandle setter = property.getSetter(type, getOwner().getMap());
104        if (property instanceof UserAccessorProperty) {
105            final UserAccessorProperty uc        = (UserAccessorProperty)property;
106            final ScriptObject         owner     = getOwner();
107            final ScriptObject         container = (owner != null) ? owner : self;
108            return MH.insertArguments(setter, 0, uc.getAccessors(container), strict ? property.getKey() : null);
109        }
110
111        return setter;
112    }
113
114    /**
115     * Return the {@code ScriptObject} owning of the property:  this means the prototype.
116     * @return owner of property
117     */
118    public ScriptObject getOwner() {
119        return prototype;
120    }
121
122    /**
123     * Return the appropriate receiver for a getter.
124     * @return appropriate receiver
125     */
126    public ScriptObject getGetterReceiver() {
127        return property != null && property.hasGetterFunction(prototype) ? self : prototype;
128    }
129
130    /**
131     * Return the appropriate receiver for a setter.
132     * @return appropriate receiver
133     */
134    public ScriptObject getSetterReceiver() {
135        return property != null && property.hasSetterFunction(prototype) ? self : prototype;
136    }
137
138    /**
139     * Return the property that was found
140     * @return property
141     */
142    public Property getProperty() {
143        return property;
144    }
145
146    /**
147     * Check if the property found was inherited, i.e. not directly in the self
148     * @return true if inherited property
149     */
150    public boolean isInherited() {
151        return self != prototype;
152    }
153
154    /**
155     * Check if the property found was NOT inherited, i.e. defined in the script
156     * object, rather than in the prototype
157     * @return true if not inherited
158     */
159    public boolean isSelf() {
160        return self == prototype;
161    }
162
163    /**
164     * Check if the property is in the scope
165     * @return true if on scope
166     */
167    public boolean isScope() {
168        return prototype.isScope();
169    }
170
171    /**
172     * Get the property value from self as object.
173     * @return the property value
174     */
175    public int getIntValue() {
176        return property.getIntValue(getGetterReceiver(), getOwner());
177    }
178    /**
179     * Get the property value from self as object.
180     * @return the property value
181     */
182    public long getLongValue() {
183        return property.getLongValue(getGetterReceiver(), getOwner());
184    }
185    /**
186     * Get the property value from self as object.
187     * @return the property value
188     */
189    public double getDoubleValue() {
190        return property.getDoubleValue(getGetterReceiver(), getOwner());
191    }
192    /**
193     * Get the property value from self as object.
194     * @return the property value
195     */
196    public Object getObjectValue() {
197        return property.getObjectValue(getGetterReceiver(), getOwner());
198    }
199
200    /**
201     * Set the property value in self.
202     *
203     * @param value the new value
204     * @param strict strict flag
205     */
206    public void setValue(final int value, final boolean strict) {
207        property.setValue(getSetterReceiver(), getOwner(), value, strict);
208    }
209
210    /**
211     * Set the property value in self.
212     *
213     * @param value the new value
214     * @param strict strict flag
215     */
216    public void setValue(final long value, final boolean strict) {
217        property.setValue(getSetterReceiver(), getOwner(), value, strict);
218    }
219
220    /**
221     * Set the property value in self.
222     *
223     * @param value the new value
224     * @param strict strict flag
225     */
226    public void setValue(final double value, final boolean strict) {
227        property.setValue(getSetterReceiver(), getOwner(), value, strict);
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 Object value, final boolean strict) {
237        property.setValue(getSetterReceiver(), getOwner(), value, strict);
238    }
239
240    /**
241     * Get the number of objects in the prototype chain between the {@code self} and the
242     * {@code owner} objects.
243     * @return the prototype chain length
244     */
245    int getProtoChainLength() {
246        assert self != null;
247        int length = 0;
248        for (ScriptObject obj = self; obj != prototype; obj = obj.getProto()) {
249            assert !(obj instanceof WithObject);
250            ++length;
251        }
252        return length;
253    }
254
255    @Override
256    public String toString() {
257        return "[FindProperty: " + property.getKey() + ']';
258    }
259
260}
261
262