1 /*
2 * Copyright (c) 2021 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/js_arguments.h"
17
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/object_factory.h"
21 #include "ecmascript/tagged_array-inl.h"
22
23 namespace panda::ecmascript {
GetOwnProperty(JSThread * thread,const JSHandle<JSArguments> & args,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)24 bool JSArguments::GetOwnProperty(JSThread *thread, const JSHandle<JSArguments> &args,
25 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
26 {
27 // 1 ~ 3 Let desc be OrdinaryGetOwnProperty(args, P).
28 JSObject::OrdinaryGetOwnProperty(thread, JSHandle<JSObject>(args), key, desc);
29 if (desc.IsEmpty()) {
30 return true;
31 }
32
33 // 4.Let map be the value of the [[ParameterMap]] internal slot of the arguments object.
34 JSHandle<JSTaggedValue> map(thread, args->GetParameterMap());
35
36 // 5.Let isMapped be HasOwnProperty(map, P).
37 bool isMapped = JSTaggedValue::HasOwnProperty(thread, map, key);
38
39 // 6.Assert: isMapped is never an abrupt completion.
40 ASSERT(!thread->HasPendingException());
41
42 // 7.If the value of isMapped is true, then
43 // a.Set desc.[[Value]] to Get(map, P).
44 if (isMapped) {
45 auto prop = JSObject::GetProperty(thread, map, key).GetValue();
46 desc.SetValue(prop);
47 }
48
49 // 8.If IsDataDescriptor(desc) is true and P is "caller" and desc.[[Value]] is a strict mode Function object,
50 // throw a TypeError exception.
51 JSHandle<EcmaString> caller = thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("caller");
52 if (desc.IsDataDescriptor() && JSTaggedValue::SameValue(key.GetTaggedValue(), caller.GetTaggedValue()) &&
53 desc.GetValue()->IsJSFunction()) {
54 THROW_TYPE_ERROR_AND_RETURN(thread, "Arguments GetOwnProperty: type error", false);
55 }
56 // 9.Return desc.
57 return true;
58 }
59
DefineOwnProperty(JSThread * thread,const JSHandle<JSArguments> & args,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)60 bool JSArguments::DefineOwnProperty(JSThread *thread, const JSHandle<JSArguments> &args,
61 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
62 {
63 // 1 ~ 2 Let args be the arguments object and get map.
64 JSHandle<JSTaggedValue> map(thread, args->GetParameterMap());
65
66 // 3.Let isMapped be HasOwnProperty(map, P).
67 bool isMapped = JSTaggedValue::HasOwnProperty(thread, map, key);
68
69 // 4.Let allowed be OrdinaryDefineOwnProperty(args, P, Desc).
70 bool allowed = JSObject::OrdinaryDefineOwnProperty(thread, JSHandle<JSObject>(args), key, desc);
71
72 // 5.ReturnIfAbrupt(allowed).
73 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, allowed);
74
75 // 6.If allowed is false, return false.
76 if (!allowed) {
77 return false;
78 }
79
80 // 7.If the value of isMapped is true, then
81 // a.If IsAccessorDescriptor(Desc) is true, then
82 // i.Call map.[[Delete]](P).
83 // b.Else
84 // i.If Desc.[[Value]] is present, then
85 // 1.Let setStatus be Set(map, P, Desc.[[Value]], false).
86 // 2.Assert: setStatus is true because formal parameters mapped by argument objects are always writable.
87 // ii.If Desc.[[Writable]] is present and its value is false, then
88 // 1.Call map.[[Delete]](P).
89 if (isMapped) {
90 if (desc.IsAccessorDescriptor()) {
91 JSTaggedValue::DeleteProperty(thread, map, key);
92 } else {
93 if (desc.HasValue()) {
94 [[maybe_unused]] bool setStatus = JSTaggedValue::SetProperty(thread, map, key, desc.GetValue(), false);
95 ASSERT(setStatus == true);
96 }
97 if (desc.HasWritable() && !desc.IsWritable()) {
98 JSTaggedValue::DeleteProperty(thread, map, key);
99 }
100 }
101 }
102
103 // 8.Return true.
104 return true;
105 }
106
GetProperty(JSThread * thread,const JSHandle<JSArguments> & args,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)107 OperationResult JSArguments::GetProperty(JSThread *thread, const JSHandle<JSArguments> &args,
108 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
109 {
110 // 1 ~ 2 Let args be the arguments object and get map.
111 JSHandle<JSTaggedValue> map(thread, args->GetParameterMap());
112
113 // 3.Let isMapped be HasOwnProperty(map, P).
114 bool isMapped = JSTaggedValue::HasOwnProperty(thread, map, key);
115
116 // 4.Assert: isMapped is not an abrupt completion.
117 ASSERT(!thread->HasPendingException());
118
119 // 5.If the value of isMapped is false, then
120 // a.Return the result of calling the default ordinary object [[Get]] internal method (9.1.8)
121 // on args passing P and Receiver as the arguments.
122 if (!isMapped) {
123 return JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(args), key, receiver);
124 }
125
126 // 6.Else map contains a formal parameter mapping for P,
127 // a.Return Get(map, P).
128 return JSTaggedValue::GetProperty(thread, map, key);
129 }
130
SetProperty(JSThread * thread,const JSHandle<JSArguments> & args,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver)131 bool JSArguments::SetProperty(JSThread *thread, const JSHandle<JSArguments> &args, const JSHandle<JSTaggedValue> &key,
132 const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &receiver)
133 {
134 // 1.Let args be the arguments object.
135 JSHandle<JSTaggedValue> map(thread, args->GetParameterMap());
136
137 // 2.If SameValue(args, Receiver) is false, then
138 // a.Let isMapped be false.
139 bool isMapped = false;
140 if (JSTaggedValue::SameValue(args.GetTaggedValue(), receiver.GetTaggedValue())) {
141 // 3.Else,
142 // a.Let map be the value of the [[ParameterMap]] internal slot of the arguments object.
143 // b.Let isMapped be HasOwnProperty(map, P).
144 // c.Assert: isMapped is not an abrupt completion.
145 isMapped = JSTaggedValue::HasOwnProperty(thread, map, key);
146 ASSERT(!thread->HasPendingException());
147 }
148
149 // 4.If isMapped is true, then
150 // a.Let setStatus be Set(map, P, V, false).
151 // b.Assert: setStatus is true because formal parameters mapped by argument objects are always writable.
152 if (isMapped) {
153 [[maybe_unused]] bool setStatus = JSTaggedValue::SetProperty(thread, map, key, value);
154 ASSERT(setStatus == true);
155 }
156
157 // 5.Return the result of calling the default ordinary object [[Set]] internal method (9.1.9)
158 // on args passing P, V and Receiver as the arguments.
159 return JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(args), key, value, receiver);
160 }
161
DeleteProperty(JSThread * thread,const JSHandle<JSArguments> & args,const JSHandle<JSTaggedValue> & key)162 bool JSArguments::DeleteProperty(JSThread *thread, const JSHandle<JSArguments> &args,
163 const JSHandle<JSTaggedValue> &key)
164 {
165 // 1.Let map be the value of the [[ParameterMap]] internal slot of the arguments object.
166 JSHandle<JSTaggedValue> map(thread, args->GetParameterMap());
167
168 // 2.Let isMapped be HasOwnProperty(map, P).
169 bool isMapped = JSTaggedValue::HasOwnProperty(thread, map, key);
170
171 // 3.Assert: isMapped is not an abrupt completion.
172 ASSERT(!thread->HasPendingException());
173
174 // 4.Let result be the result of calling the default [[Delete]] internal method for ordinary objects (9.1.10)
175 // on the arguments object passing P as the argument.
176 bool result = JSTaggedValue::DeleteProperty(thread, JSHandle<JSTaggedValue>(args), key);
177
178 // 5.ReturnIfAbrupt(result).
179 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, result);
180
181 // 6.If result is true and the value of isMapped is true, then
182 // a.Call map.[[Delete]](P).
183 if (result && isMapped) {
184 JSTaggedValue::DeleteProperty(thread, map, key);
185 }
186
187 // 7.Return result.
188 return result;
189 }
190 } // namespace panda::ecmascript
191