MapConstructor.cpp
1 /* 2 * Copyright (C) 2013-2017 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 "MapConstructor.h" 28 29 #include "IteratorOperations.h" 30 #include "JSCInlines.h" 31 #include "JSMap.h" 32 #include "MapPrototype.h" 33 34 namespace JSC { 35 36 const ClassInfo MapConstructor::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(MapConstructor) }; 37 38 void MapConstructor::finishCreation(VM& vm, MapPrototype* mapPrototype, GetterSetter* speciesSymbol) 39 { 40 Base::finishCreation(vm, 0, "Map"_s, PropertyAdditionMode::WithoutStructureTransition); 41 putDirectWithoutTransition(vm, vm.propertyNames->prototype, mapPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); 42 putDirectNonIndexAccessorWithoutTransition(vm, vm.propertyNames->speciesSymbol, speciesSymbol, PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum); 43 } 44 45 static JSC_DECLARE_HOST_FUNCTION(callMap); 46 static JSC_DECLARE_HOST_FUNCTION(constructMap); 47 48 MapConstructor::MapConstructor(VM& vm, Structure* structure) 49 : Base(vm, structure, callMap, constructMap) 50 { 51 } 52 53 JSC_DEFINE_HOST_FUNCTION(callMap, (JSGlobalObject* globalObject, CallFrame*)) 54 { 55 VM& vm = globalObject->vm(); 56 auto scope = DECLARE_THROW_SCOPE(vm); 57 return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(globalObject, scope, "Map")); 58 } 59 60 JSC_DEFINE_HOST_FUNCTION(constructMap, (JSGlobalObject* globalObject, CallFrame* callFrame)) 61 { 62 VM& vm = globalObject->vm(); 63 auto scope = DECLARE_THROW_SCOPE(vm); 64 65 JSObject* newTarget = asObject(callFrame->newTarget()); 66 Structure* mapStructure = newTarget == callFrame->jsCallee() 67 ? globalObject->mapStructure() 68 : InternalFunction::createSubclassStructure(globalObject, newTarget, getFunctionRealm(vm, newTarget)->mapStructure()); 69 RETURN_IF_EXCEPTION(scope, { }); 70 71 JSValue iterable = callFrame->argument(0); 72 if (iterable.isUndefinedOrNull()) 73 RELEASE_AND_RETURN(scope, JSValue::encode(JSMap::create(globalObject, vm, mapStructure))); 74 75 if (auto* iterableMap = jsDynamicCast<JSMap*>(vm, iterable)) { 76 if (iterableMap->canCloneFastAndNonObservable(mapStructure)) 77 RELEASE_AND_RETURN(scope, JSValue::encode(iterableMap->clone(globalObject, vm, mapStructure))); 78 } 79 80 JSMap* map = JSMap::create(globalObject, vm, mapStructure); 81 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 82 83 JSValue adderFunction = map->JSObject::get(globalObject, vm.propertyNames->set); 84 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 85 86 auto adderFunctionCallData = getCallData(vm, adderFunction); 87 if (adderFunctionCallData.type == CallData::Type::None) 88 return JSValue::encode(throwTypeError(globalObject, scope)); 89 90 scope.release(); 91 forEachInIterable(globalObject, iterable, [&](VM& vm, JSGlobalObject* globalObject, JSValue nextItem) { 92 auto scope = DECLARE_THROW_SCOPE(vm); 93 if (!nextItem.isObject()) { 94 throwTypeError(globalObject, scope); 95 return; 96 } 97 98 JSValue key = nextItem.get(globalObject, static_cast<unsigned>(0)); 99 RETURN_IF_EXCEPTION(scope, void()); 100 101 JSValue value = nextItem.get(globalObject, static_cast<unsigned>(1)); 102 RETURN_IF_EXCEPTION(scope, void()); 103 104 MarkedArgumentBuffer arguments; 105 arguments.append(key); 106 arguments.append(value); 107 ASSERT(!arguments.hasOverflowed()); 108 scope.release(); 109 call(globalObject, adderFunction, adderFunctionCallData, map, arguments); 110 }); 111 112 return JSValue::encode(map); 113 } 114 115 JSC_DEFINE_HOST_FUNCTION(mapPrivateFuncMapBucketHead, (JSGlobalObject* globalObject, CallFrame* callFrame)) 116 { 117 ASSERT_UNUSED(globalObject, jsDynamicCast<JSMap*>(globalObject->vm(), callFrame->argument(0))); 118 JSMap* map = jsCast<JSMap*>(callFrame->uncheckedArgument(0)); 119 auto* head = map->head(); 120 ASSERT(head); 121 return JSValue::encode(head); 122 } 123 124 JSC_DEFINE_HOST_FUNCTION(mapPrivateFuncMapBucketNext, (JSGlobalObject* globalObject, CallFrame* callFrame)) 125 { 126 ASSERT(jsDynamicCast<JSMap::BucketType*>(globalObject->vm(), callFrame->argument(0))); 127 auto* bucket = jsCast<JSMap::BucketType*>(callFrame->uncheckedArgument(0)); 128 ASSERT(bucket); 129 bucket = bucket->next(); 130 while (bucket) { 131 if (!bucket->deleted()) 132 return JSValue::encode(bucket); 133 bucket = bucket->next(); 134 } 135 return JSValue::encode(globalObject->vm().sentinelMapBucket()); 136 } 137 138 JSC_DEFINE_HOST_FUNCTION(mapPrivateFuncMapBucketKey, (JSGlobalObject* globalObject, CallFrame* callFrame)) 139 { 140 ASSERT_UNUSED(globalObject, jsDynamicCast<JSMap::BucketType*>(globalObject->vm(), callFrame->argument(0))); 141 auto* bucket = jsCast<JSMap::BucketType*>(callFrame->uncheckedArgument(0)); 142 ASSERT(bucket); 143 return JSValue::encode(bucket->key()); 144 } 145 146 JSC_DEFINE_HOST_FUNCTION(mapPrivateFuncMapBucketValue, (JSGlobalObject* globalObject, CallFrame* callFrame)) 147 { 148 ASSERT_UNUSED(globalObject, jsDynamicCast<JSMap::BucketType*>(globalObject->vm(), callFrame->argument(0))); 149 auto* bucket = jsCast<JSMap::BucketType*>(callFrame->uncheckedArgument(0)); 150 ASSERT(bucket); 151 return JSValue::encode(bucket->value()); 152 } 153 154 }