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 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
30 
31 import java.lang.invoke.MethodHandle;
32 import java.lang.invoke.MethodHandles;
33 import java.util.ArrayList;
34 import jdk.nashorn.internal.objects.Global;
35 
36 /**
37  * Instances of this class serve as "prototype" object for script functions.
38  * The purpose is to expose "constructor" property from "prototype". Also, nasgen
39  * generated prototype classes extend from this class.
40  */
41 public class PrototypeObject extends ScriptObject {
42     private static final PropertyMap map$;
43 
44     private Object constructor;
45 
46     private static final MethodHandle GET_CONSTRUCTOR = findOwnMH("getConstructor", Object.class, Object.class);
47     private static final MethodHandle SET_CONSTRUCTOR = findOwnMH("setConstructor", void.class, Object.class, Object.class);
48 
49     static {
50         final ArrayList<Property> properties = new ArrayList<>(1);
51         properties.add(AccessorProperty.create("constructor", Property.NOT_ENUMERABLE, GET_CONSTRUCTOR, SET_CONSTRUCTOR));
52         map$ = PropertyMap.newMap(properties);
53     }
54 
PrototypeObject(final Global global, final PropertyMap map)55     private PrototypeObject(final Global global, final PropertyMap map) {
56         super(global.getObjectPrototype(), map != map$? map.addAll(map$) : map$);
57     }
58 
59     /**
60      * Prototype constructor
61      */
PrototypeObject()62     protected PrototypeObject() {
63         this(Global.instance(), map$);
64     }
65 
66     /**
67      * PropertyObject constructor
68      *
69      * @param map property map
70      */
PrototypeObject(final PropertyMap map)71     protected PrototypeObject(final PropertyMap map) {
72         this(Global.instance(), map);
73     }
74 
75     /**
76      * PropertyObject constructor
77      *
78      * @param func constructor function
79      */
PrototypeObject(final ScriptFunction func)80     protected PrototypeObject(final ScriptFunction func) {
81         this(Global.instance(), map$);
82         this.constructor = func;
83     }
84 
85     /**
86      * Get the constructor for this {@code PrototypeObject}
87      * @param self self reference
88      * @return constructor, probably, but not necessarily, a {@link ScriptFunction}
89      */
getConstructor(final Object self)90     public static Object getConstructor(final Object self) {
91         return (self instanceof PrototypeObject) ?
92             ((PrototypeObject)self).getConstructor() :
93             UNDEFINED;
94     }
95 
96     /**
97      * Reset the constructor for this {@code PrototypeObject}
98      * @param self self reference
99      * @param constructor constructor, probably, but not necessarily, a {@link ScriptFunction}
100      */
setConstructor(final Object self, final Object constructor)101     public static void setConstructor(final Object self, final Object constructor) {
102         if (self instanceof PrototypeObject) {
103             ((PrototypeObject)self).setConstructor(constructor);
104         }
105     }
106 
getConstructor()107     private Object getConstructor() {
108         return constructor;
109     }
110 
setConstructor(final Object constructor)111     private void setConstructor(final Object constructor) {
112         this.constructor = constructor;
113     }
114 
findOwnMH(final String name, final Class<?> rtype, final Class<?>... types)115     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
116         return MH.findStatic(MethodHandles.lookup(), PrototypeObject.class, name, MH.type(rtype, types));
117     }
118 }
119