1/* 2 * Copyright (c) 2021-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/builtins/builtins_weak_map.h" 17 18#include "ecmascript/builtins/builtins_map.h" 19#include "ecmascript/js_tagged_value-inl.h" 20#include "ecmascript/js_weak_container.h" 21#include "ecmascript/linked_hash_table.h" 22namespace panda::ecmascript::builtins { 23JSTaggedValue BuiltinsWeakMap::WeakMapConstructor(EcmaRuntimeCallInfo *argv) 24{ 25 ASSERT(argv); 26 BUILTINS_API_TRACE(argv->GetThread(), WeakMap, Constructor); 27 JSThread *thread = argv->GetThread(); 28 [[maybe_unused]] EcmaHandleScope handleScope(thread); 29 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 30 // 1.If NewTarget is undefined, throw a TypeError exception 31 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 32 if (newTarget->IsUndefined()) { 33 // throw type error 34 THROW_TYPE_ERROR_AND_RETURN(thread, "new target can't be undefined", JSTaggedValue::Exception()); 35 } 36 // 2.Let WeakMap be OrdinaryCreateFromConstructor(NewTarget, "%WeakMapPrototype%", «[[WeakMapData]]» ). 37 JSHandle<JSTaggedValue> constructor = GetConstructor(argv); 38 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget); 39 // 3.returnIfAbrupt() 40 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 41 JSHandle<JSWeakMap> weakMap = JSHandle<JSWeakMap>::Cast(obj); 42 43 // 4.Set weakmap’s [[WeakMapData]] internal slot to a new empty List. 44 JSHandle<LinkedHashMap> linkedMap = LinkedHashMap::Create(thread); 45 weakMap->SetLinkedMap(thread, linkedMap); 46 // add data into set from iterable 47 // 5.If iterable is not present, let iterable be undefined. 48 // 6.If iterable is either undefined or null, let iter be undefined. 49 JSHandle<JSTaggedValue> iterable = GetCallArg(argv, 0); 50 // 8.If iter is undefined, return set 51 if (iterable->IsUndefined() || iterable->IsNull()) { 52 return weakMap.GetTaggedValue(); 53 } 54 if (!iterable->IsECMAObject()) { 55 THROW_TYPE_ERROR_AND_RETURN(thread, "iterable is not object", JSTaggedValue::Exception()); 56 } 57 // Let adder be Get(weakMap, "set"). 58 JSHandle<JSTaggedValue> adderKey = thread->GlobalConstants()->GetHandledSetString(); 59 JSHandle<JSTaggedValue> adder = 60 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(weakMap), adderKey).GetValue(); 61 // ReturnIfAbrupt(adder). 62 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, adder.GetTaggedValue()); 63 // If IsCallable(adder) is false, throw a TypeError exception 64 if (!adder->IsCallable()) { 65 THROW_TYPE_ERROR_AND_RETURN(thread, "adder is not callable", adder.GetTaggedValue()); 66 } 67 return BuiltinsMap::AddEntriesFromIterable(thread, obj, iterable, adder, factory); 68} 69 70JSTaggedValue BuiltinsWeakMap::Delete(EcmaRuntimeCallInfo *argv) 71{ 72 ASSERT(argv); 73 BUILTINS_API_TRACE(argv->GetThread(), WeakMap, Delete); 74 JSThread *thread = argv->GetThread(); 75 [[maybe_unused]] EcmaHandleScope handleScope(thread); 76 JSHandle<JSTaggedValue> self = GetThis(argv); 77 // 2.If Type(S) is not Object, throw a TypeError exception. 78 // 3.If S does not have a [[WeakMapData]] internal slot, throw a TypeError exception. 79 if (!self->IsJSWeakMap()) { 80 THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSWeakMap.", JSTaggedValue::Exception()); 81 } 82 83 JSHandle<JSWeakMap> weakMap(self); 84 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 85 // 5.If CanBeHeldWeakly(key) is false, return false. 86 if (!JSTaggedValue::CanBeHeldWeakly(thread, key)) { 87 return GetTaggedBoolean(false); 88 } 89 return GetTaggedBoolean(JSWeakMap::Delete(thread, weakMap, key)); 90} 91 92JSTaggedValue BuiltinsWeakMap::Has(EcmaRuntimeCallInfo *argv) 93{ 94 ASSERT(argv); 95 BUILTINS_API_TRACE(argv->GetThread(), WeakMap, Has); 96 JSThread *thread = argv->GetThread(); 97 [[maybe_unused]] EcmaHandleScope handleScope(thread); 98 JSHandle<JSTaggedValue> self(GetThis(argv)); 99 // 2.If Type(S) is not Object, throw a TypeError exception. 100 // 3.If S does not have a [[WeakMapData]] internal slot, throw a TypeError exception. 101 if (!self->IsJSWeakMap()) { 102 THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSWeakMap.", JSTaggedValue::Exception()); 103 } 104 JSWeakMap *jsWeakMap = JSWeakMap::Cast(self.GetTaggedValue().GetTaggedObject()); 105 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 106 // 5.If CanBeHeldWeakly(key) is false, return false. 107 if (!JSTaggedValue::CanBeHeldWeakly(thread, key)) { 108 return GetTaggedBoolean(false); 109 } 110 return GetTaggedBoolean(jsWeakMap->Has(thread, key.GetTaggedValue())); 111} 112 113JSTaggedValue BuiltinsWeakMap::Get(EcmaRuntimeCallInfo *argv) 114{ 115 ASSERT(argv); 116 BUILTINS_API_TRACE(argv->GetThread(), WeakMap, Get); 117 JSThread *thread = argv->GetThread(); 118 [[maybe_unused]] EcmaHandleScope handleScope(thread); 119 JSHandle<JSTaggedValue> self(GetThis(argv)); 120 // 2.If Type(S) is not Object, throw a TypeError exception. 121 // 3.If S does not have a [[WeakMapData]] internal slot, throw a TypeError exception. 122 if (!self->IsJSWeakMap()) { 123 THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSWeakMap.", JSTaggedValue::Exception()); 124 } 125 JSWeakMap *jsWeakMap = JSWeakMap::Cast(self.GetTaggedValue().GetTaggedObject()); 126 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 127 // 4.If CanBeHeldWeakly(key) is false, return undefined. 128 if (!JSTaggedValue::CanBeHeldWeakly(thread, key)) { 129 return JSTaggedValue::Undefined(); 130 } 131 return jsWeakMap->Get(thread, key.GetTaggedValue()); 132} 133 134JSTaggedValue BuiltinsWeakMap::Set(EcmaRuntimeCallInfo *argv) 135{ 136 ASSERT(argv); 137 BUILTINS_API_TRACE(argv->GetThread(), WeakMap, Set); 138 JSThread *thread = argv->GetThread(); 139 [[maybe_unused]] EcmaHandleScope handleScope(thread); 140 JSHandle<JSTaggedValue> self = GetThis(argv); 141 142 // 2.If Type(S) is not Object, throw a TypeError exception. 143 // 3.If S does not have a [[WeakMapData]] internal slot, throw a TypeError exception. 144 if (!self->IsJSWeakMap()) { 145 THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSWeakMap.", JSTaggedValue::Exception()); 146 } 147 148 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 149 // 4.If CanBeHeldWeakly(key) is false, throw a TypeError exception. 150 if (!JSTaggedValue::CanBeHeldWeakly(thread, key)) { 151 THROW_TYPE_ERROR_AND_RETURN(thread, "invalid value used as weak map key.", JSTaggedValue::Exception()); 152 } 153 154 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1); 155 156 JSHandle<JSWeakMap> map(self); 157 JSWeakMap::Set(thread, map, key, value); 158 return map.GetTaggedValue(); 159} 160} // namespace panda::ecmascript::builtins 161