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 "js_function.h"
17
18 #include "ecmascript/base/error_type.h"
19 #include "ecmascript/class_info_extractor.h"
20 #include "ecmascript/ecma_macros.h"
21 #include "ecmascript/ecma_runtime_call_info.h"
22 #include "ecmascript/global_env.h"
23 #include "ecmascript/internal_call_params.h"
24 #include "ecmascript/interpreter/interpreter-inl.h"
25 #include "ecmascript/js_handle.h"
26 #include "ecmascript/js_promise.h"
27 #include "ecmascript/js_proxy.h"
28 #include "ecmascript/js_tagged_value-inl.h"
29 #include "ecmascript/mem/c_containers.h"
30 #include "ecmascript/object_factory.h"
31 #include "ecmascript/tagged_array.h"
32
33 namespace panda::ecmascript {
InitializeJSFunction(JSThread * thread,const JSHandle<JSFunction> & func,FunctionKind kind,bool strict)34 void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle<JSFunction> &func, FunctionKind kind,
35 bool strict)
36 {
37 FunctionMode thisMode;
38 if (IsArrowFunction(kind)) {
39 thisMode = FunctionMode::LEXICAL;
40 } else if (strict) {
41 thisMode = FunctionMode::STRICT;
42 } else {
43 thisMode = FunctionMode::GLOBAL;
44 }
45
46 func->SetProtoOrDynClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER);
47 func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
48 func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
49 func->SetConstantPool(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
50 func->SetProfileTypeInfo(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
51 func->SetFunctionExtraInfo(thread, JSTaggedValue::Undefined());
52 func->SetFunctionKind(kind);
53 func->SetStrict(strict);
54 func->SetThisMode(thisMode);
55 func->SetResolved(false);
56
57 auto globalConst = thread->GlobalConstants();
58 if (HasPrototype(kind)) {
59 JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionPrototypeAccessor();
60 if (kind == FunctionKind::BASE_CONSTRUCTOR || kind == FunctionKind::GENERATOR_FUNCTION) {
61 func->SetPropertyInlinedProps(thread, PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
62 accessor = globalConst->GetHandledFunctionNameAccessor();
63 func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
64 } else if (!JSFunction::IsClassConstructor(kind)) { // class ctor do nothing
65 PropertyDescriptor desc(thread, accessor, kind != FunctionKind::BUILTIN_CONSTRUCTOR, false, false);
66 [[maybe_unused]] bool success = JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(func),
67 globalConst->GetHandledPrototypeString(), desc);
68 ASSERT(success);
69 }
70 } else if (HasAccessor(kind)) {
71 JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionNameAccessor();
72 func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
73 }
74 }
75
NewJSFunctionPrototype(JSThread * thread,ObjectFactory * factory,const JSHandle<JSFunction> & func)76 JSHandle<JSObject> JSFunction::NewJSFunctionPrototype(JSThread *thread, ObjectFactory *factory,
77 const JSHandle<JSFunction> &func)
78 {
79 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
80 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
81 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
82 JSHandle<JSObject> funPro = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
83 func->SetFunctionPrototype(thread, funPro.GetTaggedValue());
84
85 // set "constructor" in prototype
86 JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
87 PropertyDescriptor descriptor(thread, JSHandle<JSTaggedValue>::Cast(func), true, false, true);
88 JSObject::DefineOwnProperty(thread, funPro, constructorKey, descriptor);
89
90 return funPro;
91 }
92
GetOrCreateInitialJSHClass(JSThread * thread,const JSHandle<JSFunction> & fun)93 JSHClass *JSFunction::GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle<JSFunction> &fun)
94 {
95 JSTaggedValue protoOrDyn(fun->GetProtoOrDynClass());
96 if (protoOrDyn.IsJSHClass()) {
97 return reinterpret_cast<JSHClass *>(protoOrDyn.GetTaggedObject());
98 }
99
100 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
101 JSHandle<JSTaggedValue> proto;
102 if (!fun->HasFunctionPrototype()) {
103 proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, factory, fun));
104 } else {
105 proto = JSHandle<JSTaggedValue>(thread, fun->GetProtoOrDynClass());
106 }
107
108 JSHandle<JSHClass> dynclass = factory->NewEcmaDynClass(JSObject::SIZE, JSType::JS_OBJECT, proto);
109 fun->SetProtoOrDynClass(thread, dynclass);
110 return *dynclass;
111 }
112
PrototypeGetter(JSThread * thread,const JSHandle<JSObject> & self)113 JSTaggedValue JSFunction::PrototypeGetter(JSThread *thread, const JSHandle<JSObject> &self)
114 {
115 JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(self);
116 if (!func->HasFunctionPrototype()) {
117 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
118 NewJSFunctionPrototype(thread, factory, func);
119 }
120 return JSFunction::Cast(*self)->GetFunctionPrototype();
121 }
122
PrototypeSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)123 bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
124 [[maybe_unused]] bool mayThrow)
125 {
126 JSHandle<JSFunction> func(self);
127 JSTaggedValue protoOrDyn = func->GetProtoOrDynClass();
128 if (protoOrDyn.IsJSHClass()) {
129 // need transtion
130 JSHandle<JSHClass> dynclass(thread, protoOrDyn);
131 JSHandle<JSHClass> newDynclass = JSHClass::TransitionProto(thread, dynclass, value);
132 if (value->IsECMAObject()) {
133 JSObject::Cast(value->GetTaggedObject())->GetJSHClass()->SetIsPrototype(true);
134 }
135 func->SetProtoOrDynClass(thread, newDynclass);
136 } else {
137 func->SetFunctionPrototype(thread, value.GetTaggedValue());
138 }
139 return true;
140 }
141
NameGetter(JSThread * thread,const JSHandle<JSObject> & self)142 JSTaggedValue JSFunction::NameGetter(JSThread *thread, const JSHandle<JSObject> &self)
143 {
144 JSMethod *target = JSHandle<JSFunction>::Cast(self)->GetCallTarget();
145 if (target->GetPandaFile() == nullptr) {
146 return JSTaggedValue::Undefined();
147 }
148 std::string funcName = target->ParseFunctionName();
149 if (funcName.empty()) {
150 return thread->GlobalConstants()->GetEmptyString();
151 }
152 if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::GETTER_FUNCTION) {
153 funcName.insert(0, "get ");
154 }
155 if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::SETTER_FUNCTION) {
156 funcName.insert(0, "set ");
157 }
158
159 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
160 return factory->NewFromStdString(funcName).GetTaggedValue();
161 }
162
OrdinaryHasInstance(JSThread * thread,const JSHandle<JSTaggedValue> & constructor,const JSHandle<JSTaggedValue> & obj)163 bool JSFunction::OrdinaryHasInstance(JSThread *thread, const JSHandle<JSTaggedValue> &constructor,
164 const JSHandle<JSTaggedValue> &obj)
165 {
166 // 1. If IsCallable(C) is false, return false.
167 if (!constructor->IsCallable()) {
168 return false;
169 }
170
171 // 2. If C has a [[BoundTargetFunction]] internal slot, then
172 // a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
173 // b. Return InstanceofOperator(O,BC) (see 12.9.4).
174 if (constructor->IsBoundFunction()) {
175 JSHandle<JSBoundFunction> boundFunction(thread, JSBoundFunction::Cast(constructor->GetTaggedObject()));
176 JSTaggedValue boundTarget = boundFunction->GetBoundTarget();
177 return JSObject::InstanceOf(thread, obj, JSHandle<JSTaggedValue>(thread, boundTarget));
178 }
179 // 3. If Type(O) is not Object, return false
180 if (!obj->IsECMAObject()) {
181 return false;
182 }
183
184 // 4. Let P be Get(C, "prototype").
185 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
186 JSHandle<JSTaggedValue> constructorPrototype =
187 JSTaggedValue::GetProperty(thread, constructor, globalConst->GetHandledPrototypeString()).GetValue();
188
189 // 5. ReturnIfAbrupt(P).
190 // no throw exception, so needn't return
191 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
192
193 // 6. If Type(P) is not Object, throw a TypeError exception.
194 if (!constructorPrototype->IsECMAObject()) {
195 THROW_TYPE_ERROR_AND_RETURN(thread, "HasInstance: is not Object", false);
196 }
197
198 // 7. Repeat
199 // a.Let O be O.[[GetPrototypeOf]]().
200 // b.ReturnIfAbrupt(O).
201 // c.If O is null, return false.
202 // d.If SameValue(P, O) is true, return true.
203 JSTaggedValue objPrototype = obj.GetTaggedValue();
204 while (!objPrototype.IsNull()) {
205 if (JSTaggedValue::SameValue(objPrototype, constructorPrototype.GetTaggedValue())) {
206 return true;
207 }
208 objPrototype = JSObject::Cast(objPrototype)->GetPrototype(thread);
209 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
210 }
211 return false;
212 }
213
MakeConstructor(JSThread * thread,const JSHandle<JSFunction> & func,const JSHandle<JSTaggedValue> & proto,bool writable)214 bool JSFunction::MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &func,
215 const JSHandle<JSTaggedValue> &proto, bool writable)
216 {
217 ASSERT_PRINT(proto->IsHeapObject() || proto->IsUndefined(), "proto must be JSObject or Undefined");
218 ASSERT_PRINT(func->IsConstructor(), "func must be Constructor type");
219 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
220 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
221 JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
222
223 ASSERT_PRINT(func->GetProtoOrDynClass().IsHole() && func->IsExtensible(),
224 "function doesn't has proto_type property and is extensible object");
225 ASSERT_PRINT(JSObject::HasProperty(thread, JSHandle<JSObject>(func), constructorKey),
226 "function must have constructor");
227
228 // proto.constructor = func
229 bool status = false;
230 if (proto->IsUndefined()) {
231 // Let prototype be ObjectCreate(%ObjectPrototype%).
232 JSHandle<JSTaggedValue> objPrototype = env->GetObjectFunctionPrototype();
233 PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
234 status = JSTaggedValue::DefinePropertyOrThrow(thread, objPrototype, constructorKey, constructorDesc);
235 } else {
236 PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
237 status = JSTaggedValue::DefinePropertyOrThrow(thread, proto, constructorKey, constructorDesc);
238 }
239
240 ASSERT_PRINT(status, "DefineProperty construct failed");
241 // func.prototype = proto
242 // Let status be DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]:
243 // prototype, [[Writable]]: writablePrototype, [[Enumerable]]: false, [[Configurable]]: false}).
244 func->SetFunctionPrototype(thread, proto.GetTaggedValue());
245
246 ASSERT_PRINT(status, "DefineProperty proto_type failed");
247 return status;
248 }
249
Call(JSThread * thread,const JSHandle<JSTaggedValue> & func,const JSHandle<JSTaggedValue> & thisArg,uint32_t argc,const JSTaggedType argv[])250 JSTaggedValue JSFunction::Call(JSThread *thread, const JSHandle<JSTaggedValue> &func,
251 const JSHandle<JSTaggedValue> &thisArg, uint32_t argc, const JSTaggedType argv[])
252 {
253 // 1. ReturnIfAbrupt(F).
254 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
255 // 2. If argumentsList was not passed, let argumentsList be a new empty List.
256 // 3. If IsCallable(F) is false, throw a TypeError exception.
257 if (!func->IsCallable()) {
258 THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
259 }
260
261 if (func->IsJSFunction()) {
262 return JSFunction::CallInternal(thread, JSHandle<JSFunction>(func), thisArg, argc, argv);
263 }
264
265 if (func->IsBoundFunction()) {
266 return JSBoundFunction::CallInternal(thread, JSHandle<JSBoundFunction>(func));
267 }
268
269 if (func->IsJSProxy()) {
270 return JSProxy::CallInternal(thread, JSHandle<JSProxy>(func), thisArg, argc, argv);
271 }
272 THROW_TYPE_ERROR_AND_RETURN(thread, "Call NonCallable", JSTaggedValue::Exception());
273 }
274
Construct(JSThread * thread,const JSHandle<JSTaggedValue> & func,uint32_t argc,const JSTaggedType argv[],const JSHandle<JSTaggedValue> & newTarget)275 JSTaggedValue JSFunction::Construct(JSThread *thread, const JSHandle<JSTaggedValue> &func, uint32_t argc,
276 const JSTaggedType argv[], const JSHandle<JSTaggedValue> &newTarget)
277 {
278 JSMutableHandle<JSTaggedValue> target(thread, newTarget.GetTaggedValue());
279 if (target->IsUndefined()) {
280 target.Update(func.GetTaggedValue());
281 }
282 if (!(func->IsConstructor() && target->IsConstructor())) {
283 THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
284 }
285 if (func->IsJSFunction()) {
286 return JSFunction::ConstructInternal(thread, JSHandle<JSFunction>(func), argc, argv, target);
287 }
288 if (func->IsBoundFunction()) {
289 return JSBoundFunction::ConstructInternal(thread, JSHandle<JSBoundFunction>(func), target);
290 }
291 if (func->IsJSProxy()) {
292 return JSProxy::ConstructInternal(thread, JSHandle<JSProxy>(func), argc, argv, target);
293 }
294 THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor NonConstructor", JSTaggedValue::Exception());
295 }
296
Invoke(JSThread * thread,const JSHandle<JSTaggedValue> & thisArg,const JSHandle<JSTaggedValue> & key,uint32_t argc,const JSTaggedType argv[])297 JSTaggedValue JSFunction::Invoke(JSThread *thread, const JSHandle<JSTaggedValue> &thisArg,
298 const JSHandle<JSTaggedValue> &key, uint32_t argc, const JSTaggedType argv[])
299 {
300 ASSERT(JSTaggedValue::IsPropertyKey(key));
301 JSHandle<JSTaggedValue> func(JSTaggedValue::GetProperty(thread, thisArg, key).GetValue());
302 return JSFunction::Call(thread, func, thisArg, argc, argv);
303 }
304
305 // [[Call]]
CallInternal(JSThread * thread,const JSHandle<JSFunction> & func,const JSHandle<JSTaggedValue> & thisArg,uint32_t argc,const JSTaggedType argv[])306 JSTaggedValue JSFunction::CallInternal(JSThread *thread, const JSHandle<JSFunction> &func,
307 const JSHandle<JSTaggedValue> &thisArg, uint32_t argc, const JSTaggedType argv[])
308 {
309 if (!func->IsBuiltinsConstructor() && func->IsClassConstructor()) {
310 THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", JSTaggedValue::Exception());
311 }
312 CallParams params;
313 params.callTarget = ECMAObject::Cast(*func);
314 params.newTarget = JSTaggedValue::VALUE_UNDEFINED;
315 params.thisArg = thisArg.GetTaggedType();
316 params.argc = argc;
317 params.argv = argv;
318 return EcmaInterpreter::Execute(thread, params);
319 }
320
321 // [[Construct]]
ConstructInternal(JSThread * thread,const JSHandle<JSFunction> & func,uint32_t argc,const JSTaggedType argv[],const JSHandle<JSTaggedValue> & newTarget)322 JSTaggedValue JSFunction::ConstructInternal(JSThread *thread, const JSHandle<JSFunction> &func, uint32_t argc,
323 const JSTaggedType argv[], const JSHandle<JSTaggedValue> &newTarget)
324 {
325 ASSERT(newTarget->IsECMAObject());
326 if (!func->IsConstructor()) {
327 THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
328 }
329
330 JSHandle<JSTaggedValue> obj(thread, JSTaggedValue::Undefined());
331 if (!func->IsBuiltinsConstructor() && func->IsBase()) {
332 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
333 obj = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(func, newTarget));
334 }
335
336 CallParams params;
337 params.callTarget = ECMAObject::Cast(*func);
338 params.newTarget = newTarget.GetTaggedType();
339 params.thisArg = obj.GetTaggedType();
340 params.argc = argc;
341 params.argv = argv;
342
343 JSTaggedValue resultValue = EcmaInterpreter::Execute(thread, params);
344 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
345 // 9.3.2 [[Construct]] (argumentsList, newTarget)
346 if (func->IsBuiltinsConstructor() || resultValue.IsECMAObject()) {
347 return resultValue;
348 }
349
350 if (func->IsBase()) {
351 return obj.GetTaggedValue();
352 }
353
354 // derived ctor(sub class) return the obj which created by base ctor(parent class)
355 if (func->IsDerivedConstructor()) {
356 return resultValue;
357 }
358
359 if (!resultValue.IsUndefined()) {
360 THROW_TYPE_ERROR_AND_RETURN(thread, "function is non-constructor", JSTaggedValue::Exception());
361 }
362 return obj.GetTaggedValue();
363 }
364
GetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func)365 JSHandle<JSTaggedValue> JSFunctionBase::GetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func)
366 {
367 JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
368
369 return JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(func), nameKey).GetValue();
370 }
371
SetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & prefix)372 bool JSFunctionBase::SetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func,
373 const JSHandle<JSTaggedValue> &name, const JSHandle<JSTaggedValue> &prefix)
374 {
375 ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
376 ASSERT_PRINT(name->IsStringOrSymbol(), "name must be string or symbol");
377 bool needPrefix = false;
378 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
379 if (!prefix->IsUndefined()) {
380 ASSERT_PRINT(prefix->IsString(), "prefix must be string");
381 needPrefix = true;
382 }
383 // If Type(name) is Symbol, then
384 // Let description be name’s [[Description]] value.
385 // If description is undefined, let name be the empty String.
386 // Else, let name be the concatenation of "[", description, and "]".
387 JSHandle<EcmaString> functionName;
388 if (name->IsSymbol()) {
389 JSTaggedValue description = JSHandle<JSSymbol>::Cast(name)->GetDescription();
390 JSHandle<EcmaString> descriptionHandle(thread, description);
391 if (description.IsUndefined()) {
392 functionName = factory->GetEmptyString();
393 } else {
394 JSHandle<EcmaString> leftBrackets = factory->NewFromCanBeCompressString("[");
395 JSHandle<EcmaString> rightBrackets = factory->NewFromCanBeCompressString("]");
396 functionName = factory->ConcatFromString(leftBrackets, descriptionHandle);
397 functionName = factory->ConcatFromString(functionName, rightBrackets);
398 }
399 } else {
400 functionName = JSHandle<EcmaString>::Cast(name);
401 }
402 EcmaString *newString;
403 if (needPrefix) {
404 JSHandle<EcmaString> handlePrefixString = JSTaggedValue::ToString(thread, prefix);
405 JSHandle<EcmaString> spaceString(factory->NewFromCanBeCompressString(" "));
406 JSHandle<EcmaString> concatString = factory->ConcatFromString(handlePrefixString, spaceString);
407 newString = *factory->ConcatFromString(concatString, functionName);
408 } else {
409 newString = *functionName;
410 }
411 JSHandle<JSTaggedValue> nameHandle(thread, newString);
412 JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
413 PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
414 JSHandle<JSTaggedValue> funcHandle(func);
415 return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, nameKey, nameDesc);
416 }
417
SetFunctionLength(JSThread * thread,const JSHandle<JSFunction> & func,JSTaggedValue length,bool cfg)418 bool JSFunction::SetFunctionLength(JSThread *thread, const JSHandle<JSFunction> &func, JSTaggedValue length, bool cfg)
419 {
420 ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
421 ASSERT_PRINT(length.IsInteger(), "length must be integer");
422 JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
423 ASSERT_PRINT(!JSTaggedValue::Less(thread, JSHandle<JSTaggedValue>(thread, length),
424 JSHandle<JSTaggedValue>(thread, JSTaggedValue(0))),
425 "length must be non negtive integer");
426 PropertyDescriptor lengthDesc(thread, JSHandle<JSTaggedValue>(thread, length), false, false, cfg);
427 JSHandle<JSTaggedValue> funcHandle(func);
428 return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, lengthKeyHandle, lengthDesc);
429 }
430
CallInternal(JSThread * thread,const JSHandle<JSBoundFunction> & func)431 JSTaggedValue JSBoundFunction::CallInternal(JSThread *thread, const JSHandle<JSBoundFunction> &func)
432 {
433 JSHandle<JSTaggedValue> target(thread, func->GetBoundTarget());
434 JSHandle<JSTaggedValue> boundThis(thread, func->GetBoundThis());
435
436 InternalCallParams *params = thread->GetInternalCallParams();
437 params->MakeBoundArgv(thread, func);
438 return JSFunction::Call(thread, target, boundThis, params->GetLength(), params->GetArgv());
439 }
440
441 // 9.4.1.2[[Construct]](argumentsList, newTarget)
ConstructInternal(JSThread * thread,const JSHandle<JSBoundFunction> & func,const JSHandle<JSTaggedValue> & newTarget)442 JSTaggedValue JSBoundFunction::ConstructInternal(JSThread *thread, const JSHandle<JSBoundFunction> &func,
443 const JSHandle<JSTaggedValue> &newTarget)
444 {
445 JSHandle<JSTaggedValue> target(thread, func->GetBoundTarget());
446 ASSERT(target->IsConstructor());
447 JSMutableHandle<JSTaggedValue> newTargetMutable(thread, newTarget.GetTaggedValue());
448 if (JSTaggedValue::SameValue(func.GetTaggedValue(), newTarget.GetTaggedValue())) {
449 newTargetMutable.Update(target.GetTaggedValue());
450 }
451 InternalCallParams *params = thread->GetInternalCallParams();
452 params->MakeBoundArgv(thread, func);
453 return JSFunction::Construct(thread, target, params->GetLength(), params->GetArgv(), newTargetMutable);
454 }
455
ProxyRevocFunctions(const JSThread * thread,const JSHandle<JSProxyRevocFunction> & revoker)456 void JSProxyRevocFunction::ProxyRevocFunctions(const JSThread *thread, const JSHandle<JSProxyRevocFunction> &revoker)
457 {
458 // 1.Let p be the value of F’s [[RevocableProxy]] internal slot.
459 JSTaggedValue proxy = revoker->GetRevocableProxy();
460 // 2.If p is null, return undefined.
461 if (proxy.IsNull()) {
462 return;
463 }
464
465 // 3.Set the value of F’s [[RevocableProxy]] internal slot to null.
466 revoker->SetRevocableProxy(thread, JSTaggedValue::Null());
467
468 // 4.Assert: p is a Proxy object.
469 ASSERT(proxy.IsJSProxy());
470 JSHandle<JSProxy> proxyHandle(thread, proxy);
471
472 // 5 ~ 6 Set internal slot of p to null.
473 proxyHandle->SetTarget(thread, JSTaggedValue::Null());
474 proxyHandle->SetHandler(thread, JSTaggedValue::Null());
475 }
476
AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo * argv)477 JSTaggedValue JSFunction::AccessCallerArgumentsThrowTypeError([[maybe_unused]] EcmaRuntimeCallInfo *argv)
478 {
479 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(),
480 "Under strict mode, 'caller' and 'arguments' properties must not be accessed.",
481 JSTaggedValue::Exception());
482 }
483
IntlNameGetter(JSThread * thread,const JSHandle<JSObject> & self)484 JSTaggedValue JSIntlBoundFunction::IntlNameGetter(JSThread *thread, [[maybe_unused]] const JSHandle<JSObject> &self)
485 {
486 return thread->GlobalConstants()->GetEmptyString();
487 }
488
SetFunctionNameNoPrefix(JSThread * thread,JSFunction * func,JSTaggedValue name)489 void JSFunction::SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name)
490 {
491 ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
492 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
493
494 JSHandle<JSTaggedValue> funcHandle(thread, func);
495 {
496 JSMutableHandle<JSTaggedValue> nameHandle(thread, JSTaggedValue::Undefined());
497 if (!name.IsSymbol()) {
498 nameHandle.Update(name);
499 } else {
500 JSHandle<JSTaggedValue> nameBegin(thread, name);
501 JSTaggedValue description = JSSymbol::Cast(name.GetTaggedObject())->GetDescription();
502 if (description.IsUndefined()) {
503 nameHandle.Update(thread->GlobalConstants()->GetEmptyString());
504 } else {
505 JSHandle<EcmaString> concatName;
506 JSHandle<EcmaString> leftBrackets = factory->NewFromCanBeCompressString("[");
507 JSHandle<EcmaString> rightBrackets = factory->NewFromCanBeCompressString("]");
508 concatName = factory->ConcatFromString(
509 leftBrackets,
510 JSHandle<EcmaString>(thread, JSSymbol::Cast(nameBegin->GetHeapObject())->GetDescription()));
511 concatName = factory->ConcatFromString(concatName, rightBrackets);
512 nameHandle.Update(concatName.GetTaggedValue());
513 }
514 }
515 PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
516 JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, thread->GlobalConstants()->GetHandledNameString(),
517 nameDesc);
518 }
519 }
520
GetInstanceJSHClass(JSThread * thread,JSHandle<JSFunction> constructor,JSHandle<JSTaggedValue> newTarget)521 JSHandle<JSHClass> JSFunction::GetInstanceJSHClass(JSThread *thread, JSHandle<JSFunction> constructor,
522 JSHandle<JSTaggedValue> newTarget)
523 {
524 JSHandle<JSHClass> ctorInitialJSHClass(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
525 // newTarget is construct itself
526 if (newTarget.GetTaggedValue() == constructor.GetTaggedValue()) {
527 return ctorInitialJSHClass;
528 }
529
530 // newTarget is derived-class of constructor
531 if (newTarget->IsJSFunction()) {
532 JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
533 if (newTargetFunc->IsDerivedConstructor()) {
534 JSTaggedValue newTargetProto = JSHandle<JSObject>::Cast(newTarget)->GetPrototype(thread);
535 if (newTargetProto == constructor.GetTaggedValue()) {
536 return GetOrCreateDerivedJSHClass(thread, newTargetFunc, constructor, ctorInitialJSHClass);
537 }
538 }
539 }
540
541 // ECMA2015 9.1.15 3.Let proto be Get(constructor, "prototype").
542 JSMutableHandle<JSTaggedValue> prototype(thread, JSTaggedValue::Undefined());
543 if (newTarget->IsJSFunction()) {
544 JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
545 FunctionKind kind = newTargetFunc->GetFunctionKind();
546 if (HasPrototype(kind)) {
547 prototype.Update(PrototypeGetter(thread, JSHandle<JSObject>::Cast(newTargetFunc)));
548 }
549 } else {
550 // Such case: bound function and define a "prototype" property.
551 JSHandle<JSTaggedValue> customizePrototype =
552 JSTaggedValue::GetProperty(thread, newTarget, thread->GlobalConstants()->GetHandledPrototypeString())
553 .GetValue();
554 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread);
555 prototype.Update(customizePrototype.GetTaggedValue());
556 // Reload JSHClass of constructor, where the lookup of 'prototype' property may change it.
557 ctorInitialJSHClass = JSHandle<JSHClass>(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
558 }
559
560 if (!prototype->IsECMAObject()) {
561 prototype.Update(constructor->GetFunctionPrototype());
562 }
563
564 JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
565 newJSHClass->SetPrototype(thread, prototype);
566
567 return newJSHClass;
568 }
569
GetOrCreateDerivedJSHClass(JSThread * thread,JSHandle<JSFunction> derived,JSHandle<JSFunction> constructor,JSHandle<JSHClass> ctorInitialJSHClass)570 JSHandle<JSHClass> JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle<JSFunction> derived,
571 JSHandle<JSFunction> constructor,
572 JSHandle<JSHClass> ctorInitialJSHClass)
573 {
574 JSTaggedValue protoOrDyn(derived->GetProtoOrDynClass());
575 // has cached JSHClass, return directly
576 if (protoOrDyn.IsJSHClass()) {
577 return JSHandle<JSHClass>(thread, protoOrDyn);
578 }
579
580 JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
581 // guarante derived has function prototype
582 JSHandle<JSTaggedValue> prototype(thread, derived->GetProtoOrDynClass());
583 ASSERT(!prototype->IsHole());
584 newJSHClass->SetPrototype(thread, prototype);
585 derived->SetProtoOrDynClass(thread, newJSHClass);
586 return newJSHClass;
587 }
588
589 // Those interface below is discarded
InitializeJSFunction(JSThread * thread,const JSHandle<GlobalEnv> & env,const JSHandle<JSFunction> & func,FunctionKind kind,bool strict)590 void JSFunction::InitializeJSFunction(JSThread *thread, [[maybe_unused]] const JSHandle<GlobalEnv> &env,
591 const JSHandle<JSFunction> &func, FunctionKind kind, bool strict)
592 {
593 InitializeJSFunction(thread, func, kind, strict);
594 }
595
IsDynClass(JSTaggedValue object)596 bool JSFunction::IsDynClass(JSTaggedValue object)
597 {
598 return object.IsJSHClass();
599 }
600
GetOrCreateInitialDynClass(JSThread * thread,const JSHandle<JSFunction> & fun)601 DynClass *JSFunction::GetOrCreateInitialDynClass(JSThread *thread, const JSHandle<JSFunction> &fun)
602 {
603 return reinterpret_cast<DynClass *>(JSFunction::GetOrCreateInitialJSHClass(thread, fun));
604 }
605
GetInstanceDynClass(JSThread * thread,JSHandle<JSFunction> constructor,JSHandle<JSTaggedValue> newTarget)606 JSHandle<DynClass> JSFunction::GetInstanceDynClass(JSThread *thread, JSHandle<JSFunction> constructor,
607 JSHandle<JSTaggedValue> newTarget)
608 {
609 return JSHandle<DynClass>(JSFunction::GetInstanceJSHClass(thread, constructor, newTarget));
610 }
611
NameSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)612 bool JSFunction::NameSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
613 [[maybe_unused]] bool mayThrow)
614 {
615 if (self->IsPropertiesDict()) {
616 // replace setter with value
617 JSHandle<JSTaggedValue> nameString = thread->GlobalConstants()->GetHandledNameString();
618 return self->UpdatePropertyInDictionary(thread, nameString.GetTaggedValue(), value.GetTaggedValue());
619 }
620 self->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, value.GetTaggedValue());
621 return true;
622 }
623 } // namespace panda::ecmascript
624