NativeSymbol.java revision 1626:d99fa86747ee
1/*
2 * Copyright (c) 2015, 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.objects;
27
28import static jdk.nashorn.internal.lookup.Lookup.MH;
29import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30
31import java.lang.invoke.MethodHandle;
32import java.lang.invoke.MethodHandles;
33import java.lang.invoke.MethodType;
34import jdk.dynalink.linker.GuardedInvocation;
35import jdk.dynalink.linker.LinkRequest;
36import jdk.nashorn.internal.WeakValueCache;
37import jdk.nashorn.internal.objects.annotations.Attribute;
38import jdk.nashorn.internal.objects.annotations.Constructor;
39import jdk.nashorn.internal.objects.annotations.Function;
40import jdk.nashorn.internal.objects.annotations.Getter;
41import jdk.nashorn.internal.objects.annotations.Property;
42import jdk.nashorn.internal.objects.annotations.ScriptClass;
43import jdk.nashorn.internal.objects.annotations.Where;
44import jdk.nashorn.internal.runtime.JSType;
45import jdk.nashorn.internal.runtime.PropertyMap;
46import jdk.nashorn.internal.runtime.ScriptObject;
47import jdk.nashorn.internal.runtime.ScriptRuntime;
48import jdk.nashorn.internal.runtime.Symbol;
49import jdk.nashorn.internal.runtime.Undefined;
50import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
51
52/**
53 * ECMAScript 6 - 19.4 Symbol Objects
54 */
55@ScriptClass("Symbol")
56public final class NativeSymbol extends ScriptObject {
57
58    private final Symbol symbol;
59
60    /** Method handle to create an object wrapper for a primitive symbol. */
61    static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeSymbol.class, Object.class));
62    /** Method handle to retrieve the Symbol prototype object. */
63    private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
64
65    // initialized by nasgen
66    private static PropertyMap $nasgenmap$;
67
68    /** See ES6 19.4.2.1 */
69    private static WeakValueCache<String, Symbol> globalSymbolRegistry = new WeakValueCache<>();
70
71    /**
72     * ECMA 6 19.4.2.4 Symbol.iterator
73     */
74    @Property(where = Where.CONSTRUCTOR, attributes = Attribute.NON_ENUMERABLE_CONSTANT, name = "iterator")
75    public static final Symbol iterator = new Symbol("Symbol.iterator");
76
77    NativeSymbol(final Symbol symbol) {
78        this(symbol, Global.instance());
79    }
80
81    NativeSymbol(final Symbol symbol, final Global global) {
82        this(symbol, global.getSymbolPrototype(), $nasgenmap$);
83    }
84
85    private NativeSymbol(final Symbol symbol, final ScriptObject prototype, final PropertyMap map) {
86        super(prototype, map);
87        this.symbol = symbol;
88    }
89
90    private static Symbol getSymbolValue(final Object self) {
91        if (self instanceof Symbol) {
92            return (Symbol) self;
93        } else if (self instanceof NativeSymbol) {
94            return ((NativeSymbol) self).symbol;
95        } else {
96            throw typeError("not.a.symbol");
97        }
98    }
99
100    /**
101     * Lookup the appropriate method for an invoke dynamic call.
102     *
103     * @param request  The link request
104     * @param receiver The receiver for the call
105     * @return Link to be invoked at call site.
106     */
107    public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
108        return PrimitiveLookup.lookupPrimitive(request, Symbol.class, new NativeSymbol((Symbol)receiver), WRAPFILTER, PROTOFILTER);
109    }
110
111    // ECMA 6 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
112    @Override
113    public Object getDefaultValue(final Class<?> typeHint) {
114        // Just return the symbol value.
115        return symbol;
116    }
117
118    /**
119     * ECMA 6 19.4.3.2 Symbol.prototype.toString ( )
120     *
121     * @param self self reference
122     * @return localized string for this Number
123     */
124    @Function(attributes = Attribute.NOT_ENUMERABLE)
125    public static String toString(final Object self) {
126        return getSymbolValue(self).toString();
127    }
128
129
130    /**
131     * ECMA 6 19.4.3.3  Symbol.prototype.valueOf ( )
132     *
133     * @param self self reference
134     * @return number value for this Number
135     */
136    @Function(attributes = Attribute.NOT_ENUMERABLE)
137    public static Object valueOf(final Object self) {
138        return getSymbolValue(self);
139    }
140
141    /**
142     * ECMA 6 19.4.1.1 Symbol ( [ description ] )
143     *
144     * @param newObj is this function invoked with the new operator
145     * @param self   self reference
146     * @param args   arguments
147     * @return new symbol value
148     */
149    @Constructor(arity = 1)
150    public static Object constructor(final boolean newObj, final Object self, final Object... args) {
151        if (newObj) {
152            throw typeError("symbol.as.constructor");
153        }
154        final String description = args.length > 0 && args[0] != Undefined.getUndefined() ?
155                JSType.toString(args[0]) : "";
156        return new Symbol(description);
157    }
158
159    /**
160     * ES6 19.4.2.1 Symbol.for ( key )
161     *
162     * @param self self reference
163     * @param arg the argument
164     * @return the symbol value
165     */
166    @Function(name = "for", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
167    public synchronized static Object _for(final Object self, final Object arg) {
168        final String name = JSType.toString(arg);
169        return globalSymbolRegistry.getOrCreate(name, Symbol::new);
170    }
171
172    /**
173     * ES6 19.4.2.5 Symbol.keyFor ( sym )
174     *
175     * @param self self reference
176     * @param arg the argument
177     * @return the symbol name
178     */
179    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
180    public synchronized static Object keyFor(final Object self, final Object arg) {
181        if (!(arg instanceof Symbol)) {
182            throw typeError("not.a.symbol", ScriptRuntime.safeToString(arg));
183        }
184        final String name = ((Symbol) arg).getName();
185        return globalSymbolRegistry.get(name) == arg ? name : Undefined.getUndefined();
186    }
187
188    @SuppressWarnings("unused")
189    private static NativeSymbol wrapFilter(final Object receiver) {
190        return new NativeSymbol((Symbol)receiver);
191    }
192
193    @SuppressWarnings("unused")
194    private static Object protoFilter(final Object object) {
195        return Global.instance().getSymbolPrototype();
196    }
197
198    private static MethodHandle findOwnMH(final String name, final MethodType type) {
199        return MH.findStatic(MethodHandles.lookup(), NativeSymbol.class, name, type);
200    }
201
202}
203