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"
22 namespace panda::ecmascript::builtins {
WeakMapConstructor(EcmaRuntimeCallInfo *argv)23 JSTaggedValue 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
Delete(EcmaRuntimeCallInfo *argv)70 JSTaggedValue 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
Has(EcmaRuntimeCallInfo *argv)92 JSTaggedValue 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
Get(EcmaRuntimeCallInfo *argv)113 JSTaggedValue 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
Set(EcmaRuntimeCallInfo *argv)134 JSTaggedValue 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