MapPrototype.cpp
1 /* 2 * Copyright (C) 2013-2019 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "MapPrototype.h" 28 29 #include "BuiltinNames.h" 30 #include "JSCInlines.h" 31 #include "JSMap.h" 32 #include "JSMapIterator.h" 33 34 #include "MapPrototype.lut.h" 35 36 namespace JSC { 37 38 const ClassInfo MapPrototype::s_info = { "Map", &Base::s_info, &mapPrototypeTable, nullptr, CREATE_METHOD_TABLE(MapPrototype) }; 39 40 /* Source for MapPrototype.lut.h 41 @begin mapPrototypeTable 42 forEach JSBuiltin DontEnum|Function 0 43 @end 44 */ 45 46 static JSC_DECLARE_HOST_FUNCTION(mapProtoFuncClear); 47 static JSC_DECLARE_HOST_FUNCTION(mapProtoFuncDelete); 48 static JSC_DECLARE_HOST_FUNCTION(mapProtoFuncGet); 49 static JSC_DECLARE_HOST_FUNCTION(mapProtoFuncHas); 50 static JSC_DECLARE_HOST_FUNCTION(mapProtoFuncSet); 51 static JSC_DECLARE_HOST_FUNCTION(mapProtoFuncValues); 52 static JSC_DECLARE_HOST_FUNCTION(mapProtoFuncKeys); 53 static JSC_DECLARE_HOST_FUNCTION(mapProtoFuncEntries); 54 55 static JSC_DECLARE_HOST_FUNCTION(mapProtoFuncSize); 56 57 void MapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) 58 { 59 Base::finishCreation(vm); 60 ASSERT(inherits(vm, info())); 61 62 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, mapProtoFuncClear, static_cast<unsigned>(PropertyAttribute::DontEnum), 0); 63 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, mapProtoFuncDelete, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); 64 JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, mapProtoFuncGet, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSMapGetIntrinsic); 65 JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, mapProtoFuncHas, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSMapHasIntrinsic); 66 JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, mapProtoFuncSet, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, JSMapSetIntrinsic); 67 JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().keysPublicName(), mapProtoFuncKeys, static_cast<unsigned>(PropertyAttribute::DontEnum), 0, JSMapKeysIntrinsic); 68 JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().valuesPublicName(), mapProtoFuncValues, static_cast<unsigned>(PropertyAttribute::DontEnum), 0, JSMapValuesIntrinsic); 69 70 JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getPrivateName(), mapProtoFuncGet, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSMapGetIntrinsic); 71 JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().setPrivateName(), mapProtoFuncSet, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, JSMapSetIntrinsic); 72 73 JSFunction* entries = JSFunction::create(vm, globalObject, 0, vm.propertyNames->builtinNames().entriesPublicName().string(), mapProtoFuncEntries, JSMapEntriesIntrinsic); 74 putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().entriesPublicName(), entries, static_cast<unsigned>(PropertyAttribute::DontEnum)); 75 putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, entries, static_cast<unsigned>(PropertyAttribute::DontEnum)); 76 JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); 77 78 JSC_NATIVE_GETTER_WITHOUT_TRANSITION(vm.propertyNames->size, mapProtoFuncSize, PropertyAttribute::DontEnum | PropertyAttribute::Accessor); 79 80 globalObject->installMapPrototypeWatchpoint(this); 81 } 82 83 ALWAYS_INLINE static JSMap* getMap(JSGlobalObject* globalObject, JSValue thisValue) 84 { 85 VM& vm = globalObject->vm(); 86 auto scope = DECLARE_THROW_SCOPE(vm); 87 88 if (UNLIKELY(!thisValue.isCell())) { 89 throwVMError(globalObject, scope, createNotAnObjectError(globalObject, thisValue)); 90 return nullptr; 91 } 92 93 auto* map = jsDynamicCast<JSMap*>(vm, thisValue.asCell()); 94 if (LIKELY(map)) 95 return map; 96 throwTypeError(globalObject, scope, "Map operation called on non-Map object"_s); 97 return nullptr; 98 } 99 100 JSC_DEFINE_HOST_FUNCTION(mapProtoFuncClear, (JSGlobalObject* globalObject, CallFrame* callFrame)) 101 { 102 JSMap* map = getMap(globalObject, callFrame->thisValue()); 103 if (!map) 104 return JSValue::encode(jsUndefined()); 105 map->clear(globalObject); 106 return JSValue::encode(jsUndefined()); 107 } 108 109 JSC_DEFINE_HOST_FUNCTION(mapProtoFuncDelete, (JSGlobalObject* globalObject, CallFrame* callFrame)) 110 { 111 JSMap* map = getMap(globalObject, callFrame->thisValue()); 112 if (!map) 113 return JSValue::encode(jsUndefined()); 114 return JSValue::encode(jsBoolean(map->remove(globalObject, callFrame->argument(0)))); 115 } 116 117 JSC_DEFINE_HOST_FUNCTION(mapProtoFuncGet, (JSGlobalObject* globalObject, CallFrame* callFrame)) 118 { 119 JSMap* map = getMap(globalObject, callFrame->thisValue()); 120 if (!map) 121 return JSValue::encode(jsUndefined()); 122 return JSValue::encode(map->get(globalObject, callFrame->argument(0))); 123 } 124 125 JSC_DEFINE_HOST_FUNCTION(mapProtoFuncHas, (JSGlobalObject* globalObject, CallFrame* callFrame)) 126 { 127 JSMap* map = getMap(globalObject, callFrame->thisValue()); 128 if (!map) 129 return JSValue::encode(jsUndefined()); 130 return JSValue::encode(jsBoolean(map->has(globalObject, callFrame->argument(0)))); 131 } 132 133 JSC_DEFINE_HOST_FUNCTION(mapProtoFuncSet, (JSGlobalObject* globalObject, CallFrame* callFrame)) 134 { 135 JSValue thisValue = callFrame->thisValue(); 136 JSMap* map = getMap(globalObject, thisValue); 137 if (!map) 138 return JSValue::encode(jsUndefined()); 139 map->set(globalObject, callFrame->argument(0), callFrame->argument(1)); 140 return JSValue::encode(thisValue); 141 } 142 143 inline JSValue createMapIteratorObject(JSGlobalObject* globalObject, CallFrame* callFrame, IterationKind kind) 144 { 145 VM& vm = globalObject->vm(); 146 JSValue thisValue = callFrame->thisValue(); 147 JSMap* map = getMap(globalObject, thisValue); 148 if (!map) 149 return jsUndefined(); 150 return JSMapIterator::create(vm, globalObject->mapIteratorStructure(), map, kind); 151 } 152 153 JSC_DEFINE_HOST_FUNCTION(mapProtoFuncValues, (JSGlobalObject* globalObject, CallFrame* callFrame)) 154 { 155 return JSValue::encode(createMapIteratorObject(globalObject, callFrame, IterationKind::Values)); 156 } 157 158 JSC_DEFINE_HOST_FUNCTION(mapProtoFuncKeys, (JSGlobalObject* globalObject, CallFrame* callFrame)) 159 { 160 return JSValue::encode(createMapIteratorObject(globalObject, callFrame, IterationKind::Keys)); 161 } 162 163 JSC_DEFINE_HOST_FUNCTION(mapProtoFuncEntries, (JSGlobalObject* globalObject, CallFrame* callFrame)) 164 { 165 return JSValue::encode(createMapIteratorObject(globalObject, callFrame, IterationKind::Entries)); 166 } 167 168 JSC_DEFINE_HOST_FUNCTION(mapProtoFuncSize, (JSGlobalObject* globalObject, CallFrame* callFrame)) 169 { 170 JSMap* map = getMap(globalObject, callFrame->thisValue()); 171 if (!map) 172 return JSValue::encode(jsUndefined()); 173 return JSValue::encode(jsNumber(map->size())); 174 } 175 176 }