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/builtins/builtins_object.h"
17 #include "ecmascript/ecma_macros.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/internal_call_params.h"
20 #include "ecmascript/interpreter/fast_runtime_stub-inl.h"
21 #include "ecmascript/js_array.h"
22 #include "ecmascript/js_function.h"
23 #include "ecmascript/js_handle.h"
24 #include "ecmascript/js_primitive_ref.h"
25 #include "ecmascript/js_realm.h"
26 #include "ecmascript/object_factory.h"
27
28 namespace panda::ecmascript::builtins {
29 // 19.1.1.1 Object ( [ value ] )
ObjectConstructor(EcmaRuntimeCallInfo * argv)30 JSTaggedValue BuiltinsObject::ObjectConstructor(EcmaRuntimeCallInfo *argv)
31 {
32 ASSERT(argv);
33 BUILTINS_API_TRACE(argv->GetThread(), Object, Constructor);
34 JSThread *thread = argv->GetThread();
35 [[maybe_unused]] EcmaHandleScope handleScope(thread);
36 auto ecmaVm = thread->GetEcmaVM();
37 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
38
39 // 1.If NewTarget is neither undefined nor the active function, then
40 // a.Return OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
41 JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
42 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
43 if (!newTarget->IsUndefined() && !(newTarget.GetTaggedValue() == constructor.GetTaggedValue())) {
44 JSHandle<JSObject> obj =
45 ecmaVm->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
46 return obj.GetTaggedValue();
47 }
48
49 // 2.If value is null, undefined or not supplied, return ObjectCreate(%ObjectPrototype%).
50 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
51 if (value->IsNull() || value->IsUndefined()) {
52 JSHandle<JSObject> obj = ecmaVm->GetFactory()->OrdinaryNewJSObjectCreate(env->GetObjectFunctionPrototype());
53 return obj.GetTaggedValue();
54 }
55
56 // 3.Return ToObject(value).
57 return JSTaggedValue::ToObject(thread, value).GetTaggedValue();
58 }
59
60 // 19.1.2.1 Object.assign ( target, ...sources )
Assign(EcmaRuntimeCallInfo * argv)61 JSTaggedValue BuiltinsObject::Assign(EcmaRuntimeCallInfo *argv)
62 {
63 ASSERT(argv);
64 BUILTINS_API_TRACE(argv->GetThread(), Object, Assign);
65 JSThread *thread = argv->GetThread();
66 [[maybe_unused]] EcmaHandleScope handleScope(thread);
67
68 uint32_t numArgs = argv->GetArgsNumber();
69 // 1.Let to be ToObject(target).
70 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
71 JSHandle<JSObject> toAssign = JSTaggedValue::ToObject(thread, target);
72 // 2.ReturnIfAbrupt(to).
73 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
74
75 // 3.If only one argument was passed, return to.
76 // 4.Let sources be the List of argument values starting with the second argument.
77 // 5.For each element nextSource of sources, in ascending index order
78 // a.If nextSource is undefined or null, let keys be an empty List.
79 // b.Else,
80 // i.Let from be ToObject(nextSource).
81 // ii.Let keys be from.[[OwnPropertyKeys]]().
82 // iii.ReturnIfAbrupt(keys).
83 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
84 for (uint32_t i = 1; i < numArgs; i++) {
85 JSHandle<JSTaggedValue> source = GetCallArg(argv, i);
86 if (!source->IsNull() && !source->IsUndefined()) {
87 JSHandle<JSObject> from = JSTaggedValue::ToObject(thread, source);
88 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
89
90 JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>::Cast(from));
91 // ReturnIfAbrupt(keys)
92 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
93
94 // c.Repeat for each element nextKey of keys in List order,
95 // i.Let desc be from.[[GetOwnProperty]](nextKey).
96 // ii.ReturnIfAbrupt(desc).
97 // iii.if desc is not undefined and desc.[[Enumerable]] is true, then
98 // 1.Let propValue be Get(from, nextKey).
99 // 2.ReturnIfAbrupt(propValue).
100 // 3.Let status be Set(to, nextKey, propValue, true).
101 // 4.ReturnIfAbrupt(status).
102 uint32_t keysLen = keys->GetLength();
103 for (uint32_t j = 0; j < keysLen; j++) {
104 PropertyDescriptor desc(thread);
105 key.Update(keys->Get(j));
106 bool success = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(from), key, desc);
107 // ReturnIfAbrupt(desc)
108 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
109
110 if (success && desc.IsEnumerable()) {
111 JSTaggedValue value =
112 FastRuntimeStub::FastGetPropertyByValue(thread, from.GetTaggedValue(), key.GetTaggedValue());
113 // ReturnIfAbrupt(prop_value)
114 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
115
116 FastRuntimeStub::FastSetPropertyByValue(thread, toAssign.GetTaggedValue(), key.GetTaggedValue(),
117 value);
118 // ReturnIfAbrupt(status)
119 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
120 }
121 }
122 }
123 }
124
125 // 6.Return to.
126 return toAssign.GetTaggedValue();
127 }
128
129 // Runtime Semantics
ObjectDefineProperties(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & prop)130 JSTaggedValue BuiltinsObject::ObjectDefineProperties(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
131 const JSHandle<JSTaggedValue> &prop)
132 {
133 BUILTINS_API_TRACE(thread, Object, DefineProperties);
134 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
135 // 1.If Type(O) is not Object, throw a TypeError exception.
136 if (!obj->IsECMAObject()) {
137 // throw a TypeError exception
138 THROW_TYPE_ERROR_AND_RETURN(thread, "is not an object", JSTaggedValue::Exception());
139 }
140
141 // 2.Let props be ToObject(Properties).
142 JSHandle<JSObject> props = JSTaggedValue::ToObject(thread, prop);
143
144 // 3.ReturnIfAbrupt(props).
145 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
146
147 // 4.Let keys be props.[[OwnPropertyKeys]]().
148 JSHandle<TaggedArray> handleKeys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>::Cast(props));
149
150 // 5.ReturnIfAbrupt(keys).
151 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
152
153 // 6.Let descriptors be an empty List.
154 // new an empty array and append
155 uint32_t length = handleKeys->GetLength();
156 [[maybe_unused]] JSHandle<TaggedArray> descriptors =
157 factory->NewTaggedArray(2 * length); // 2: 2 means two element list
158
159 // 7.Repeat for each element nextKey of keys in List order,
160 // a.Let propDesc be props.[[GetOwnProperty]](nextKey).
161 // b.ReturnIfAbrupt(propDesc).
162 // c.If propDesc is not undefined and propDesc.[[Enumerable]] is true, then
163 // i.Let descObj be Get( props, nextKey).
164 // ii.ReturnIfAbrupt(descObj).
165 // iii.Let desc be ToPropertyDescriptor(descObj).
166 // iv.ReturnIfAbrupt(desc).
167 // v.Append the pair (a two element List) consisting of nextKey and desc to the end of descriptors.
168 JSMutableHandle<JSTaggedValue> handleKey(thread, JSTaggedValue::Undefined());
169 for (uint32_t i = 0; i < length; i++) {
170 PropertyDescriptor propDesc(thread);
171 handleKey.Update(handleKeys->Get(i));
172
173 bool success = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(props), handleKey, propDesc);
174 // ReturnIfAbrupt(propDesc)
175 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
176
177 if (success && propDesc.IsEnumerable()) {
178 JSHandle<JSTaggedValue> descObj =
179 JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(props), handleKey).GetValue();
180 // ReturnIfAbrupt(descObj)
181 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
182
183 PropertyDescriptor desc(thread);
184 JSObject::ToPropertyDescriptor(thread, descObj, desc);
185
186 // ReturnIfAbrupt(desc)
187 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
188
189 // 8.For each pair from descriptors in list order,
190 // a.Let P be the first element of pair.
191 // b.Let desc be the second element of pair.
192 // c.Let status be DefinePropertyOrThrow(O,P, desc).
193 // d.ReturnIfAbrupt(status).
194 [[maybe_unused]] bool setSuccess = JSTaggedValue::DefinePropertyOrThrow(thread, obj, handleKey, desc);
195
196 // ReturnIfAbrupt(status)
197 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
198 }
199 }
200
201 // 9.Return O.
202 return obj.GetTaggedValue();
203 }
204
205 // 19.1.2.2 Object.create ( O [ , Properties ] )
Create(EcmaRuntimeCallInfo * argv)206 JSTaggedValue BuiltinsObject::Create(EcmaRuntimeCallInfo *argv)
207 {
208 ASSERT(argv);
209 BUILTINS_API_TRACE(argv->GetThread(), Object, Create);
210 JSThread *thread = argv->GetThread();
211 [[maybe_unused]] EcmaHandleScope handleScope(thread);
212 // 1.If Type(O) is neither Object nor Null, throw a TypeError exception.
213 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
214 if (!obj->IsECMAObject() && !obj->IsNull()) {
215 // throw a TypeError exception
216 THROW_TYPE_ERROR_AND_RETURN(thread, "Create: O is neither Object nor Null", JSTaggedValue::Exception());
217 }
218
219 JSHandle<JSTaggedValue> properties = GetCallArg(argv, 1);
220
221 // 2.Let obj be ObjectCreate(O).
222 JSHandle<JSObject> objCreate = thread->GetEcmaVM()->GetFactory()->OrdinaryNewJSObjectCreate(obj);
223
224 // 3.If the argument Properties is present and not undefined, then
225 // a.Return ObjectDefineProperties(obj, Properties).
226 if (!properties->IsUndefined()) {
227 return ObjectDefineProperties(thread, JSHandle<JSTaggedValue>::Cast(objCreate), properties);
228 }
229
230 // 4.Return obj.
231 return objCreate.GetTaggedValue();
232 }
233
234 // 19.1.2.3 Object.defineProperties ( O, Properties )
DefineProperties(EcmaRuntimeCallInfo * argv)235 JSTaggedValue BuiltinsObject::DefineProperties(EcmaRuntimeCallInfo *argv)
236 {
237 ASSERT(argv);
238 BUILTINS_API_TRACE(argv->GetThread(), Object, DefineProperties);
239 JSThread *thread = argv->GetThread();
240 [[maybe_unused]] EcmaHandleScope handleScope(thread);
241 // 1.Return ObjectDefineProperties(O, Properties).
242 return ObjectDefineProperties(thread, GetCallArg(argv, 0), GetCallArg(argv, 1));
243 }
244
245 // 19.1.2.4 Object.defineProperty ( O, P, Attributes )
DefineProperty(EcmaRuntimeCallInfo * argv)246 JSTaggedValue BuiltinsObject::DefineProperty(EcmaRuntimeCallInfo *argv)
247 {
248 ASSERT(argv);
249 BUILTINS_API_TRACE(argv->GetThread(), Object, DefineProperty);
250 JSThread *thread = argv->GetThread();
251 [[maybe_unused]] EcmaHandleScope handleScope(thread);
252
253 // 1.If Type(O) is not Object, throw a TypeError exception.
254 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
255 if (!obj->IsECMAObject()) {
256 // throw a TypeError
257 THROW_TYPE_ERROR_AND_RETURN(thread, "DefineProperty: O is not Object", JSTaggedValue::Exception());
258 }
259
260 // 2.Let key be ToPropertyKey(P).
261 JSHandle<JSTaggedValue> prop = GetCallArg(argv, 1);
262 JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, prop);
263
264 // 3.ReturnIfAbrupt(key).
265 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
266 // 4.Let desc be ToPropertyDescriptor(Attributes).
267 PropertyDescriptor desc(thread);
268 JSObject::ToPropertyDescriptor(thread, GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD), desc);
269
270 // 5.ReturnIfAbrupt(desc).
271 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
272
273 // 6.Let success be DefinePropertyOrThrow(O,key, desc).
274 [[maybe_unused]] bool success = JSTaggedValue::DefinePropertyOrThrow(thread, obj, key, desc);
275
276 // 7.ReturnIfAbrupt(success).
277 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
278 // 8.Return O.
279 return obj.GetTaggedValue();
280 }
281
282 // 19.1.2.5 Object.freeze ( O )
Freeze(EcmaRuntimeCallInfo * argv)283 JSTaggedValue BuiltinsObject::Freeze(EcmaRuntimeCallInfo *argv)
284 {
285 ASSERT(argv);
286 BUILTINS_API_TRACE(argv->GetThread(), Object, Freeze);
287
288 // 1.If Type(O) is not Object, return O.
289 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
290 if (!obj->IsECMAObject()) {
291 return obj.GetTaggedValue();
292 }
293
294 JSThread *thread = argv->GetThread();
295 [[maybe_unused]] EcmaHandleScope handleScope(thread);
296
297 // 2.Let status be SetIntegrityLevel( O, "frozen").
298 bool status = JSObject::SetIntegrityLevel(thread, JSHandle<JSObject>(obj), IntegrityLevel::FROZEN);
299
300 // 3.ReturnIfAbrupt(status).
301 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
302
303 // 4.If status is false, throw a TypeError exception.
304 if (!status) {
305 // throw a TypeError exception
306 THROW_TYPE_ERROR_AND_RETURN(thread, "Freeze: freeze failed", JSTaggedValue::Exception());
307 }
308
309 // 5.Return O.
310 return obj.GetTaggedValue();
311 }
312
313 // 19.1.2.6 Object.getOwnPropertyDescriptor ( O, P )
GetOwnPropertyDesciptor(EcmaRuntimeCallInfo * argv)314 JSTaggedValue BuiltinsObject::GetOwnPropertyDesciptor(EcmaRuntimeCallInfo *argv)
315 {
316 ASSERT(argv);
317 BUILTINS_API_TRACE(argv->GetThread(), Object, GetOwnPropertyDesciptor);
318 JSThread *thread = argv->GetThread();
319 [[maybe_unused]] EcmaHandleScope handleScope(thread);
320
321 // 1.Let obj be ToObject(O).
322 JSHandle<JSTaggedValue> func = GetCallArg(argv, 0);
323 JSHandle<JSObject> handle = JSTaggedValue::ToObject(thread, func);
324
325 // 2.ReturnIfAbrupt(obj).
326 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
327
328 // 3.Let key be ToPropertyKey(P).
329 JSHandle<JSTaggedValue> prop = GetCallArg(argv, 1);
330 JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, prop);
331
332 // 4.ReturnIfAbrupt(key).
333 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
334
335 // 5.Let desc be obj.[[GetOwnProperty]](key).
336 PropertyDescriptor desc(thread);
337 JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(handle), key, desc);
338
339 // 6.ReturnIfAbrupt(desc).
340 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
341
342 // 7.Return FromPropertyDescriptor(desc).
343 JSHandle<JSTaggedValue> res = JSObject::FromPropertyDescriptor(thread, desc);
344 return res.GetTaggedValue();
345 }
346
347 // Runtime Semantics
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & object,const KeyType & type)348 JSTaggedValue BuiltinsObject::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &object,
349 const KeyType &type)
350 {
351 BUILTINS_API_TRACE(thread, Object, GetOwnPropertyKeys);
352 // 1.Let obj be ToObject(O).
353 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
354 JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, object);
355
356 // 2.ReturnIfAbrupt(obj).
357 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
358
359 // 3.Let keys be obj.[[OwnPropertyKeys]]().
360 JSHandle<TaggedArray> handleKeys = JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>::Cast(obj));
361
362 // 4.ReturnIfAbrupt(keys).
363 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
364
365 // 5.Let nameList be a new empty List.
366 // new an empty array and append
367 uint32_t length = handleKeys->GetLength();
368 JSHandle<TaggedArray> nameList = factory->NewTaggedArray(length);
369
370 // 6.Repeat for each element nextKey of keys in List order,
371 uint32_t copyLength = 0;
372 switch (type) {
373 case KeyType::STRING_TYPE: {
374 for (uint32_t i = 0; i < length; i++) {
375 JSTaggedValue key = handleKeys->Get(i);
376 if (key.IsString()) {
377 nameList->Set(thread, copyLength, key);
378 copyLength++;
379 }
380 }
381 break;
382 }
383 case KeyType::SYMBOL_TYPE: {
384 for (uint32_t i = 0; i < length; i++) {
385 JSTaggedValue key = handleKeys->Get(i);
386 if (key.IsSymbol()) {
387 nameList->Set(thread, copyLength, key);
388 copyLength++;
389 }
390 }
391 break;
392 }
393 default:
394 break;
395 }
396
397 // 7.Return CreateArrayFromList(nameList).
398 JSHandle<TaggedArray> resultList = factory->CopyArray(nameList, length, copyLength);
399 JSHandle<JSArray> resultArray = JSArray::CreateArrayFromList(thread, resultList);
400 return resultArray.GetTaggedValue();
401 }
402
403 // 19.1.2.7 Object.getOwnPropertyNames ( O )
GetOwnPropertyNames(EcmaRuntimeCallInfo * argv)404 JSTaggedValue BuiltinsObject::GetOwnPropertyNames(EcmaRuntimeCallInfo *argv)
405 {
406 ASSERT(argv);
407 BUILTINS_API_TRACE(argv->GetThread(), Object, GetOwnPropertyNames);
408 [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
409 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
410 KeyType type = KeyType::STRING_TYPE;
411
412 // 1.Return GetOwnPropertyKeys(O, String).
413 return GetOwnPropertyKeys(argv->GetThread(), obj, type);
414 }
415
416 // 19.1.2.8 Object.getOwnPropertySymbols ( O )
GetOwnPropertySymbols(EcmaRuntimeCallInfo * argv)417 JSTaggedValue BuiltinsObject::GetOwnPropertySymbols(EcmaRuntimeCallInfo *argv)
418 {
419 ASSERT(argv);
420 BUILTINS_API_TRACE(argv->GetThread(), Object, GetOwnPropertySymbols);
421 [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
422 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
423 KeyType type = KeyType::SYMBOL_TYPE;
424
425 // 1.Return GetOwnPropertyKeys(O, Symbol).
426 return GetOwnPropertyKeys(argv->GetThread(), obj, type);
427 }
428
429 // 19.1.2.9 Object.getPrototypeOf ( O )
GetPrototypeOf(EcmaRuntimeCallInfo * argv)430 JSTaggedValue BuiltinsObject::GetPrototypeOf(EcmaRuntimeCallInfo *argv)
431 {
432 ASSERT(argv);
433 BUILTINS_API_TRACE(argv->GetThread(), Object, GetPrototypeOf);
434 JSThread *thread = argv->GetThread();
435 [[maybe_unused]] EcmaHandleScope handleScope(thread);
436
437 // 1.Let obj be ToObject(O).
438 JSHandle<JSTaggedValue> func = GetCallArg(argv, 0);
439
440 JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, func);
441
442 // 2.ReturnIfAbrupt(obj).
443 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
444
445 // 3.Return obj.[[GetPrototypeOf]]().
446 return obj->GetPrototype(thread);
447 }
448
449 // 19.1.2.10 Object.is ( value1, value2 )
Is(EcmaRuntimeCallInfo * argv)450 JSTaggedValue BuiltinsObject::Is(EcmaRuntimeCallInfo *argv)
451 {
452 ASSERT(argv);
453 BUILTINS_API_TRACE(argv->GetThread(), Object, Is);
454
455 // 1.Return SameValue(value1, value2).
456 bool result = JSTaggedValue::SameValue(GetCallArg(argv, 0), GetCallArg(argv, 1));
457 return GetTaggedBoolean(result);
458 }
459
460 // 19.1.2.11 Object.isExtensible ( O )
IsExtensible(EcmaRuntimeCallInfo * argv)461 JSTaggedValue BuiltinsObject::IsExtensible(EcmaRuntimeCallInfo *argv)
462 {
463 ASSERT(argv);
464 JSThread *thread = argv->GetThread();
465 // 1.If Type(O) is not Object, return false.
466 JSTaggedValue obj = GetCallArg(argv, 0).GetTaggedValue();
467 if (!obj.IsObject()) {
468 return GetTaggedBoolean(false);
469 }
470 [[maybe_unused]] EcmaHandleScope handleScope(thread);
471 // 2.Return IsExtensible(O).
472 return GetTaggedBoolean(obj.IsExtensible(thread));
473 }
474
475 // 19.1.2.12 Object.isFrozen ( O )
IsFrozen(EcmaRuntimeCallInfo * argv)476 JSTaggedValue BuiltinsObject::IsFrozen(EcmaRuntimeCallInfo *argv)
477 {
478 ASSERT(argv);
479 // 1.If Type(O) is not Object, return true.
480 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
481 if (!obj->IsECMAObject()) {
482 return GetTaggedBoolean(true);
483 }
484
485 JSThread *thread = argv->GetThread();
486 [[maybe_unused]] EcmaHandleScope handleScope(thread);
487
488 // 2.Return TestIntegrityLevel(O, "frozen").
489 bool status = JSObject::TestIntegrityLevel(thread, JSHandle<JSObject>(obj), IntegrityLevel::FROZEN);
490 return GetTaggedBoolean(status);
491 }
492
493 // 19.1.2.13 Object.isSealed ( O )
IsSealed(EcmaRuntimeCallInfo * argv)494 JSTaggedValue BuiltinsObject::IsSealed(EcmaRuntimeCallInfo *argv)
495 {
496 ASSERT(argv);
497
498 // 1.If Type(O) is not Object, return true.
499 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
500 if (!obj->IsECMAObject()) {
501 return GetTaggedBoolean(true);
502 }
503
504 JSThread *thread = argv->GetThread();
505 [[maybe_unused]] EcmaHandleScope handleScope(thread);
506
507 // 2.Return TestIntegrityLevel(O, "sealed").
508 bool status = JSObject::TestIntegrityLevel(thread, JSHandle<JSObject>(obj), IntegrityLevel::SEALED);
509 return GetTaggedBoolean(status);
510 }
511
512 // 19.1.2.14 Object.keys(O)
Keys(EcmaRuntimeCallInfo * argv)513 JSTaggedValue BuiltinsObject::Keys(EcmaRuntimeCallInfo *argv)
514 {
515 ASSERT(argv);
516 BUILTINS_API_TRACE(argv->GetThread(), Object, Keys);
517 JSThread *thread = argv->GetThread();
518 [[maybe_unused]] EcmaHandleScope handleScope(thread);
519
520 // 1. Let obj be ToObject(O).
521 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
522
523 JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, msg);
524
525 // 2. ReturnIfAbrupt(obj).
526 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
527
528 // 3. Let nameList be EnumerableOwnNames(obj).
529 JSHandle<TaggedArray> nameList = JSObject::EnumerableOwnNames(thread, obj);
530
531 // 4. ReturnIfAbrupt(nameList).
532 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
533
534 // 5. Return CreateArrayFromList(nameList).
535 JSHandle<JSArray> result = JSArray::CreateArrayFromList(thread, nameList);
536 return result.GetTaggedValue();
537 }
538
539 // 19.1.2.15 Object.preventExtensions(O)
PreventExtensions(EcmaRuntimeCallInfo * argv)540 JSTaggedValue BuiltinsObject::PreventExtensions(EcmaRuntimeCallInfo *argv)
541 {
542 ASSERT(argv);
543 BUILTINS_API_TRACE(argv->GetThread(), Object, PreventExtensions);
544 // 1. If Type(O) is not Object, return O.
545 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
546 if (!obj->IsECMAObject()) {
547 return obj.GetTaggedValue();
548 }
549 [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
550 // 2. Let status be O.[[PreventExtensions]]().
551 bool status = JSTaggedValue::PreventExtensions(argv->GetThread(), obj);
552
553 // 3. ReturnIfAbrupt(status).
554 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
555
556 // 4. If status is false, throw a TypeError exception.
557 if (!status) {
558 // throw a TypeError exception.
559 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "PreventExtensions: preventExtensions failed",
560 JSTaggedValue::Exception());
561 }
562
563 // 5. Return O.
564 return obj.GetTaggedValue();
565 }
566 // 19.1.2.16 Object.prototype
567
568 // 19.1.2.17 Object.seal(O)
Seal(EcmaRuntimeCallInfo * argv)569 JSTaggedValue BuiltinsObject::Seal(EcmaRuntimeCallInfo *argv)
570 {
571 ASSERT(argv);
572 BUILTINS_API_TRACE(argv->GetThread(), Object, Seal);
573
574 // 1. If Type(O) is not Object, return O.
575 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
576 if (!msg->IsECMAObject()) {
577 return msg.GetTaggedValue();
578 }
579
580 JSThread *thread = argv->GetThread();
581 [[maybe_unused]] EcmaHandleScope handleScope(thread);
582
583 // 2. Let status be SetIntegrityLevel(O, "sealed").
584 JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, msg);
585 bool status = JSObject::SetIntegrityLevel(thread, object, IntegrityLevel::SEALED);
586
587 // 3. ReturnIfAbrupt(status).
588 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
589
590 // 4. If status is false, throw a TypeError exception.
591 if (!status) {
592 // throw a TypeError exception.
593 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "Seal: seal failed", JSTaggedValue::Exception());
594 }
595
596 // 5. Return O.
597 return object.GetTaggedValue();
598 }
599
600 // 19.1.2.18 Object.setPrototypeOf(O, proto)
SetPrototypeOf(EcmaRuntimeCallInfo * argv)601 JSTaggedValue BuiltinsObject::SetPrototypeOf(EcmaRuntimeCallInfo *argv)
602 {
603 ASSERT(argv);
604 BUILTINS_API_TRACE(argv->GetThread(), Object, SetPrototypeOf);
605 JSThread *thread = argv->GetThread();
606 [[maybe_unused]] EcmaHandleScope handleScope(thread);
607 // 1. Let O be RequireObjectCoercible(O).
608 JSHandle<JSTaggedValue> object = JSTaggedValue::RequireObjectCoercible(thread, GetCallArg(argv, 0));
609
610 // 2. ReturnIfAbrupt(O).
611 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
612
613 // 3. If Type(proto) is neither Object nor Null, throw a TypeError exception.
614 JSHandle<JSTaggedValue> proto = GetCallArg(argv, 1);
615 if (!proto->IsNull() && !proto->IsECMAObject()) {
616 // throw a TypeError exception.
617 THROW_TYPE_ERROR_AND_RETURN(thread, "SetPrototypeOf: proto is neither Object nor Null",
618 JSTaggedValue::Exception());
619 }
620
621 // 4. If Type(O) is not Object, return O.
622 if (!object->IsECMAObject()) {
623 return object.GetTaggedValue();
624 }
625
626 // 5. Let status be O.[[SetPrototypeOf]](proto).
627 bool status = JSTaggedValue::SetPrototype(thread, object, proto);
628
629 // 6. ReturnIfAbrupt(status).
630 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
631
632 // 7. If status is false, throw a TypeError exception.
633 if (!status) {
634 // throw a TypeError exception.
635 THROW_TYPE_ERROR_AND_RETURN(thread, "SetPrototypeOf: prototype set failed", JSTaggedValue::Exception());
636 }
637
638 // 8. Return O.
639 return object.GetTaggedValue();
640 }
641
642 // 19.1.3.1 Object.prototype.constructor
643
644 // 19.1.3.2 Object.prototype.hasOwnProperty(V)
HasOwnProperty(EcmaRuntimeCallInfo * argv)645 JSTaggedValue BuiltinsObject::HasOwnProperty(EcmaRuntimeCallInfo *argv)
646 {
647 ASSERT(argv);
648 BUILTINS_API_TRACE(argv->GetThread(), Object, HasOwnProperty);
649 JSThread *thread = argv->GetThread();
650 [[maybe_unused]] EcmaHandleScope handleScope(thread);
651 // 1. Let P be ToPropertyKey(V).
652 JSHandle<JSTaggedValue> prop = GetCallArg(argv, 0);
653 JSHandle<JSTaggedValue> property = JSTaggedValue::ToPropertyKey(thread, prop);
654
655 // 2. ReturnIfAbrupt(P).
656 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
657
658 // 3. Let O be ToObject(this value).
659 JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, GetThis(argv));
660
661 // 4. ReturnIfAbrupt(O).
662 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
663
664 // 5. Return HasOwnProperty(O, P).
665 bool res = JSTaggedValue::HasOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(object), property);
666 return GetTaggedBoolean(res);
667 }
668
669 // 19.1.3.3 Object.prototype.isPrototypeOf(V)
IsPrototypeOf(EcmaRuntimeCallInfo * argv)670 JSTaggedValue BuiltinsObject::IsPrototypeOf(EcmaRuntimeCallInfo *argv)
671 {
672 ASSERT(argv);
673 BUILTINS_API_TRACE(argv->GetThread(), Object, IsPrototypeOf);
674 JSThread *thread = argv->GetThread();
675 // 1. If Type(V) is not Object, return false.
676 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
677 if (!msg->IsECMAObject()) {
678 return GetTaggedBoolean(false);
679 }
680 [[maybe_unused]] EcmaHandleScope handleScope(thread);
681 // 2. Let O be ToObject(this value).
682 JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, GetThis(argv));
683 // 3. ReturnIfAbrupt(O).
684 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
685
686 // 4. Repeat
687 // a. Let V be V.[[GetPrototypeOf]]().
688 // b. If V is null, return false
689 // c. If SameValue(O, V) is true, return true.
690 JSTaggedValue msgValue = msg.GetTaggedValue();
691 while (!msgValue.IsNull()) {
692 if (JSTaggedValue::SameValue(object.GetTaggedValue(), msgValue)) {
693 return GetTaggedBoolean(true);
694 }
695 msgValue = JSObject::Cast(msgValue)->GetPrototype(thread);
696 }
697 return GetTaggedBoolean(false);
698 }
699
700 // 19.1.3.4 Object.prototype.propertyIsEnumerable(V)
PropertyIsEnumerable(EcmaRuntimeCallInfo * argv)701 JSTaggedValue BuiltinsObject::PropertyIsEnumerable(EcmaRuntimeCallInfo *argv)
702 {
703 ASSERT(argv);
704 // 1. Let P be ToPropertyKey(V).
705 JSThread *thread = argv->GetThread();
706 [[maybe_unused]] EcmaHandleScope handleScope(thread);
707 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
708 JSHandle<JSTaggedValue> property = JSTaggedValue::ToPropertyKey(thread, msg);
709
710 // 2. ReturnIfAbrupt(P).
711 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
712
713 // 3. Let O be ToObject(this value).
714 JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, GetThis(argv));
715 // 4. ReturnIfAbrupt(O).
716 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
717
718 // 5. Let desc be O.[[GetOwnProperty]](P).
719 PropertyDescriptor desc(thread);
720 JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(object), property, desc);
721
722 // 6. ReturnIfAbrupt(desc).
723 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
724
725 // 7. If desc is undefined, return false.
726 if (desc.IsEmpty()) {
727 return GetTaggedBoolean(false);
728 }
729
730 // 8. Return the value of desc.[[Enumerable]].
731 return GetTaggedBoolean(desc.IsEnumerable());
732 }
733
734 // 19.1.3.5 Object.prototype.toLocaleString([reserved1[, reserved2]])
ToLocaleString(EcmaRuntimeCallInfo * argv)735 JSTaggedValue BuiltinsObject::ToLocaleString(EcmaRuntimeCallInfo *argv)
736 {
737 ASSERT(argv);
738 BUILTINS_API_TRACE(argv->GetThread(), Object, ToLocaleString);
739 JSThread *thread = argv->GetThread();
740 [[maybe_unused]] EcmaHandleScope handleScope(thread);
741 // 1. Let O be the this value.
742 JSHandle<JSTaggedValue> object = GetThis(argv);
743 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
744
745 // 2. Return Invoke(O, "toString").
746 JSHandle<JSTaggedValue> calleeKey = thread->GlobalConstants()->GetHandledToStringString();
747
748 JSHandle<TaggedArray> argsList = GetArgsArray(argv);
749 ecmascript::InternalCallParams *arguments = thread->GetInternalCallParams();
750 arguments->MakeArgList(*argsList);
751 return JSFunction::Invoke(thread, object, calleeKey, argsList->GetLength(), arguments->GetArgv());
752 }
753
GetBuiltinTag(JSThread * thread,const JSHandle<JSObject> & object)754 JSTaggedValue BuiltinsObject::GetBuiltinTag(JSThread *thread, const JSHandle<JSObject> &object)
755 {
756 BUILTINS_API_TRACE(thread, Object, GetBuiltinTag);
757 // 4. Let isArray be IsArray(O).
758 bool isArray = object->IsJSArray();
759 // 5. ReturnIfAbrupt(isArray).
760 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
761
762 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
763 JSHandle<EcmaString> builtinTag = factory->NewFromCanBeCompressString("Object");
764 // 6. If isArray is true, let builtinTag be "Array".
765 if (isArray) {
766 builtinTag = factory->NewFromCanBeCompressString("Array");
767 } else if (object->IsJSPrimitiveRef()) {
768 // 7. Else, if O is an exotic String object, let builtinTag be "String".
769 JSPrimitiveRef *primitiveRef = JSPrimitiveRef::Cast(*object);
770 if (primitiveRef->IsString()) {
771 builtinTag = factory->NewFromCanBeCompressString("String");
772 } else if (primitiveRef->IsBoolean()) {
773 // 11. Else, if O has a [[BooleanData]] internal slot, let builtinTag be "Boolean".
774 builtinTag = factory->NewFromCanBeCompressString("Boolean");
775 } else if (primitiveRef->IsNumber()) {
776 // 12. Else, if O has a [[NumberData]] internal slot, let builtinTag be "Number".
777 builtinTag = factory->NewFromCanBeCompressString("Number");
778 }
779 } else if (object->IsArguments()) {
780 builtinTag = factory->NewFromCanBeCompressString("Arguments");
781 } else if (object->IsCallable()) {
782 builtinTag = factory->NewFromCanBeCompressString("Function");
783 } else if (object->IsJSError()) {
784 builtinTag = factory->NewFromCanBeCompressString("Error");
785 } else if (object->IsDate()) {
786 builtinTag = factory->NewFromCanBeCompressString("Date");
787 } else if (object->IsJSRegExp()) {
788 builtinTag = factory->NewFromCanBeCompressString("RegExp");
789 }
790 // 15. Else, let builtinTag be "Object".
791 return builtinTag.GetTaggedValue();
792 }
793
794 // 19.1.3.6 Object.prototype.toString()
ToString(EcmaRuntimeCallInfo * argv)795 JSTaggedValue BuiltinsObject::ToString(EcmaRuntimeCallInfo *argv)
796 {
797 ASSERT(argv);
798 BUILTINS_API_TRACE(argv->GetThread(), Object, ToString);
799 JSThread *thread = argv->GetThread();
800 [[maybe_unused]] EcmaHandleScope handleScope(thread);
801 // 1. If the this value is undefined, return "[object Undefined]".
802
803 JSHandle<JSTaggedValue> msg = GetThis(argv);
804 if (msg->IsUndefined()) {
805 return GetTaggedString(thread, "[object Undefined]");
806 }
807 // 2. If the this value is null, return "[object Null]".
808 if (msg->IsNull()) {
809 return GetTaggedString(thread, "[object Null]");
810 }
811
812 // 3. Let O be ToObject(this value).
813 JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, GetThis(argv));
814 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
815 JSHandle<JSTaggedValue> builtinTag(thread, GetBuiltinTag(thread, object));
816
817 // 16. Let tag be Get (O, @@toStringTag).
818 auto ecmaVm = thread->GetEcmaVM();
819 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
820 auto factory = ecmaVm->GetFactory();
821
822 JSHandle<JSTaggedValue> tag = JSTaggedValue::GetProperty(thread, msg, env->GetToStringTagSymbol()).GetValue();
823
824 // 17. ReturnIfAbrupt(tag).
825 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
826
827 // 18. If Type(tag) is not String, let tag be builtinTag.
828 if (!tag->IsString()) {
829 tag = builtinTag;
830 }
831
832 // 19. Return the String that is the result of concatenating "[object ", tag, and "]".
833 JSHandle<EcmaString> leftString(factory->NewFromCanBeCompressString("[object "));
834 JSHandle<EcmaString> rightString(factory->NewFromCanBeCompressString("]"));
835
836 JSHandle<EcmaString> newLeftStringHandle =
837 factory->ConcatFromString(leftString, JSTaggedValue::ToString(thread, tag));
838 auto result = factory->ConcatFromString(newLeftStringHandle, rightString);
839 return result.GetTaggedValue();
840 }
841
842 // 19.1.3.7 Object.prototype.valueOf()
ValueOf(EcmaRuntimeCallInfo * argv)843 JSTaggedValue BuiltinsObject::ValueOf(EcmaRuntimeCallInfo *argv)
844 {
845 ASSERT(argv);
846 BUILTINS_API_TRACE(argv->GetThread(), Object, ValueOf);
847 JSThread *thread = argv->GetThread();
848 [[maybe_unused]] EcmaHandleScope handleScope(thread);
849
850 // 1. Return ToObject(this value).
851 JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, GetThis(argv));
852 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
853 return object.GetTaggedValue();
854 }
855 // B.2.2.1 Object.prototype.__proto__
ProtoGetter(EcmaRuntimeCallInfo * argv)856 JSTaggedValue BuiltinsObject::ProtoGetter(EcmaRuntimeCallInfo *argv)
857 {
858 ASSERT(argv);
859 BUILTINS_API_TRACE(argv->GetThread(), Object, ProtoGetter);
860 JSThread *thread = argv->GetThread();
861 [[maybe_unused]] EcmaHandleScope handleScope(thread);
862
863 // 1.Let obj be ToObject(this value).
864 JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, GetThis(argv));
865
866 // 2.ReturnIfAbrupt(obj).
867 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
868
869 // 3.Return obj.[[GetPrototypeOf]]().
870 return obj->GetPrototype(thread);
871 }
872
ProtoSetter(EcmaRuntimeCallInfo * argv)873 JSTaggedValue BuiltinsObject::ProtoSetter(EcmaRuntimeCallInfo *argv)
874 {
875 ASSERT(argv);
876 BUILTINS_API_TRACE(argv->GetThread(), Object, ProtoSetter);
877 JSThread *thread = argv->GetThread();
878 [[maybe_unused]] EcmaHandleScope handleScope(thread);
879 // 1. Let O be RequireObjectCoercible(this value).
880 JSHandle<JSTaggedValue> obj = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv));
881
882 // 2. ReturnIfAbrupt(O).
883 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
884
885 // 3. If Type(proto) is neither Object nor Null, return undefined..
886 JSHandle<JSTaggedValue> proto = GetCallArg(argv, 0);
887 if (!proto->IsNull() && !proto->IsECMAObject()) {
888 return JSTaggedValue::Undefined();
889 }
890
891 // 4. If Type(O) is not Object, return undefined.
892 if (!obj->IsECMAObject()) {
893 return JSTaggedValue::Undefined();
894 }
895
896 // 5. Let status be O.[[SetPrototypeOf]](proto).
897 bool status = JSTaggedValue::SetPrototype(thread, obj, proto);
898
899 // 6. ReturnIfAbrupt(status).
900 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
901
902 // 7. If status is false, throw a TypeError exception.
903 if (!status) {
904 // throw a TypeError exception.
905 THROW_TYPE_ERROR_AND_RETURN(thread, "ProtoSetter: proto set failed", JSTaggedValue::Exception());
906 }
907
908 // 8. Return O.
909 return JSTaggedValue::Undefined();
910 }
911
CreateRealm(EcmaRuntimeCallInfo * argv)912 JSTaggedValue BuiltinsObject::CreateRealm(EcmaRuntimeCallInfo *argv)
913 {
914 ASSERT(argv);
915 JSThread *thread = argv->GetThread();
916 [[maybe_unused]] EcmaHandleScope handleScope(thread);
917 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
918 JSHandle<JSRealm> realm = factory->NewJSRealm();
919 return realm.GetTaggedValue();
920 }
921
Entries(EcmaRuntimeCallInfo * argv)922 JSTaggedValue BuiltinsObject::Entries(EcmaRuntimeCallInfo *argv)
923 {
924 ASSERT(argv);
925 BUILTINS_API_TRACE(argv->GetThread(), Object, ToString);
926 JSThread *thread = argv->GetThread();
927 [[maybe_unused]] EcmaHandleScope handleScope(thread);
928
929 // 1. Let obj be ? ToObject(O).
930 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
931 JSHandle<JSObject> object = JSTaggedValue::ToObject(thread, obj);
932 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
933 // 2. Let nameList be ? EnumerableOwnPropertyNames(obj, key+value).
934 JSHandle<TaggedArray> nameList = JSObject::EnumerableOwnPropertyNames(thread, object, PropertyKind::KEY_VALUE);
935 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
936 // 3. Return CreateArrayFromList(nameList).
937 return JSArray::CreateArrayFromList(thread, nameList).GetTaggedValue();
938 }
939 } // namespace panda::ecmascript::builtins
940