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