1/* 2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/compiler/builtins/builtins_collection_stub_builder.h" 17 18#include "ecmascript/compiler/new_object_stub_builder.h" 19#include "ecmascript/linked_hash_table.h" 20#include "ecmascript/js_map.h" 21#include "ecmascript/js_set.h" 22#include "ecmascript/js_iterator.h" 23 24namespace panda::ecmascript::kungfu { 25 26template <typename CollectionType> 27void BuiltinsCollectionStubBuilder<CollectionType>::CheckCollectionObj(Label *thisCollectionObj, Label *slowPath) 28{ 29 // check target obj 30 auto jsType = std::is_same_v<CollectionType, JSSet> ? JSType::JS_SET : JSType::JS_MAP; 31 GateRef isJsCollectionObj = IsJSObjectType(thisValue_, jsType); 32 BRANCH(isJsCollectionObj, thisCollectionObj, slowPath); 33} 34 35template <typename CollectionType> 36void BuiltinsCollectionStubBuilder<CollectionType>::Clear(Variable *result, Label *exit, Label *slowPath) 37{ 38 auto env = GetEnvironment(); 39 Label thisCollectionObj(env); 40 // check target obj 41 CheckCollectionObj(&thisCollectionObj, slowPath); 42 43 Bind(&thisCollectionObj); 44 GateRef linkedTable = GetLinked(); 45 GateRef res = Circuit::NullGate(); 46 if constexpr (std::is_same_v<CollectionType, JSMap>) { 47 LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_); 48 res = linkedHashTableStubBuilder.Clear(linkedTable); 49 } else { 50 LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_); 51 res = linkedHashTableStubBuilder.Clear(linkedTable); 52 } 53 54 Label exception(env); 55 Label noException(env); 56 BRANCH(TaggedIsException(res), &exception, &noException); 57 Bind(&noException); 58 SetLinked(res); 59 Jump(exit); 60 Bind(&exception); 61 *result = res; 62 Jump(exit); 63} 64 65template void BuiltinsCollectionStubBuilder<JSMap>::Clear(Variable *result, Label *exit, Label *slowPath); 66template void BuiltinsCollectionStubBuilder<JSSet>::Clear(Variable *result, Label *exit, Label *slowPath); 67 68template <typename CollectionType> 69void BuiltinsCollectionStubBuilder<CollectionType>::CreateIterator(Variable *result, 70 Label *exit, Label *slowPath, GateRef kind) 71{ 72 auto env = GetEnvironment(); 73 Label entry(env); 74 Label thisCollectionObj(env); 75 // check target obj 76 CheckCollectionObj(&thisCollectionObj, slowPath); 77 78 Bind(&thisCollectionObj); 79 NewObjectStubBuilder newBuilder(this); 80 newBuilder.SetGlue(glue_); 81 if constexpr (std::is_same_v<CollectionType, JSSet>) { 82 newBuilder.CreateJSCollectionIterator<JSSetIterator, CollectionType>(result, exit, thisValue_, kind); 83 } else { 84 newBuilder.CreateJSCollectionIterator<JSMapIterator, CollectionType>(result, exit, thisValue_, kind); 85 } 86} 87 88template <typename CollectionType> 89void BuiltinsCollectionStubBuilder<CollectionType>::Values(Variable *result, Label *exit, Label *slowPath) 90{ 91 GateRef kind = Int32(static_cast<int32_t>(IterationKind::VALUE)); 92 CreateIterator(result, exit, slowPath, kind); 93} 94 95template void BuiltinsCollectionStubBuilder<JSMap>::Values(Variable *result, Label *exit, Label *slowPath); 96template void BuiltinsCollectionStubBuilder<JSSet>::Values(Variable *result, Label *exit, Label *slowPath); 97 98template <typename CollectionType> 99void BuiltinsCollectionStubBuilder<CollectionType>::Entries(Variable *result, Label *exit, Label *slowPath) 100{ 101 GateRef kind = Int32(static_cast<int32_t>(IterationKind::KEY_AND_VALUE)); 102 CreateIterator(result, exit, slowPath, kind); 103} 104 105template void BuiltinsCollectionStubBuilder<JSMap>::Entries(Variable *result, Label *exit, Label *slowPath); 106template void BuiltinsCollectionStubBuilder<JSSet>::Entries(Variable *result, Label *exit, Label *slowPath); 107 108template <typename CollectionType> 109void BuiltinsCollectionStubBuilder<CollectionType>::Keys(Variable *result, Label *exit, Label *slowPath) 110{ 111 GateRef kind = Int32(static_cast<int32_t>(IterationKind::KEY)); 112 CreateIterator(result, exit, slowPath, kind); 113} 114 115template void BuiltinsCollectionStubBuilder<JSMap>::Keys(Variable *result, Label *exit, Label *slowPath); 116 117template <typename CollectionType> 118void BuiltinsCollectionStubBuilder<CollectionType>::ForEach(Variable *result, Label *exit, Label *slowPath) 119{ 120 auto env = GetEnvironment(); 121 Label thisCollectionObj(env); 122 // check target obj 123 CheckCollectionObj(&thisCollectionObj, slowPath); 124 125 Bind(&thisCollectionObj); 126 GateRef callbackFnHandle = GetCallArg0(numArgs_); 127 Label callable(env); 128 // check heap obj 129 Label heapObj(env); 130 BRANCH(TaggedIsHeapObject(callbackFnHandle), &heapObj, slowPath); 131 Bind(&heapObj); 132 BRANCH(IsCallable(callbackFnHandle), &callable, slowPath); 133 Bind(&callable); 134 135 GateRef linkedTable = GetLinked(); 136 GateRef res = Circuit::NullGate(); 137 GateRef thisArg = GetCallArg1(numArgs_); 138 if constexpr (std::is_same_v<CollectionType, JSMap>) { 139 LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_); 140 res = linkedHashTableStubBuilder.ForEach(thisValue_, linkedTable, callbackFnHandle, thisArg); 141 } else { 142 LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_); 143 res = linkedHashTableStubBuilder.ForEach(thisValue_, linkedTable, callbackFnHandle, thisArg); 144 } 145 146 Label exception(env); 147 BRANCH(TaggedIsException(res), &exception, exit); 148 Bind(&exception); 149 *result = res; 150 Jump(exit); 151} 152 153template void BuiltinsCollectionStubBuilder<JSMap>::ForEach(Variable *result, Label *exit, Label *slowPath); 154template void BuiltinsCollectionStubBuilder<JSSet>::ForEach(Variable *result, Label *exit, Label *slowPath); 155 156template <typename CollectionType> 157void BuiltinsCollectionStubBuilder<CollectionType>::MapSetOrSetAdd( 158 Variable *result, Label *exit, Label *slowPath, bool isJsMapSet) 159{ 160 auto env = GetEnvironment(); 161 Label thisCollectionObj(env); 162 // check target obj 163 CheckCollectionObj(&thisCollectionObj, slowPath); 164 Bind(&thisCollectionObj); 165 GateRef key = GetCallArg0(numArgs_); 166 // check key 167 Label keyNotHole(env); 168 BRANCH(TaggedIsHole(key), slowPath, &keyNotHole); 169 Bind(&keyNotHole); 170 GateRef value = isJsMapSet ? GetCallArg1(numArgs_) : key; 171 GateRef linkedTable = GetLinked(); 172 GateRef res = Circuit::NullGate(); 173 if constexpr (std::is_same_v<CollectionType, JSMap>) { 174 LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_); 175 res = linkedHashTableStubBuilder.Insert(linkedTable, key, value); 176 } else { 177 LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_); 178 res = linkedHashTableStubBuilder.Insert(linkedTable, key, value); 179 } 180 181 SetLinked(res); 182 *result = thisValue_; 183 Jump(exit); 184} 185 186template <typename CollectionType> 187void BuiltinsCollectionStubBuilder<CollectionType>::Set(Variable *result, Label *exit, Label *slowPath) 188{ 189 MapSetOrSetAdd(result, exit, slowPath, true); 190} 191 192template void BuiltinsCollectionStubBuilder<JSMap>::Set(Variable *result, Label *exit, Label *slowPath); 193 194template <typename CollectionType> 195void BuiltinsCollectionStubBuilder<CollectionType>::Add(Variable *result, Label *exit, Label *slowPath) 196{ 197 MapSetOrSetAdd(result, exit, slowPath, false); 198} 199 200template void BuiltinsCollectionStubBuilder<JSSet>::Add(Variable *result, Label *exit, Label *slowPath); 201 202template <typename CollectionType> 203void BuiltinsCollectionStubBuilder<CollectionType>::Delete(Variable *result, Label *exit, Label *slowPath) 204{ 205 auto env = GetEnvironment(); 206 Label thisCollectionObj(env); 207 // check target obj 208 CheckCollectionObj(&thisCollectionObj, slowPath); 209 210 Bind(&thisCollectionObj); 211 GateRef key = GetCallArg0(numArgs_); 212 GateRef linkedTable = GetLinked(); 213 GateRef res = Circuit::NullGate(); 214 if constexpr (std::is_same_v<CollectionType, JSMap>) { 215 LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_); 216 res = linkedHashTableStubBuilder.Delete(linkedTable, key); 217 } else { 218 LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_); 219 res = linkedHashTableStubBuilder.Delete(linkedTable, key); 220 } 221 *result = BooleanToTaggedBooleanPtr(res); 222 Jump(exit); 223} 224 225template void BuiltinsCollectionStubBuilder<JSMap>::Delete(Variable *result, Label *exit, Label *slowPath); 226template void BuiltinsCollectionStubBuilder<JSSet>::Delete(Variable *result, Label *exit, Label *slowPath); 227 228template <typename CollectionType> 229void BuiltinsCollectionStubBuilder<CollectionType>::Has(Variable *result, Label *exit, Label *slowPath) 230{ 231 auto env = GetEnvironment(); 232 Label thisCollectionObj(env); 233 // check target obj 234 CheckCollectionObj(&thisCollectionObj, slowPath); 235 236 Bind(&thisCollectionObj); 237 GateRef key = GetCallArg0(numArgs_); 238 GateRef linkedTable = GetLinked(); 239 GateRef res = Circuit::NullGate(); 240 if constexpr (std::is_same_v<CollectionType, JSMap>) { 241 LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_); 242 res = linkedHashTableStubBuilder.Has(linkedTable, key); 243 } else { 244 LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject> linkedHashTableStubBuilder(this, glue_); 245 res = linkedHashTableStubBuilder.Has(linkedTable, key); 246 } 247 *result = BooleanToTaggedBooleanPtr(res); 248 Jump(exit); 249} 250 251template void BuiltinsCollectionStubBuilder<JSMap>::Has(Variable *result, Label *exit, Label *slowPath); 252template void BuiltinsCollectionStubBuilder<JSSet>::Has(Variable *result, Label *exit, Label *slowPath); 253 254template <typename CollectionType> 255void BuiltinsCollectionStubBuilder<CollectionType>::Get(Variable *result, Label *exit, Label *slowPath) 256{ 257 auto env = GetEnvironment(); 258 Label thisCollectionObj(env); 259 // check target obj 260 CheckCollectionObj(&thisCollectionObj, slowPath); 261 262 Bind(&thisCollectionObj); 263 GateRef key = GetCallArg0(numArgs_); 264 GateRef linkedTable = GetLinked(); 265 static_assert(std::is_same_v<CollectionType, JSMap>); 266 LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(this, glue_); 267 *result = linkedHashTableStubBuilder.Get(linkedTable, key); 268 Jump(exit); 269} 270 271template void BuiltinsCollectionStubBuilder<JSMap>::Get(Variable *result, Label *exit, Label *slowPath); 272 273} // namespace panda::ecmascript::kungfu 274