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_reflect.h" 17 18#include "ecmascript/interpreter/interpreter.h" 19#include "ecmascript/js_object-inl.h" 20 21namespace panda::ecmascript::builtins { 22// ecma 26.1.1 Reflect.apply (target, thisArgument, argumentsList) 23JSTaggedValue BuiltinsReflect::ReflectApply(EcmaRuntimeCallInfo *argv) 24{ 25 ASSERT(argv); 26 BUILTINS_API_TRACE(argv->GetThread(), Reflect, Apply); 27 JSThread *thread = argv->GetThread(); 28 [[maybe_unused]] EcmaHandleScope handleScope(thread); 29 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 30 JSHandle<JSTaggedValue> thisArgument = GetCallArg(argv, 1); 31 JSHandle<JSTaggedValue> argumentsList = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD); 32 return ReflectApplyInternal(thread, target, thisArgument, argumentsList); 33} 34 35JSTaggedValue BuiltinsReflect::ReflectApplyInternal(JSThread *thread, JSHandle<JSTaggedValue> target, 36 JSHandle<JSTaggedValue> thisArgument, 37 JSHandle<JSTaggedValue> argumentsList) 38{ 39 [[maybe_unused]] EcmaHandleScope handleScope(thread); 40 // 1. If IsCallable(target) is false, throw a TypeError exception. 41 if (!target->IsCallable()) { 42 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.apply target is not callable", JSTaggedValue::Exception()); 43 } 44 // 2. Let args be ? CreateListFromArrayLike(argumentsList). 45 JSHandle<JSTaggedValue> argOrAbrupt = JSObject::CreateListFromArrayLike(thread, argumentsList); 46 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 47 JSHandle<TaggedArray> args = JSHandle<TaggedArray>::Cast(argOrAbrupt); 48 49 // 3. Perform PrepareForTailCall(). 50 // 4. Return ? Call(target, thisArgument, args). 51 const uint32_t argsLength = args->GetLength(); 52 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 53 EcmaRuntimeCallInfo *info = 54 EcmaInterpreter::NewRuntimeCallInfo(thread, target, thisArgument, undefined, argsLength); 55 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 56 info->SetCallArg(argsLength, args); 57 return JSFunction::Call(info); 58} 59 60// ecma 26.1.2 Reflect.construct (target, argumentsList [ , newTarget]) 61JSTaggedValue BuiltinsReflect::ReflectConstruct(EcmaRuntimeCallInfo *argv) 62{ 63 ASSERT(argv); 64 BUILTINS_API_TRACE(argv->GetThread(), Reflect, Constructor); 65 JSThread *thread = argv->GetThread(); 66 [[maybe_unused]] EcmaHandleScope handleScope(thread); 67 // 1. If IsConstructor(target) is false, throw a TypeError exception. 68 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 69 if (!target->IsConstructor()) { 70 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.construct target is not constructor", JSTaggedValue::Exception()); 71 } 72 // 2. If newTarget is not present, set newTarget to target. 73 JSHandle<JSTaggedValue> newTarget = 74 argv->GetArgsNumber() > 2 ? GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD) : target; // 2: num args 75 // 3. Else if IsConstructor(newTarget) is false, throw a TypeError exception. 76 if (!newTarget->IsConstructor()) { 77 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.construct newTarget is present, but not constructor", 78 JSTaggedValue::Exception()); 79 } 80 // 4. Let args be ? CreateListFromArrayLike(argumentsList). 81 JSHandle<JSTaggedValue> argumentsList = GetCallArg(argv, 1); 82 JSHandle<JSTaggedValue> argOrAbrupt = JSObject::CreateListFromArrayLike(thread, argumentsList); 83 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 84 JSHandle<TaggedArray> args = JSHandle<TaggedArray>::Cast(argOrAbrupt); 85 return ReflectConstructInternal(thread, target, args, newTarget); 86} 87 88JSTaggedValue BuiltinsReflect::ReflectConstructInternal(JSThread *thread, JSHandle<JSTaggedValue> target, 89 JSHandle<TaggedArray> args, JSHandle<JSTaggedValue> newTarget) 90{ 91 [[maybe_unused]] EcmaHandleScope handleScope(thread); 92 // 5. Return ? Construct(target, args, newTarget). 93 const uint32_t argsLength = args->GetLength(); 94 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 95 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, target, undefined, newTarget, argsLength); 96 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 97 info->SetCallArg(argsLength, args); 98 return JSFunction::Construct(info); 99} 100 101// ecma 26.1.3 Reflect.defineProperty (target, propertyKey, attributes) 102JSTaggedValue BuiltinsReflect::ReflectDefineProperty(EcmaRuntimeCallInfo *argv) 103{ 104 ASSERT(argv); 105 BUILTINS_API_TRACE(argv->GetThread(), Reflect, DefineProperty); 106 JSThread *thread = argv->GetThread(); 107 [[maybe_unused]] EcmaHandleScope handleScope(thread); 108 // 1. If Type(target) is not Object, throw a TypeError exception. 109 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 110 if (!target->IsECMAObject()) { 111 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.defineProperty target is not object", JSTaggedValue::Exception()); 112 } 113 // 2. Let key be ? ToPropertyKey(propertyKey). 114 JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1)); 115 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 116 // 3. Let desc be ? ToPropertyDescriptor(attributes). 117 JSHandle<JSTaggedValue> attributes = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD); 118 PropertyDescriptor desc(thread); 119 JSObject::ToPropertyDescriptor(thread, attributes, desc); 120 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 121 // 4. Return ? target.[[DefineOwnProperty]](key, desc). 122 return GetTaggedBoolean(JSTaggedValue::DefineOwnProperty(thread, target, key, desc)); 123} 124 125// ecma 21.1.4 Reflect.deleteProperty (target, propertyKey) 126JSTaggedValue BuiltinsReflect::ReflectDeleteProperty(EcmaRuntimeCallInfo *argv) 127{ 128 ASSERT(argv); 129 BUILTINS_API_TRACE(argv->GetThread(), Reflect, DeleteProperty); 130 JSThread *thread = argv->GetThread(); 131 [[maybe_unused]] EcmaHandleScope handleScope(thread); 132 // 1. If Type(target) is not Object, throw a TypeError exception. 133 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 134 if (!target->IsECMAObject()) { 135 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.deleteProperty target is not object", JSTaggedValue::Exception()); 136 } 137 // 2. Let key be ? ToPropertyKey(propertyKey). 138 JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1)); 139 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 140 // 3. Return ? target.[[Delete]](key). 141 return GetTaggedBoolean(JSTaggedValue::DeleteProperty(thread, target, key)); 142} 143 144// ecma 26.1.5 Reflect.get (target, propertyKey [ , receiver]) 145JSTaggedValue BuiltinsReflect::ReflectGet(EcmaRuntimeCallInfo *argv) 146{ 147 ASSERT(argv); 148 BUILTINS_API_TRACE(argv->GetThread(), Reflect, Get); 149 JSThread *thread = argv->GetThread(); 150 [[maybe_unused]] EcmaHandleScope handleScope(thread); 151 // 1. If Type(target) is not Object, throw a TypeError exception. 152 JSHandle<JSTaggedValue> val = GetCallArg(argv, 0); 153 if (!val->IsECMAObject()) { 154 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.get target is not object", JSTaggedValue::Exception()); 155 } 156 // 2. Let key be ? ToPropertyKey(propertyKey). 157 JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1)); 158 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 159 // 3. If receiver is not present, then 160 // a. Set receiver to target. 161 // 4. Return ? target.[[Get]](key, receiver). 162 if (argv->GetArgsNumber() == 2) { // 2: 2 means that there are 2 args in total 163 return JSTaggedValue::GetProperty(thread, val, key).GetValue().GetTaggedValue(); 164 } 165 JSHandle<JSTaggedValue> receiver = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD); 166 return JSTaggedValue::GetProperty(thread, val, key, receiver).GetValue().GetTaggedValue(); 167} 168 169// ecma 26.1.6 Reflect.getOwnPropertyDescriptor ( target, propertyKey ) 170JSTaggedValue BuiltinsReflect::ReflectGetOwnPropertyDescriptor(EcmaRuntimeCallInfo *argv) 171{ 172 ASSERT(argv); 173 BUILTINS_API_TRACE(argv->GetThread(), Reflect, GetOwnPropertyDescriptor); 174 JSThread *thread = argv->GetThread(); 175 [[maybe_unused]] EcmaHandleScope handleScope(thread); 176 // 1. If Type(target) is not Object, throw a TypeError exception. 177 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 178 if (!target->IsECMAObject()) { 179 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.getOwnPropertyDescriptor target is not object", 180 JSTaggedValue::Exception()); 181 } 182 // 2. Let key be ? ToPropertyKey(propertyKey). 183 JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1)); 184 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 185 // 3. Let desc be ? target.[[GetOwnProperty]](key). 186 PropertyDescriptor desc(thread); 187 if (!JSTaggedValue::GetOwnProperty(thread, target, key, desc)) { 188 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 189 } 190 // 4. Return FromPropertyDescriptor(desc). 191 JSHandle<JSTaggedValue> res = JSObject::FromPropertyDescriptor(thread, desc); 192 return res.GetTaggedValue(); 193} 194 195// ecma 21.1.7 Reflect.getPrototypeOf (target) 196JSTaggedValue BuiltinsReflect::ReflectGetPrototypeOf(EcmaRuntimeCallInfo *argv) 197{ 198 ASSERT(argv); 199 BUILTINS_API_TRACE(argv->GetThread(), Reflect, GetPrototypeOf); 200 JSThread *thread = argv->GetThread(); 201 [[maybe_unused]] EcmaHandleScope handleScope(thread); 202 // 1. If Type(target) is not Object, throw a TypeError exception. 203 JSHandle<JSTaggedValue> val = GetCallArg(argv, 0); 204 if (!val->IsECMAObject()) { 205 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.getPrototypeOf target is not object", JSTaggedValue::Exception()); 206 } 207 // 2. Return ? target.[[GetPrototypeOf]](). 208 return JSTaggedValue::GetPrototype(thread, val); 209} 210 211// ecma 26.1.8 Reflect.has (target, propertyKey) 212JSTaggedValue BuiltinsReflect::ReflectHas(EcmaRuntimeCallInfo *argv) 213{ 214 ASSERT(argv); 215 BUILTINS_API_TRACE(argv->GetThread(), Reflect, Has); 216 JSThread *thread = argv->GetThread(); 217 [[maybe_unused]] EcmaHandleScope handleScope(thread); 218 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 219 JSHandle<JSTaggedValue> key = GetCallArg(argv, 1); 220 return ReflectHasInternal(thread, target, key); 221} 222 223JSTaggedValue BuiltinsReflect::ReflectHasInternal(JSThread *thread, JSHandle<JSTaggedValue> target, 224 JSHandle<JSTaggedValue> key) 225{ 226 [[maybe_unused]] EcmaHandleScope handleScope(thread); 227 // 1. If Type(target) is not Object, throw a TypeError exception. 228 if (!target->IsECMAObject()) { 229 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.has target is not object", JSTaggedValue::Exception()); 230 } 231 // 2. Let key be ? ToPropertyKey(propertyKey). 232 JSHandle<JSTaggedValue> propertyKey = JSTaggedValue::ToPropertyKey(thread, key); 233 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 234 // 3. Return ? target.[[HasProperty]](key). 235 return GetTaggedBoolean(JSTaggedValue::HasProperty(thread, target, propertyKey)); 236} 237 238// ecma 26.1.9 Reflect.isExtensible (target) 239JSTaggedValue BuiltinsReflect::ReflectIsExtensible(EcmaRuntimeCallInfo *argv) 240{ 241 ASSERT(argv); 242 JSThread *thread = argv->GetThread(); 243 [[maybe_unused]] EcmaHandleScope handleScope(thread); 244 // 1. If Type(target) is not Object, throw a TypeError exception. 245 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 246 if (!target->IsECMAObject()) { 247 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.isExtensible target is not object", JSTaggedValue::Exception()); 248 } 249 // 2. Return ? target.[[IsExtensible]](). 250 return GetTaggedBoolean(target->IsExtensible(thread)); 251} 252 253// ecma 26.1.10 Reflect.ownKeys (target) 254JSTaggedValue BuiltinsReflect::ReflectOwnKeys(EcmaRuntimeCallInfo *argv) 255{ 256 ASSERT(argv); 257 BUILTINS_API_TRACE(argv->GetThread(), Reflect, OwnKeys); 258 JSThread *thread = argv->GetThread(); 259 [[maybe_unused]] EcmaHandleScope handleScope(thread); 260 // 1. If Type(target) is not Object, throw a TypeError exception. 261 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 262 if (!target->IsECMAObject()) { 263 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.ownKeys target is not object", JSTaggedValue::Exception()); 264 } 265 // 2. Let keys be ? target.[[OwnPropertyKeys]](). 266 JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, target); 267 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 268 // 3. Return CreateArrayFromList(keys). 269 JSHandle<JSArray> result = JSArray::CreateArrayFromList(thread, keys); 270 return result.GetTaggedValue(); 271} 272 273// ecma 26.1.11 Reflect.preventExtensions (target) 274JSTaggedValue BuiltinsReflect::ReflectPreventExtensions(EcmaRuntimeCallInfo *argv) 275{ 276 ASSERT(argv); 277 BUILTINS_API_TRACE(argv->GetThread(), Reflect, PreventExtensions); 278 JSThread *thread = argv->GetThread(); 279 [[maybe_unused]] EcmaHandleScope handleScope(thread); 280 // 1. If Type(target) is not Object, throw a TypeError exception. 281 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 282 if (!target->IsECMAObject()) { 283 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.preventExtensions target is not object", 284 JSTaggedValue::Exception()); 285 } 286 // 2. Return ? target.[[PreventExtensions]](). 287 return GetTaggedBoolean(JSTaggedValue::PreventExtensions(thread, target)); 288} 289 290// ecma 26.1.12 Reflect.set (target, propertyKey, V [ , receiver]) 291JSTaggedValue BuiltinsReflect::ReflectSet(EcmaRuntimeCallInfo *argv) 292{ 293 ASSERT(argv); 294 BUILTINS_API_TRACE(argv->GetThread(), Reflect, Set); 295 JSThread *thread = argv->GetThread(); 296 [[maybe_unused]] EcmaHandleScope handleScope(thread); 297 // 1. If Type(target) is not Object, throw a TypeError exception. 298 JSHandle<JSTaggedValue> targetVal = GetCallArg(argv, 0); 299 if (!targetVal->IsECMAObject()) { 300 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.set target is not object", JSTaggedValue::Exception()); 301 } 302 // 2. Let key be ? ToPropertyKey(propertyKey). 303 JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1)); 304 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 305 JSHandle<JSTaggedValue> value = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD); 306 // 3. If receiver is not present, then 307 // a. Set receiver to target. 308 // 4. Return ? target.[[Set]](key, receiver). 309 if (argv->GetArgsNumber() <= BuiltinsBase::ArgsPosition::FOURTH) { 310 return GetTaggedBoolean(JSTaggedValue::SetProperty(thread, targetVal, key, value)); 311 } 312 JSHandle<JSTaggedValue> receiver = GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH); 313 return GetTaggedBoolean(JSTaggedValue::SetProperty(thread, targetVal, key, value, receiver)); 314} 315 316// ecma 26.1.13 Reflect.setPrototypeOf (target, proto) 317JSTaggedValue BuiltinsReflect::ReflectSetPrototypeOf(EcmaRuntimeCallInfo *argv) 318{ 319 ASSERT(argv); 320 BUILTINS_API_TRACE(argv->GetThread(), Reflect, SetPrototypeOf); 321 JSThread *thread = argv->GetThread(); 322 [[maybe_unused]] EcmaHandleScope handleScope(thread); 323 // 1. If Type(target) is not Object, throw a TypeError exception. 324 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 325 if (!target->IsECMAObject()) { 326 THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.setPrototypeOf target is not object", JSTaggedValue::Exception()); 327 } 328 // 2. If Type(proto) is not Object and proto is not null, throw a TypeError exception. 329 JSHandle<JSTaggedValue> proto = GetCallArg(argv, 1); 330 if (!proto->IsECMAObject() && !proto->IsNull()) { 331 THROW_TYPE_ERROR_AND_RETURN(thread, "SetPrototypeOf: proto is neither Object nor Null", 332 JSTaggedValue::Exception()); 333 } 334 // 3. Return ? target.[[SetPrototypeOf]](proto). 335 return GetTaggedBoolean(JSTaggedValue::SetPrototype(thread, target, proto)); 336} 337} // namespace panda::ecmascript::builtins 338