[DFG][FTL] Support MapSet / SetAdd intrinsics
[WebKit-https.git] / Source / JavaScriptCore / runtime / MapPrototype.cpp
1 /*
2  * Copyright (C) 2013, 2016 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 "Error.h"
31 #include "ExceptionHelpers.h"
32 #include "IteratorOperations.h"
33 #include "JSCInlines.h"
34 #include "JSMap.h"
35 #include "Lookup.h"
36
37 #include "MapPrototype.lut.h"
38
39 namespace JSC {
40
41 const ClassInfo MapPrototype::s_info = { "Map", &Base::s_info, &mapPrototypeTable, nullptr, CREATE_METHOD_TABLE(MapPrototype) };
42
43 /* Source for MapPrototype.lut.h
44 @begin mapPrototypeTable
45   forEach   JSBuiltin  DontEnum|Function 0
46   values    JSBuiltin  DontEnum|Function 0
47   keys      JSBuiltin  DontEnum|Function 0
48 @end
49 */
50
51 static EncodedJSValue JSC_HOST_CALL mapProtoFuncClear(ExecState*);
52 static EncodedJSValue JSC_HOST_CALL mapProtoFuncDelete(ExecState*);
53 static EncodedJSValue JSC_HOST_CALL mapProtoFuncGet(ExecState*);
54 static EncodedJSValue JSC_HOST_CALL mapProtoFuncHas(ExecState*);
55 static EncodedJSValue JSC_HOST_CALL mapProtoFuncSet(ExecState*);
56
57 static EncodedJSValue JSC_HOST_CALL mapProtoFuncSize(ExecState*);
58     
59 void MapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
60 {
61     Base::finishCreation(vm);
62     ASSERT(inherits(vm, info()));
63     didBecomePrototype();
64
65     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, mapProtoFuncClear, static_cast<unsigned>(PropertyAttribute::DontEnum), 0);
66     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, mapProtoFuncDelete, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
67     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, mapProtoFuncGet, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSMapGetIntrinsic);
68     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, mapProtoFuncHas, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSMapHasIntrinsic);
69     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, mapProtoFuncSet, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, JSMapSetIntrinsic);
70
71     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getPrivateName(), mapProtoFuncGet, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSMapGetIntrinsic);
72     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().setPrivateName(), mapProtoFuncSet, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, JSMapSetIntrinsic);
73
74     JSFunction* entries = JSFunction::create(vm, mapPrototypeEntriesCodeGenerator(vm), globalObject);
75     putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().entriesPublicName(), entries, static_cast<unsigned>(PropertyAttribute::DontEnum));
76     putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, entries, static_cast<unsigned>(PropertyAttribute::DontEnum));
77     putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Map"), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
78
79     JSC_NATIVE_GETTER(vm.propertyNames->size, mapProtoFuncSize, PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
80 }
81
82 ALWAYS_INLINE static JSMap* getMap(CallFrame* callFrame, JSValue thisValue)
83 {
84     VM& vm = callFrame->vm();
85     auto scope = DECLARE_THROW_SCOPE(vm);
86
87     if (UNLIKELY(!thisValue.isCell())) {
88         throwVMError(callFrame, scope, createNotAnObjectError(callFrame, thisValue));
89         return nullptr;
90     }
91
92     if (LIKELY(thisValue.asCell()->type() == JSMapType))
93         return jsCast<JSMap*>(thisValue);
94     throwTypeError(callFrame, scope, ASCIILiteral("Map operation called on non-Map object"));
95     return nullptr;
96 }
97
98 EncodedJSValue JSC_HOST_CALL mapProtoFuncClear(CallFrame* callFrame)
99 {
100     JSMap* map = getMap(callFrame, callFrame->thisValue());
101     if (!map)
102         return JSValue::encode(jsUndefined());
103     map->clear(callFrame);
104     return JSValue::encode(jsUndefined());
105 }
106
107 EncodedJSValue JSC_HOST_CALL mapProtoFuncDelete(CallFrame* callFrame)
108 {
109     JSMap* map = getMap(callFrame, callFrame->thisValue());
110     if (!map)
111         return JSValue::encode(jsUndefined());
112     return JSValue::encode(jsBoolean(map->remove(callFrame, callFrame->argument(0))));
113 }
114
115 EncodedJSValue JSC_HOST_CALL mapProtoFuncGet(CallFrame* callFrame)
116 {
117     JSMap* map = getMap(callFrame, callFrame->thisValue());
118     if (!map)
119         return JSValue::encode(jsUndefined());
120     return JSValue::encode(map->get(callFrame, callFrame->argument(0)));
121 }
122
123 EncodedJSValue JSC_HOST_CALL mapProtoFuncHas(CallFrame* callFrame)
124 {
125     JSMap* map = getMap(callFrame, callFrame->thisValue());
126     if (!map)
127         return JSValue::encode(jsUndefined());
128     return JSValue::encode(jsBoolean(map->has(callFrame, callFrame->argument(0))));
129 }
130
131 EncodedJSValue JSC_HOST_CALL mapProtoFuncSet(CallFrame* callFrame)
132 {
133     JSValue thisValue = callFrame->thisValue();
134     JSMap* map = getMap(callFrame, thisValue);
135     if (!map)
136         return JSValue::encode(jsUndefined());
137     map->set(callFrame, callFrame->argument(0), callFrame->argument(1));
138     return JSValue::encode(thisValue);
139 }
140
141 EncodedJSValue JSC_HOST_CALL mapProtoFuncSize(CallFrame* callFrame)
142 {
143     JSMap* map = getMap(callFrame, callFrame->thisValue());
144     if (!map)
145         return JSValue::encode(jsUndefined());
146     return JSValue::encode(jsNumber(map->size()));
147 }
148
149 }