/ runtime / MapPrototype.cpp
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  }