NativeWeakMap.java revision 1626:d99fa86747ee
1/* 2 * Copyright (c) 2016, 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 java.util.Map; 29import java.util.WeakHashMap; 30import jdk.nashorn.internal.objects.annotations.Attribute; 31import jdk.nashorn.internal.objects.annotations.Constructor; 32import jdk.nashorn.internal.objects.annotations.Function; 33import jdk.nashorn.internal.objects.annotations.ScriptClass; 34import jdk.nashorn.internal.runtime.JSType; 35import jdk.nashorn.internal.runtime.PropertyMap; 36import jdk.nashorn.internal.runtime.ScriptObject; 37import jdk.nashorn.internal.runtime.ScriptRuntime; 38import jdk.nashorn.internal.runtime.Undefined; 39 40import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 41import static jdk.nashorn.internal.runtime.JSType.isPrimitive; 42 43/** 44 * This implements the ECMA6 WeakMap object. 45 */ 46@ScriptClass("WeakMap") 47public class NativeWeakMap extends ScriptObject { 48 49 private final Map<Object, Object> jmap = new WeakHashMap<>(); 50 51 // initialized by nasgen 52 private static PropertyMap $nasgenmap$; 53 54 private NativeWeakMap(final ScriptObject proto, final PropertyMap map) { 55 super(proto, map); 56 } 57 58 /** 59 * ECMA6 23.3.1 The WeakMap Constructor 60 * 61 * @param isNew whether the new operator used 62 * @param self self reference 63 * @param arg optional iterable argument 64 * @return a new WeakMap object 65 */ 66 @Constructor(arity = 0) 67 public static Object construct(final boolean isNew, final Object self, final Object arg) { 68 if (!isNew) { 69 throw typeError("constructor.requires.new", "WeakMap"); 70 } 71 final Global global = Global.instance(); 72 final NativeWeakMap weakMap = new NativeWeakMap(global.getWeakMapPrototype(), $nasgenmap$); 73 populateMap(weakMap.jmap, arg, global); 74 return weakMap; 75 } 76 77 /** 78 * ECMA6 23.3.3.5 WeakMap.prototype.set ( key , value ) 79 * 80 * @param self the self reference 81 * @param key the key 82 * @param value the value 83 * @return this WeakMap object 84 */ 85 @Function(attributes = Attribute.NOT_ENUMERABLE) 86 public static Object set(final Object self, final Object key, final Object value) { 87 final NativeWeakMap map = getMap(self); 88 map.jmap.put(checkKey(key), value); 89 return self; 90 } 91 92 /** 93 * ECMA6 23.3.3.3 WeakMap.prototype.get ( key ) 94 * 95 * @param self the self reference 96 * @param key the key 97 * @return the associated value or undefined 98 */ 99 @Function(attributes = Attribute.NOT_ENUMERABLE) 100 public static Object get(final Object self, final Object key) { 101 final NativeWeakMap map = getMap(self); 102 if (isPrimitive(key)) { 103 return Undefined.getUndefined(); 104 } 105 return map.jmap.get(key); 106 } 107 108 /** 109 * ECMA6 23.3.3.2 WeakMap.prototype.delete ( key ) 110 * 111 * @param self the self reference 112 * @param key the key to delete 113 * @return true if the key was deleted 114 */ 115 @Function(attributes = Attribute.NOT_ENUMERABLE) 116 public static boolean delete(final Object self, final Object key) { 117 final Map<Object, Object> map = getMap(self).jmap; 118 if (isPrimitive(key)) { 119 return false; 120 } 121 final boolean returnValue = map.containsKey(key); 122 map.remove(key); 123 return returnValue; 124 } 125 126 /** 127 * ECMA6 23.3.3.4 WeakMap.prototype.has ( key ) 128 * 129 * @param self the self reference 130 * @param key the key 131 * @return true if key is contained 132 */ 133 @Function(attributes = Attribute.NOT_ENUMERABLE) 134 public static boolean has(final Object self, final Object key) { 135 final NativeWeakMap map = getMap(self); 136 return !isPrimitive(key) && map.jmap.containsKey(key); 137 } 138 139 @Override 140 public String getClassName() { 141 return "WeakMap"; 142 } 143 144 /** 145 * Make sure {@code key} is not a JavaScript primitive value. 146 * 147 * @param key a key object 148 * @return the valid key 149 */ 150 static Object checkKey(final Object key) { 151 if (isPrimitive(key)) { 152 throw typeError("invalid.weak.key", ScriptRuntime.safeToString(key)); 153 } 154 return key; 155 } 156 157 static void populateMap(final Map<Object, Object> map, final Object arg, final Global global) { 158 // This method is similar to NativeMap.populateMap, but it uses a different 159 // map implementation and the checking/conversion of keys differs as well. 160 if (arg != null && arg != Undefined.getUndefined()) { 161 AbstractIterator.iterate(arg, global, value -> { 162 if (isPrimitive(value)) { 163 throw typeError(global, "not.an.object", ScriptRuntime.safeToString(value)); 164 } 165 if (value instanceof ScriptObject) { 166 final ScriptObject sobj = (ScriptObject) value; 167 map.put(checkKey(sobj.get(0)), sobj.get(1)); 168 } 169 }); 170 } 171 } 172 173 private static NativeWeakMap getMap(final Object self) { 174 if (self instanceof NativeWeakMap) { 175 return (NativeWeakMap)self; 176 } else { 177 throw typeError("not.a.weak.map", ScriptRuntime.safeToString(self)); 178 } 179 } 180 181} 182 183 184