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