• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/js_function.h"
17 
18 #include "ecmascript/debugger/js_debugger_manager.h"
19 #include "ecmascript/ecma_context.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/interpreter/interpreter.h"
22 #include "ecmascript/js_object-inl.h"
23 #include "ecmascript/module/js_module_manager.h"
24 #include "ecmascript/object_factory-inl.h"
25 #include "ecmascript/pgo_profiler/pgo_profiler.h"
26 #include "ecmascript/require/js_require_manager.h"
27 
28 namespace panda::ecmascript {
InitializeJSFunction(JSThread * thread,const JSHandle<JSFunction> & func,FunctionKind kind)29 void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle<JSFunction> &func, FunctionKind kind)
30 {
31     InitializeWithDefaultValue(thread, func);
32     auto globalConst = thread->GlobalConstants();
33     if (HasPrototype(kind)) {
34         JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionPrototypeAccessor();
35         if (kind == FunctionKind::BASE_CONSTRUCTOR || kind == FunctionKind::GENERATOR_FUNCTION ||
36             kind == FunctionKind::ASYNC_GENERATOR_FUNCTION || kind == FunctionKind::NONE_FUNCTION) {
37             func->SetPropertyInlinedProps(thread, PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
38             accessor = globalConst->GetHandledFunctionNameAccessor();
39             func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
40             accessor = globalConst->GetHandledFunctionLengthAccessor();
41             func->SetPropertyInlinedProps(thread, LENGTH_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
42             if (kind == FunctionKind::ASYNC_GENERATOR_FUNCTION) {
43                 // Not duplicate codes, it will slow the performace if combining and put outside!
44                 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
45                 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
46                 JSHandle<JSFunction> objFun(env->GetObjectFunction());
47                 JSHandle<JSObject> initialGeneratorFuncPrototype = factory->NewJSObjectByConstructor(objFun);
48                 JSObject::SetPrototype(thread, initialGeneratorFuncPrototype, env->GetAsyncGeneratorPrototype());
49                 func->SetProtoOrHClass(thread, initialGeneratorFuncPrototype);
50             }
51             if (kind == FunctionKind::GENERATOR_FUNCTION) {
52                 // Not duplicate codes, it will slow the performace if combining and put outside!
53                 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
54                 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
55                 JSHandle<JSFunction> objFun(env->GetObjectFunction());
56                 JSHandle<JSObject> initialGeneratorFuncPrototype = factory->NewJSObjectByConstructor(objFun);
57                 JSObject::SetPrototype(thread, initialGeneratorFuncPrototype, env->GetGeneratorPrototype());
58                 func->SetProtoOrHClass(thread, initialGeneratorFuncPrototype);
59             }
60         } else if (!JSFunction::IsClassConstructor(kind)) {  // class ctor do nothing
61             PropertyDescriptor desc(thread, accessor, kind != FunctionKind::BUILTIN_CONSTRUCTOR, false, false);
62             [[maybe_unused]] bool success = JSObject::DefineOwnProperty(
63                 thread, JSHandle<JSObject>(func), globalConst->GetHandledPrototypeString(), desc, SCheckMode::SKIP);
64             ASSERT(success);
65         }
66     } else if (HasAccessor(kind)) {
67         JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionNameAccessor();
68         func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
69         accessor = globalConst->GetHandledFunctionLengthAccessor();
70         func->SetPropertyInlinedProps(thread, LENGTH_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
71     }
72 }
73 
InitializeSFunction(JSThread * thread,const JSHandle<JSFunction> & func,FunctionKind kind)74 void JSFunction::InitializeSFunction(JSThread *thread, const JSHandle<JSFunction> &func, FunctionKind kind)
75 {
76     InitializeWithDefaultValue(thread, func);
77     auto globalConst = thread->GlobalConstants();
78     JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionPrototypeAccessor();
79     if (HasAccessor(kind) || IsBaseConstructorKind(kind)) {
80         if (IsBaseConstructorKind(kind)) {
81             func->SetPropertyInlinedProps(thread, PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
82         }
83         accessor = globalConst->GetHandledFunctionNameAccessor();
84         func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
85         accessor = globalConst->GetHandledFunctionLengthAccessor();
86         func->SetPropertyInlinedProps(thread, LENGTH_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
87     }
88 }
89 
InitializeWithDefaultValue(JSThread * thread,const JSHandle<JSFunction> & func)90 void JSFunction::InitializeWithDefaultValue(JSThread *thread, const JSHandle<JSFunction> &func)
91 {
92     func->SetProtoOrHClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER);
93     func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
94     func->SetWorkNodePointer(reinterpret_cast<uintptr_t>(nullptr));
95     func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
96     func->SetMachineCode(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
97     func->SetBaselineCode(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
98     func->SetRawProfileTypeInfo(thread, thread->GlobalConstants()->GetEmptyProfileTypeInfoCell(), SKIP_BARRIER);
99     func->SetMethod(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
100     func->SetModule(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
101     func->SetProtoTransRootHClass(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
102     func->SetCodeEntry(reinterpret_cast<uintptr_t>(nullptr));
103     func->ClearCompiledCodeFlags();
104     func->SetTaskConcurrentFuncFlag(0); // 0 : default value
105 }
106 
NewJSFunctionPrototype(JSThread * thread,const JSHandle<JSFunction> & func)107 JSHandle<JSObject> JSFunction::NewJSFunctionPrototype(JSThread *thread, const JSHandle<JSFunction> &func)
108 {
109     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
110     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
111     JSHandle<JSFunction> objFun;
112     if (func->IsSharedFunction()) {
113         objFun = JSHandle<JSFunction>(env->GetSObjectFunction());
114     } else {
115         objFun = JSHandle<JSFunction>(env->GetObjectFunction());
116     }
117     JSHandle<JSObject> funPro = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(objFun);
118     SetFunctionPrototypeOrInstanceHClass(thread, func, funPro.GetTaggedValue());
119 
120     // set "constructor" in prototype
121     JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
122     PropertyDescriptor descriptor(thread, JSHandle<JSTaggedValue>::Cast(func), true, false, true);
123     JSObject::DefineOwnProperty(thread, funPro, constructorKey, descriptor);
124 
125     return funPro;
126 }
127 
GetOrCreateInitialJSHClass(JSThread * thread,const JSHandle<JSFunction> & fun)128 JSHClass *JSFunction::GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle<JSFunction> &fun)
129 {
130     JSTaggedValue protoOrHClass(fun->GetProtoOrHClass());
131     if (protoOrHClass.IsJSHClass()) {
132         return reinterpret_cast<JSHClass *>(protoOrHClass.GetTaggedObject());
133     }
134 
135     JSHandle<JSTaggedValue> proto;
136     bool needProfileTransition = false;
137     if (!fun->HasFunctionPrototype()) {
138         proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, fun));
139         if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
140             thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(fun.GetTaggedType(),
141                 JSTaggedType(proto->GetTaggedObject()->GetClass()), pgo::ProfileType::Kind::PrototypeId);
142         }
143     } else {
144         proto = JSHandle<JSTaggedValue>(thread, fun->GetProtoOrHClass());
145         needProfileTransition = proto->IsECMAObject();
146     }
147 
148     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
149     JSHandle<JSHClass> hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, proto);
150     fun->SetProtoOrHClass(thread, hclass);
151     if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
152         if (!needProfileTransition) {
153             thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(fun.GetTaggedType(), hclass.GetTaggedType());
154         } else {
155             thread->GetEcmaVM()->GetPGOProfiler()->ProfileProtoTransitionClass(fun, hclass, proto);
156         }
157     }
158     return *hclass;
159 }
160 
PrototypeGetter(JSThread * thread,const JSHandle<JSObject> & self)161 JSTaggedValue JSFunction::PrototypeGetter(JSThread *thread, const JSHandle<JSObject> &self)
162 {
163     JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(self);
164     if (!func->HasFunctionPrototype()) {
165         JSHandle<JSTaggedValue> proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, func));
166         if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
167             thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(func.GetTaggedType(),
168                 JSTaggedType(proto->GetTaggedObject()->GetClass()), pgo::ProfileType::Kind::PrototypeId);
169         }
170     }
171     return JSFunction::Cast(*self)->GetFunctionPrototype();
172 }
173 
PrototypeSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)174 bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
175                                  [[maybe_unused]] bool mayThrow)
176 {
177     JSHandle<JSFunction> func(self);
178     JSTaggedValue protoOrHClass = func->GetProtoOrHClass();
179     if (protoOrHClass.IsJSHClass()) {
180         // need transition
181         JSHandle<JSHClass> hclass(thread, JSHClass::Cast(protoOrHClass.GetTaggedObject()));
182         JSHandle<JSHClass> newClass = JSHClass::SetPrototypeWithNotification(thread, hclass, value);
183         func->SetProtoOrHClass(thread, newClass);
184         // Forbide to profile for changing the function prototype after an instance of the function has been created
185         if (!hclass->IsTS() && thread->GetEcmaVM()->IsEnablePGOProfiler()) {
186             EntityId ctorMethodId = Method::Cast(func->GetMethod().GetTaggedObject())->GetMethodId();
187             thread->GetEcmaVM()->GetPGOProfiler()->InsertSkipCtorMethodIdSafe(ctorMethodId);
188         }
189     } else {
190         if (!value->IsECMAObject()) {
191             func->SetProtoOrHClass(thread, value.GetTaggedValue());
192             return true;
193         }
194 
195         bool enablePgo = thread->GetEcmaVM()->IsEnablePGOProfiler();
196         JSMutableHandle<JSTaggedValue> oldPrototype(thread, func->GetProtoOrHClass());
197         // For pgo, we need the oldPrototype to record the old ihc and phc.
198         if (enablePgo && oldPrototype->IsHole()) {
199             oldPrototype.Update(JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, func)));
200         }
201         JSHandle<JSTaggedValue> baseIhc(thread, value->GetTaggedObject()->GetClass());
202         func->SetProtoOrHClass(thread, value.GetTaggedValue());
203         JSHClass::OptimizePrototypeForIC(thread, value, true);
204         if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
205             thread->GetEcmaVM()->GetPGOProfiler()->ProfileProtoTransitionPrototype(func, value, oldPrototype, baseIhc);
206         }
207     }
208     return true;
209 }
210 
SetFunctionPrototypeOrInstanceHClass(const JSThread * thread,const JSHandle<JSFunction> & fun,JSTaggedValue protoOrHClass)211 void JSFunction::SetFunctionPrototypeOrInstanceHClass(const JSThread *thread, const JSHandle<JSFunction> &fun,
212                                                       JSTaggedValue protoOrHClass)
213 {
214     JSHandle<JSTaggedValue> protoHandle(thread, protoOrHClass);
215     fun->SetProtoOrHClass(thread, protoHandle.GetTaggedValue());
216     if (protoHandle->IsJSHClass()) {
217         protoHandle = JSHandle<JSTaggedValue>(thread,
218                                               JSHClass::Cast(protoHandle->GetTaggedObject())->GetPrototype());
219     }
220     if (protoHandle->IsECMAObject()) {
221         JSHClass::OptimizePrototypeForIC(thread, protoHandle);
222     }
223 }
224 
GetFunctionNameString(JSThread * thread,JSHandle<EcmaString> concatString,ObjectFactory * factory,JSHandle<JSTaggedValue> target)225 EcmaString* JSFunction::GetFunctionNameString(JSThread *thread, JSHandle<EcmaString> concatString,
226                                               ObjectFactory *factory, JSHandle<JSTaggedValue> target)
227 {
228     JSTaggedValue method = JSHandle<JSFunction>::Cast(target)->GetMethod();
229     JSHandle<EcmaString> newString = factory->ConcatFromString(concatString, factory->GetEmptyString());
230     if (!method.IsUndefined()) {
231         Method *targetObj = Method::Cast(method.GetTaggedObject());
232         std::string funcName = targetObj->ParseFunctionName();
233         if (!funcName.empty()) {
234             JSHandle<JSTaggedValue> methodName(thread,
235                                                factory->NewFromStdString(funcName).GetTaggedValue());
236             JSHandle<EcmaString> functionName = JSHandle<EcmaString>::Cast(methodName);
237             newString = factory->ConcatFromString(concatString, functionName);
238         }
239     }
240     return *newString;
241 }
242 
NameGetter(JSThread * thread,const JSHandle<JSObject> & self)243 JSTaggedValue JSFunction::NameGetter(JSThread *thread, const JSHandle<JSObject> &self)
244 {
245     if (self->IsBoundFunction()) {
246         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
247         const GlobalEnvConstants *globalConst = thread->GlobalConstants();
248         JSHandle<JSBoundFunction> boundFunction(self);
249         JSHandle<JSTaggedValue> target(thread, boundFunction->GetBoundTarget());
250 
251         JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
252         JSHandle<JSTaggedValue> boundName = thread->GlobalConstants()->GetHandledBoundString();
253         JSHandle<JSTaggedValue> targetName = JSObject::GetProperty(thread, target, nameKey).GetValue();
254         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
255 
256         JSHandle<EcmaString> handlePrefixString = JSTaggedValue::ToString(thread, boundName);
257         JSHandle<EcmaString> spaceString(globalConst->GetHandledSpaceString());
258         JSHandle<EcmaString> concatString = factory->ConcatFromString(handlePrefixString, spaceString);
259 
260         EcmaString *newString;
261         if (!targetName->IsString()) {
262             newString = GetFunctionNameString(thread, concatString, factory, target);
263         } else {
264             JSHandle<EcmaString> functionName = JSHandle<EcmaString>::Cast(targetName);
265             newString = *factory->ConcatFromString(concatString, functionName);
266         }
267 
268         return JSTaggedValue(newString);
269     }
270 
271     JSTaggedValue method = JSHandle<JSFunction>::Cast(self)->GetMethod();
272     if (method.IsUndefined()) {
273         return JSTaggedValue::Undefined();
274     }
275     Method *target = Method::Cast(method.GetTaggedObject());
276     if (target->IsNativeWithCallField()) {
277         return JSTaggedValue::Undefined();
278     }
279     auto [funcName, isASCII] = target->ParseFunctionNameView();
280     if (funcName.empty()) {
281         return thread->GlobalConstants()->GetEmptyString();
282     }
283     ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
284     const JSHandle<EcmaString> nameHdl = factory->NewFromUtf8(funcName, isASCII);
285     if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::GETTER_FUNCTION) {
286         return factory->ConcatFromString(
287             JSHandle<EcmaString>(thread->GlobalConstants()->GetHandledGetWithSpaceString()), nameHdl).GetTaggedValue();
288     }
289     if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::SETTER_FUNCTION) {
290         return factory->ConcatFromString(
291             JSHandle<EcmaString>(thread->GlobalConstants()->GetHandledSetWithSpaceString()), nameHdl).GetTaggedValue();
292     }
293     return nameHdl.GetTaggedValue();
294 }
295 
LengthGetter(JSThread * thread,const JSHandle<JSObject> & self)296 JSTaggedValue JSFunction::LengthGetter(JSThread *thread, const JSHandle<JSObject> &self)
297 {
298     // LengthGetter only support BoundFunction
299     if (self->IsBoundFunction()) {
300         JSMutableHandle<JSBoundFunction> boundFunction(thread, self.GetTaggedValue());
301         JSHandle<JSTaggedValue> arguments(thread, boundFunction->GetBoundArguments());
302         uint32_t argsLength = TaggedArray::Cast(arguments->GetTaggedObject())->GetLength();
303         while (boundFunction->GetBoundTarget().IsBoundFunction()) {
304             boundFunction.Update(boundFunction->GetBoundTarget());
305             argsLength += TaggedArray::Cast(boundFunction->GetBoundArguments())->GetLength();
306         }
307 
308         JSHandle<JSTaggedValue> target(thread, boundFunction->GetBoundTarget());
309         JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
310 
311         bool targetHasLength =
312             JSTaggedValue::HasOwnProperty(thread, target, lengthKey);
313         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
314         uint32_t lengthValue = 0;
315         if (targetHasLength) {
316             JSHandle<JSTaggedValue> targetLength = JSTaggedValue::GetProperty(thread, target, lengthKey).GetValue();
317             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
318             if (targetLength->IsNumber()) {
319                 lengthValue =
320                     std::max(0u, static_cast<uint32_t>(JSTaggedValue::ToNumber(thread, targetLength).GetNumber()) -
321                              argsLength);
322                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
323             }
324         }
325         return JSTaggedValue(lengthValue);
326     }
327 
328     JSHandle<JSFunction> func(self);
329     return JSTaggedValue(func->GetLength());
330 }
331 
OrdinaryHasInstance(JSThread * thread,const JSHandle<JSTaggedValue> & constructor,const JSHandle<JSTaggedValue> & obj)332 bool JSFunction::OrdinaryHasInstance(JSThread *thread, const JSHandle<JSTaggedValue> &constructor,
333                                      const JSHandle<JSTaggedValue> &obj)
334 {
335     // 1. If IsCallable(C) is false, return false.
336     if (!constructor->IsCallable()) {
337         return false;
338     }
339 
340     // 2. If C has a [[BoundTargetFunction]] internal slot, then
341     //    a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
342     //    b. Return InstanceofOperator(O,BC)  (see 12.9.4).
343     if (constructor->IsBoundFunction()) {
344         STACK_LIMIT_CHECK(thread, false);
345         JSHandle<JSBoundFunction> boundFunction(thread, JSBoundFunction::Cast(constructor->GetTaggedObject()));
346         JSTaggedValue boundTarget = boundFunction->GetBoundTarget();
347         return JSObject::InstanceOf(thread, obj, JSHandle<JSTaggedValue>(thread, boundTarget));
348     }
349     // 3. If Type(O) is not Object, return false
350     if (!obj->IsECMAObject()) {
351         return false;
352     }
353 
354     // 4. Let P be Get(C, "prototype").
355     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
356     JSHandle<JSTaggedValue> prototypeString = globalConst->GetHandledPrototypeString();
357     JSMutableHandle<JSTaggedValue> constructorPrototype(thread, JSTaggedValue::Undefined());
358     if (constructor->IsJSFunction()) {
359         JSHandle<JSFunction> ctor(thread, constructor->GetTaggedObject());
360         JSHandle<JSTaggedValue> ctorProtoOrHclass(thread, ctor->GetProtoOrHClass());
361         if (!ctorProtoOrHclass->IsHole()) {
362             if (!ctorProtoOrHclass->IsJSHClass()) {
363                 constructorPrototype.Update(ctorProtoOrHclass);
364             } else {
365                 JSTaggedValue ctorProto = JSHClass::Cast(ctorProtoOrHclass->GetTaggedObject())->GetProto();
366                 constructorPrototype.Update(ctorProto);
367             }
368         } else {
369             constructorPrototype.Update(JSTaggedValue::GetProperty(thread, constructor, prototypeString).GetValue());
370         }
371     } else {
372         constructorPrototype.Update(JSTaggedValue::GetProperty(thread, constructor, prototypeString).GetValue());
373     }
374 
375     // 5. ReturnIfAbrupt(P).
376     // no throw exception, so needn't return
377     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
378 
379     // 6. If Type(P) is not Object, throw a TypeError exception.
380     if (!constructorPrototype->IsECMAObject()) {
381         THROW_TYPE_ERROR_AND_RETURN(thread, "HasInstance: is not Object", false);
382     }
383 
384     // 7. Repeat
385     //    a.Let O be O.[[GetPrototypeOf]]().
386     //    b.ReturnIfAbrupt(O).
387     //    c.If O is null, return false.
388     //    d.If SameValue(P, O) is true, return true.
389     JSMutableHandle<JSTaggedValue> object(thread, obj.GetTaggedValue());
390     while (!object->IsNull()) {
391         object.Update(JSTaggedValue::GetPrototype(thread, object));
392         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
393         if (JSTaggedValue::SameValue(object, constructorPrototype)) {
394             return true;
395         }
396     }
397     return false;
398 }
399 
MakeConstructor(JSThread * thread,const JSHandle<JSFunction> & func,const JSHandle<JSTaggedValue> & proto,bool writable)400 bool JSFunction::MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &func,
401                                  const JSHandle<JSTaggedValue> &proto, bool writable)
402 {
403     ASSERT_PRINT(proto->IsHeapObject() || proto->IsUndefined(), "proto must be JSObject or Undefined");
404     ASSERT_PRINT(func->IsConstructor(), "func must be Constructor type");
405     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
406     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
407     JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
408 
409     ASSERT_PRINT(func->GetProtoOrHClass().IsHole() && func->IsExtensible(),
410                  "function doesn't has proto_type property and is extensible object");
411     ASSERT_PRINT(JSObject::HasProperty(thread, JSHandle<JSObject>(func), constructorKey),
412                  "function must have constructor");
413 
414     // proto.constructor = func
415     bool status = false;
416     if (proto->IsUndefined()) {
417         // Let prototype be ObjectCreate(%ObjectPrototype%).
418         JSHandle<JSTaggedValue> objPrototype = env->GetObjectFunctionPrototype();
419         PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
420         status = JSTaggedValue::DefinePropertyOrThrow(thread, objPrototype, constructorKey, constructorDesc);
421     } else {
422         PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
423         status = JSTaggedValue::DefinePropertyOrThrow(thread, proto, constructorKey, constructorDesc);
424     }
425     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
426 
427     ASSERT_PRINT(status, "DefineProperty construct failed");
428     // func.prototype = proto
429     // Let status be DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]:
430     // prototype, [[Writable]]: writablePrototype, [[Enumerable]]: false, [[Configurable]]: false}).
431     SetFunctionPrototypeOrInstanceHClass(thread, func, proto.GetTaggedValue());
432 
433     ASSERT_PRINT(status, "DefineProperty proto_type failed");
434     return status;
435 }
436 
Call(EcmaRuntimeCallInfo * info)437 JSTaggedValue JSFunction::Call(EcmaRuntimeCallInfo *info)
438 {
439     if (info == nullptr) {
440         return JSTaggedValue::Exception();
441     }
442 
443     JSThread *thread = info->GetThread();
444     // 1. ReturnIfAbrupt(F).
445     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
446     JSHandle<JSTaggedValue> func = info->GetFunction();
447     // 2. If argumentsList was not passed, let argumentsList be a new empty List.
448     // 3. If IsCallable(F) is false, throw a TypeError exception.
449     if (!func->IsCallable()) {
450         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
451         THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
452     }
453 
454     auto *hclass = func->GetTaggedObject()->GetClass();
455     if (hclass->IsClassConstructor()) {
456         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
457         THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", JSTaggedValue::Exception());
458     }
459     return EcmaInterpreter::Execute(info);
460 }
461 
Construct(EcmaRuntimeCallInfo * info)462 JSTaggedValue JSFunction::Construct(EcmaRuntimeCallInfo *info)
463 {
464     if (info == nullptr) {
465         return JSTaggedValue::Exception();
466     }
467 
468     JSThread *thread = info->GetThread();
469     JSHandle<JSTaggedValue> func(info->GetFunction());
470     JSHandle<JSTaggedValue> target = info->GetNewTarget();
471     if (target->IsUndefined()) {
472         target = func;
473         info->SetNewTarget(target.GetTaggedValue());
474     }
475     if (!(func->IsConstructor() && target->IsConstructor())) {
476         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
477         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
478     }
479 
480     if (func->IsJSFunction()) {
481         return JSFunction::ConstructInternal(info);
482     } else if (func->IsJSProxy()) {
483         return JSProxy::ConstructInternal(info);
484     } else {
485         ASSERT(func->IsBoundFunction());
486         return JSBoundFunction::ConstructInternal(info);
487     }
488 }
489 
Invoke(EcmaRuntimeCallInfo * info,const JSHandle<JSTaggedValue> & key)490 JSTaggedValue JSFunction::Invoke(EcmaRuntimeCallInfo *info, const JSHandle<JSTaggedValue> &key)
491 {
492     if (info == nullptr) {
493         return JSTaggedValue::Exception();
494     }
495 
496     ASSERT(JSTaggedValue::IsPropertyKey(key));
497     JSThread *thread = info->GetThread();
498     JSHandle<JSTaggedValue> thisArg = info->GetThis();
499     JSHandle<JSTaggedValue> func(JSTaggedValue::GetProperty(thread, thisArg, key).GetValue());
500     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
501     info->SetFunction(func.GetTaggedValue());
502     return JSFunction::Call(info);
503 }
504 
InvokeOptimizedEntrypoint(JSThread * thread,JSHandle<JSFunction> mainFunc,JSHandle<JSTaggedValue> & thisArg,CJSInfo * cjsInfo)505 JSTaggedValue JSFunction::InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<JSFunction> mainFunc,
506     JSHandle<JSTaggedValue> &thisArg, CJSInfo* cjsInfo)
507 {
508     ASSERT(thread->IsInManagedState());
509     if (mainFunc->IsClassConstructor()) {
510         {
511             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
512             JSHandle<JSObject> error = factory->GetJSError(ErrorType::TYPE_ERROR,
513                 "class constructor cannot called without 'new'", StackCheck::NO);
514             thread->SetException(error.GetTaggedValue());
515         }
516         return thread->GetException();
517     }
518     Method *method = mainFunc->GetCallTarget();
519     size_t actualNumArgs = method->GetNumArgs();
520     const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
521     JSTaggedValue res;
522     std::vector<JSTaggedType> args;
523 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
524     RuntimeStubs::StartCallTimer(thread->GetGlueAddr(), mainFunc.GetTaggedType(), true);
525 #endif
526     if (mainFunc->IsCompiledFastCall()) {
527         // entry of aot
528         args = JSFunction::GetArgsData(true, thisArg, mainFunc, cjsInfo);
529         res = thread->GetEcmaVM()->FastCallAot(actualNumArgs, args.data(), prevFp);
530     } else {
531         args = JSFunction::GetArgsData(false, thisArg, mainFunc, cjsInfo);
532         // entry of aot
533         res = thread->GetCurrentEcmaContext()->ExecuteAot(actualNumArgs, args.data(), prevFp, false);
534     }
535 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
536     RuntimeStubs::EndCallTimer(thread->GetGlueAddr(), mainFunc.GetTaggedType());
537 #endif
538     if (thread->HasPendingException()) {
539         return thread->GetException();
540     }
541     return res;
542 }
543 
GetArgsData(bool isFastCall,JSHandle<JSTaggedValue> & thisArg,JSHandle<JSFunction> mainFunc,CJSInfo * cjsInfo)544 std::vector<JSTaggedType> JSFunction::GetArgsData(bool isFastCall, JSHandle<JSTaggedValue> &thisArg,
545     JSHandle<JSFunction> mainFunc, CJSInfo* cjsInfo)
546 {
547     size_t argsNum;
548     uint32_t mandatoryNum;
549     Method *method = mainFunc->GetCallTarget();
550     size_t actualNumArgs = method->GetNumArgs();
551     if (isFastCall) {
552         argsNum = actualNumArgs + NUM_MANDATORY_JSFUNC_ARGS - 1;
553         mandatoryNum = NUM_MANDATORY_JSFUNC_ARGS - 1;
554     } else {
555         argsNum = actualNumArgs + NUM_MANDATORY_JSFUNC_ARGS;
556         mandatoryNum = NUM_MANDATORY_JSFUNC_ARGS;
557     }
558     std::vector<JSTaggedType> args(argsNum, JSTaggedValue::Undefined().GetRawData());
559     args[0] = mainFunc.GetTaggedValue().GetRawData();
560     if (isFastCall) {
561         args[1] = thisArg.GetTaggedValue().GetRawData(); // 1: args number
562     } else {
563         args[2] = thisArg.GetTaggedValue().GetRawData(); // 2: args number
564     }
565     if (cjsInfo != nullptr) {
566         args[mandatoryNum++] = cjsInfo->exportsHdl.GetTaggedValue().GetRawData();
567         args[mandatoryNum++] = cjsInfo->requireHdl.GetTaggedValue().GetRawData();
568         args[mandatoryNum++] = cjsInfo->moduleHdl.GetTaggedValue().GetRawData();
569         args[mandatoryNum++] = cjsInfo->filenameHdl.GetTaggedValue().GetRawData();
570         args[mandatoryNum] = cjsInfo->dirnameHdl.GetTaggedValue().GetRawData();
571     }
572     return args;
573 }
574 
InvokeOptimizedEntrypoint(JSThread * thread,JSHandle<JSFunction> func,EcmaRuntimeCallInfo * info)575 JSTaggedValue JSFunction::InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<JSFunction> func,
576     EcmaRuntimeCallInfo *info)
577 {
578     ASSERT(thread->IsInManagedState());
579     Method *method = func->GetCallTarget();
580     JSTaggedValue resultValue;
581     size_t numArgs = method->GetNumArgsWithCallField();
582     bool needPushArgv = numArgs > info->GetArgsNumber();
583     const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
584 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
585     RuntimeStubs::StartCallTimer(thread->GetGlueAddr(), func.GetTaggedType(), true);
586 #endif
587     if (func->IsCompiledFastCall()) {
588         if (needPushArgv) {
589             info = EcmaInterpreter::ReBuildRuntimeCallInfo(thread, info, numArgs);
590             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
591         }
592         JSTaggedType *stackArgs = info->GetArgs();
593         stackArgs[1] = stackArgs[0];
594         resultValue = thread->GetEcmaVM()->FastCallAot(info->GetArgsNumber(), stackArgs + 1, prevFp);
595     } else {
596         resultValue = thread->GetCurrentEcmaContext()->ExecuteAot(info->GetArgsNumber(),
597             info->GetArgs(), prevFp, needPushArgv);
598     }
599 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
600     RuntimeStubs::EndCallTimer(thread->GetGlueAddr(), func.GetTaggedType());
601 #endif
602     return resultValue;
603 }
604 
605 // [[Construct]]
ConstructInternal(EcmaRuntimeCallInfo * info)606 JSTaggedValue JSFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
607 {
608     ASSERT(info != nullptr);
609     JSThread *thread = info->GetThread();
610     // func need to create a new handle, because optimized EcmaRuntimeCallInfo may overwrite this position.
611     JSHandle<JSFunction> func(thread, info->GetFunction().GetTaggedValue());
612     JSHandle<JSTaggedValue> newTarget(info->GetNewTarget());
613     ASSERT(newTarget->IsECMAObject());
614     if (!func->IsConstructor()) {
615         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
616         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
617     }
618 
619     JSHandle<JSTaggedValue> obj(thread, JSTaggedValue::Undefined());
620     if (func->IsBase()) {
621         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
622         obj = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(func, newTarget));
623         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
624     }
625 
626     JSTaggedValue resultValue;
627     info->SetThis(obj.GetTaggedValue());
628     if (func->IsCompiledCode()) {
629         resultValue = InvokeOptimizedEntrypoint(thread, func, info);
630         const JSTaggedType *curSp = thread->GetCurrentSPFrame();
631         InterpretedEntryFrame *entryState = InterpretedEntryFrame::GetFrameFromSp(curSp);
632         JSTaggedType *prevSp = entryState->base.prev;
633         thread->SetCurrentSPFrame(prevSp);
634     } else {
635         resultValue = EcmaInterpreter::Execute(info);
636     }
637     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
638     // 9.3.2 [[Construct]] (argumentsList, newTarget)
639     if (resultValue.IsECMAObject()) {
640         return resultValue;
641     }
642     if (func->IsBase()) {
643         return obj.GetTaggedValue();
644     }
645     // derived ctor(sub class) return the obj which created by base ctor(parent class)
646     if (func->IsDerivedConstructor()) {
647         if (!resultValue.IsECMAObject() && !resultValue.IsUndefined()) {
648             THROW_TYPE_ERROR_AND_RETURN(thread,
649                 "derived class constructor must return an object or undefined", JSTaggedValue::Exception());
650         }
651         return resultValue;
652     }
653     if (!resultValue.IsUndefined()) {
654         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
655         THROW_TYPE_ERROR_AND_RETURN(thread, "function is non-constructor", JSTaggedValue::Exception());
656     }
657     return obj.GetTaggedValue();
658 }
659 
GetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func)660 JSHandle<JSTaggedValue> JSFunctionBase::GetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func)
661 {
662     JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
663 
664     return JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(func), nameKey).GetValue();
665 }
666 
SetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & prefix)667 bool JSFunctionBase::SetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func,
668                                      const JSHandle<JSTaggedValue> &name, const JSHandle<JSTaggedValue> &prefix)
669 {
670     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
671     ASSERT_PRINT(name->IsStringOrSymbol(), "name must be string or symbol");
672     bool needPrefix = false;
673     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
674     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
675     if (!prefix->IsUndefined()) {
676         ASSERT_PRINT(prefix->IsString(), "prefix must be string");
677         needPrefix = true;
678     }
679     // If Type(name) is Symbol, then
680     // Let description be name’s [[Description]] value.
681     // If description is undefined, let name be the empty String.
682     // Else, let name be the concatenation of "[", description, and "]".
683     JSHandle<EcmaString> functionName;
684     if (name->IsSymbol()) {
685         JSTaggedValue description = JSHandle<JSSymbol>::Cast(name)->GetDescription();
686         JSHandle<EcmaString> descriptionHandle(thread, description);
687         if (description.IsUndefined()) {
688             functionName = factory->GetEmptyString();
689         } else {
690             JSHandle<EcmaString> leftBrackets(globalConst->GetHandledLeftSquareBracketString());
691             JSHandle<EcmaString> rightBrackets(globalConst->GetHandledRightSquareBracketString());
692             functionName = factory->ConcatFromString(leftBrackets, descriptionHandle);
693             functionName = factory->ConcatFromString(functionName, rightBrackets);
694         }
695     } else {
696         functionName = JSHandle<EcmaString>::Cast(name);
697     }
698     EcmaString *newString;
699     if (needPrefix) {
700         JSHandle<EcmaString> handlePrefixString = JSTaggedValue::ToString(thread, prefix);
701         JSHandle<EcmaString> spaceString(globalConst->GetHandledSpaceString());
702         JSHandle<EcmaString> concatString = factory->ConcatFromString(handlePrefixString, spaceString);
703         newString = *factory->ConcatFromString(concatString, functionName);
704     } else {
705         newString = *functionName;
706     }
707     JSHandle<JSTaggedValue> nameHandle(thread, newString);
708     // String.prototype.trimLeft.name shoud be trimStart
709     if (!nameHandle.IsEmpty()
710         && nameHandle.GetTaggedValue() == globalConst->GetHandledTrimLeftString().GetTaggedValue()) {
711         nameHandle = globalConst->GetHandledTrimStartString();
712     }
713     // String.prototype.trimRight.name shoud be trimEnd
714     if (!nameHandle.IsEmpty()
715         && nameHandle.GetTaggedValue() == globalConst->GetHandledTrimRightString().GetTaggedValue()) {
716         nameHandle = globalConst->GetHandledTrimEndString();
717     }
718     JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
719     PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
720     JSHandle<JSTaggedValue> funcHandle(func);
721     return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, nameKey, nameDesc);
722 }
723 
SetFunctionLength(JSThread * thread,const JSHandle<JSFunction> & func,JSTaggedValue length,bool cfg)724 bool JSFunction::SetFunctionLength(JSThread *thread, const JSHandle<JSFunction> &func, JSTaggedValue length, bool cfg)
725 {
726     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
727     ASSERT_PRINT(length.IsInteger(), "length must be integer");
728     JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
729     ASSERT_PRINT(!JSTaggedValue::Less(thread, JSHandle<JSTaggedValue>(thread, length),
730                                       JSHandle<JSTaggedValue>(thread, JSTaggedValue(0))),
731                  "length must be non negative integer");
732     PropertyDescriptor lengthDesc(thread, JSHandle<JSTaggedValue>(thread, length), false, false, cfg);
733     JSHandle<JSTaggedValue> funcHandle(func);
734     return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, lengthKeyHandle, lengthDesc);
735 }
736 
737 // 9.4.1.2[[Construct]](argumentsList, newTarget)
ConstructInternal(EcmaRuntimeCallInfo * info)738 JSTaggedValue JSBoundFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
739 {
740     JSThread *thread = info->GetThread();
741     JSHandle<JSBoundFunction> func(info->GetFunction());
742     JSHandle<JSTaggedValue> target(thread, func->GetBoundTarget());
743     if (!target->IsConstructor()) {
744         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
745     }
746     JSHandle<JSTaggedValue> newTarget = info->GetNewTarget();
747     JSMutableHandle<JSTaggedValue> newTargetMutable(thread, newTarget.GetTaggedValue());
748     if (JSTaggedValue::SameValue(func.GetTaggedValue(), newTarget.GetTaggedValue())) {
749         newTargetMutable.Update(target.GetTaggedValue());
750     }
751 
752     JSHandle<TaggedArray> boundArgs(thread, func->GetBoundArguments());
753     const uint32_t boundLength = boundArgs->GetLength();
754     const uint32_t argsLength = info->GetArgsNumber() + boundLength;
755     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
756     uint32_t argc = info->GetArgsNumber();
757     std::vector<JSTaggedType> argArray(argc);
758     for (uint32_t index = 0; index < argc; ++index) {
759         argArray[index] = info->GetCallArgValue(index).GetRawData();
760     }
761     JSTaggedType *currentSp = reinterpret_cast<JSTaggedType *>(info);
762     InterpretedEntryFrame *currentEntryState = InterpretedEntryFrame::GetFrameFromSp(currentSp);
763     JSTaggedType *prevSp = currentEntryState->base.prev;
764     thread->SetCurrentSPFrame(prevSp);
765     EcmaRuntimeCallInfo *runtimeInfo =
766         EcmaInterpreter::NewRuntimeCallInfo(thread, target, undefined, newTargetMutable, argsLength);
767     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
768     if (boundLength != 0) {
769         runtimeInfo->SetCallArg(boundLength, boundArgs);
770     }
771     for (uint32_t index = 0; index < argc; index++) {
772         runtimeInfo->SetCallArg(static_cast<uint32_t>(index + boundLength), JSTaggedValue(argArray[index]));
773     }
774     return JSFunction::Construct(runtimeInfo);
775 }
776 
ProxyRevocFunctions(const JSThread * thread,const JSHandle<JSProxyRevocFunction> & revoker)777 void JSProxyRevocFunction::ProxyRevocFunctions(const JSThread *thread, const JSHandle<JSProxyRevocFunction> &revoker)
778 {
779     // 1.Let p be the value of F’s [[RevocableProxy]] internal slot.
780     JSTaggedValue proxy = revoker->GetRevocableProxy();
781     // 2.If p is null, return undefined.
782     if (proxy.IsNull()) {
783         return;
784     }
785 
786     // 3.Set the value of F’s [[RevocableProxy]] internal slot to null.
787     revoker->SetRevocableProxy(thread, JSTaggedValue::Null());
788 
789     // 4.Assert: p is a Proxy object.
790     ASSERT(proxy.IsJSProxy());
791     JSHandle<JSProxy> proxyHandle(thread, proxy);
792 
793     // 5 ~ 6 Set internal slot of p to null.
794     proxyHandle->SetTarget(thread, JSTaggedValue::Null());
795     proxyHandle->SetHandler(thread, JSTaggedValue::Null());
796     proxyHandle->SetIsRevoked(true);
797 }
798 
AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo * argv)799 JSTaggedValue JSFunction::AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo *argv)
800 {
801     THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(),
802                                 "Under strict mode, 'caller' and 'arguments' properties must not be accessed.",
803                                 JSTaggedValue::Exception());
804 }
805 
IntlNameGetter(JSThread * thread,const JSHandle<JSObject> & self)806 JSTaggedValue JSIntlBoundFunction::IntlNameGetter(JSThread *thread, [[maybe_unused]] const JSHandle<JSObject> &self)
807 {
808     return thread->GlobalConstants()->GetEmptyString();
809 }
810 
SetFunctionNameNoPrefix(JSThread * thread,JSFunction * func,JSTaggedValue name)811 void JSFunction::SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name)
812 {
813     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
814     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
815     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
816 
817     JSHandle<JSTaggedValue> funcHandle(thread, func);
818     {
819         JSMutableHandle<JSTaggedValue> nameHandle(thread, JSTaggedValue::Undefined());
820         if (!name.IsSymbol()) {
821             nameHandle.Update(name);
822         } else {
823             JSHandle<JSTaggedValue> nameBegin(thread, name);
824             JSTaggedValue description = JSSymbol::Cast(name.GetTaggedObject())->GetDescription();
825             if (description.IsUndefined()) {
826                 nameHandle.Update(globalConst->GetEmptyString());
827             } else {
828                 JSHandle<EcmaString> leftBrackets(globalConst->GetHandledLeftSquareBracketString());
829                 JSHandle<EcmaString> rightBrackets(globalConst->GetHandledRightSquareBracketString());
830                 JSHandle<EcmaString> concatName = factory->ConcatFromString(leftBrackets,
831                     JSHandle<EcmaString>(thread, JSSymbol::Cast(nameBegin->GetTaggedObject())->GetDescription()));
832                 concatName = factory->ConcatFromString(concatName, rightBrackets);
833                 nameHandle.Update(concatName.GetTaggedValue());
834             }
835         }
836         PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
837         JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, globalConst->GetHandledNameString(), nameDesc);
838     }
839 }
840 
GetInstanceJSHClass(JSThread * thread,JSHandle<JSFunction> constructor,JSHandle<JSTaggedValue> newTarget)841 JSHandle<JSHClass> JSFunction::GetInstanceJSHClass(JSThread *thread, JSHandle<JSFunction> constructor,
842                                                    JSHandle<JSTaggedValue> newTarget)
843 {
844     JSHandle<JSHClass> ctorInitialJSHClass(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
845     // newTarget is construct itself
846     if (newTarget.GetTaggedValue() == constructor.GetTaggedValue()) {
847         return ctorInitialJSHClass;
848     }
849 
850     // newTarget is derived-class of constructor
851     if (newTarget->IsJSFunction()) {
852         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
853         if (newTargetFunc->IsDerivedConstructor()) {
854             JSMutableHandle<JSTaggedValue> mutableNewTarget(thread, newTarget.GetTaggedValue());
855             JSMutableHandle<JSTaggedValue> mutableNewTargetProto(thread, JSTaggedValue::Undefined());
856             while (!mutableNewTargetProto->IsNull()) {
857                 mutableNewTargetProto.Update(JSTaggedValue::GetPrototype(thread, mutableNewTarget));
858                 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread);
859                 if (mutableNewTargetProto.GetTaggedValue() == constructor.GetTaggedValue()) {
860                     return GetOrCreateDerivedJSHClass(thread, newTargetFunc, ctorInitialJSHClass);
861                 }
862                 mutableNewTarget.Update(mutableNewTargetProto.GetTaggedValue());
863             }
864         }
865     }
866 
867     // ECMA2015 9.1.15 3.Let proto be Get(constructor, "prototype").
868     JSMutableHandle<JSTaggedValue> prototype(thread, JSTaggedValue::Undefined());
869     if (newTarget->IsJSFunction()) {
870         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
871         FunctionKind kind = newTargetFunc->GetFunctionKind();
872         if (HasPrototype(kind)) {
873             prototype.Update(PrototypeGetter(thread, JSHandle<JSObject>::Cast(newTargetFunc)));
874         }
875     } else {
876         // Such case: bound function and define a "prototype" property.
877         JSHandle<JSTaggedValue> customizePrototype =
878             JSTaggedValue::GetProperty(thread, newTarget, thread->GlobalConstants()->GetHandledPrototypeString())
879                 .GetValue();
880         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread);
881         prototype.Update(customizePrototype.GetTaggedValue());
882         // Reload JSHClass of constructor, where the lookup of 'prototype' property may change it.
883         ctorInitialJSHClass = JSHandle<JSHClass>(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
884     }
885 
886     if (!prototype->IsECMAObject()) {
887         prototype.Update(constructor->GetFunctionPrototype());
888     }
889 
890     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
891     newJSHClass->SetElementsKind(ElementsKind::GENERIC);
892     newJSHClass->SetPrototype(thread, prototype);
893 
894     return newJSHClass;
895 }
896 
GetOrCreateDerivedJSHClass(JSThread * thread,JSHandle<JSFunction> derived,JSHandle<JSHClass> ctorInitialJSHClass)897 JSHandle<JSHClass> JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle<JSFunction> derived,
898                                                           JSHandle<JSHClass> ctorInitialJSHClass)
899 {
900     JSTaggedValue protoOrHClass(derived->GetProtoOrHClass());
901     // has cached JSHClass, return directly
902     if (protoOrHClass.IsJSHClass()) {
903         return JSHandle<JSHClass>(thread, protoOrHClass);
904     }
905 
906     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
907     newJSHClass->SetElementsKind(ElementsKind::GENERIC);
908     // guarante derived has function prototype
909     JSHandle<JSTaggedValue> prototype(thread, derived->GetProtoOrHClass());
910     ASSERT(!prototype->IsHole());
911     newJSHClass->SetPrototype(thread, prototype);
912     derived->SetProtoOrHClass(thread, newJSHClass);
913 
914     if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
915         thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(derived.GetTaggedType(),
916             newJSHClass.GetTaggedType());
917     }
918 
919     return newJSHClass;
920 }
921 
GetRecordName() const922 CString JSFunction::GetRecordName() const
923 {
924     JSTaggedValue module = GetModule();
925     if (module.IsSourceTextModule()) {
926         return SourceTextModule::GetModuleName(module);
927     }
928     if (module.IsString()) {
929         return ConvertToString(module);
930     }
931     LOG_INTERPRETER(DEBUG) << "record name is undefined";
932     return "";
933 }
934 
935 // Those interface below is discarded
InitializeJSFunction(JSThread * thread,const JSHandle<GlobalEnv> & env,const JSHandle<JSFunction> & func,FunctionKind kind)936 void JSFunction::InitializeJSFunction(JSThread *thread, [[maybe_unused]] const JSHandle<GlobalEnv> &env,
937                                       const JSHandle<JSFunction> &func, FunctionKind kind)
938 {
939     InitializeJSFunction(thread, func, kind);
940 }
941 
NameSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)942 bool JSFunction::NameSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
943                             [[maybe_unused]] bool mayThrow)
944 {
945     if (self->IsPropertiesDict()) {
946         // replace setter with value
947         JSHandle<JSTaggedValue> nameString = thread->GlobalConstants()->GetHandledNameString();
948         return self->UpdatePropertyInDictionary(thread, nameString.GetTaggedValue(), value.GetTaggedValue());
949     }
950     self->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, value.GetTaggedValue());
951     return true;
952 }
953 
954 // NOTE: move to INL file?
SetFunctionLength(const JSThread * thread,JSTaggedValue length)955 void JSFunction::SetFunctionLength(const JSThread *thread, JSTaggedValue length)
956 {
957     ASSERT(!IsPropertiesDict());
958     SetPropertyInlinedProps(thread, LENGTH_INLINE_PROPERTY_INDEX, length);
959 }
960 
SetFunctionExtraInfo(JSThread * thread,void * nativeFunc,const NativePointerCallback & deleter,void * data,size_t nativeBindingsize,Concurrent isConcurrent)961 void JSFunction::SetFunctionExtraInfo(JSThread *thread, void *nativeFunc, const NativePointerCallback &deleter,
962                                       void *data, size_t nativeBindingsize, Concurrent isConcurrent)
963 {
964     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
965     EcmaVM *vm = thread->GetEcmaVM();
966     JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
967     JSHandle<ECMAObject> obj(thread, this);
968     JSHandle<JSNativePointer> pointer = vm->GetFactory()->NewJSNativePointer(nativeFunc, deleter, data,
969         false, nativeBindingsize, isConcurrent);
970     if (!obj->HasHash()) {
971         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
972         return;
973     }
974     if (value->IsHeapObject()) {
975         if (value->IsJSNativePointer()) {
976             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
977             return;
978         }
979         JSHandle<TaggedArray> array(value);
980 
981         uint32_t nativeFieldCount = array->GetExtraLength();
982         if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
983             array->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
984         } else {
985             JSHandle<TaggedArray> newArray = vm->GetFactory()->NewTaggedArray(nativeFieldCount + RESOLVED_MAX_SIZE);
986             newArray->SetExtraLength(nativeFieldCount);
987             for (uint32_t i = 0; i < nativeFieldCount; i++) {
988                 newArray->Set(thread, i, array->Get(i));
989             }
990             newArray->Set(thread, nativeFieldCount + HASH_INDEX, array->Get(nativeFieldCount + HASH_INDEX));
991             newArray->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
992             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
993         }
994     } else {
995         JSHandle<TaggedArray> newArray = vm->GetFactory()->NewTaggedArray(RESOLVED_MAX_SIZE);
996         newArray->SetExtraLength(0);
997         newArray->Set(thread, HASH_INDEX, value);
998         newArray->Set(thread, FUNCTION_EXTRA_INDEX, pointer);
999         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
1000     }
1001 }
1002 
SetSFunctionExtraInfo(JSThread * thread,void * nativeFunc,const NativePointerCallback & deleter,void * data,size_t nativeBindingsize)1003 void JSFunction::SetSFunctionExtraInfo(
1004     JSThread *thread, void *nativeFunc, const NativePointerCallback &deleter, void *data, size_t nativeBindingsize)
1005 {
1006     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
1007     EcmaVM *vm = thread->GetEcmaVM();
1008     JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
1009     JSHandle<ECMAObject> obj(thread, this);
1010     JSHandle<JSNativePointer> pointer =
1011         vm->GetFactory()->NewSJSNativePointer(nativeFunc, deleter, data, false, nativeBindingsize);
1012     if (!obj->HasHash()) {
1013         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
1014         return;
1015     }
1016     if (value->IsHeapObject()) {
1017         if (value->IsJSNativePointer()) {
1018             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
1019             return;
1020         }
1021         JSHandle<TaggedArray> array(value);
1022 
1023         uint32_t nativeFieldCount = array->GetExtraLength();
1024         if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
1025             array->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
1026         } else {
1027             JSHandle<TaggedArray> newArray =
1028                 vm->GetFactory()->NewSTaggedArrayWithoutInit(nativeFieldCount + RESOLVED_MAX_SIZE);
1029             newArray->SetExtraLength(nativeFieldCount);
1030             for (uint32_t i = 0; i < nativeFieldCount; i++) {
1031                 newArray->Set(thread, i, array->Get(i));
1032             }
1033             newArray->Set(thread, nativeFieldCount + HASH_INDEX, array->Get(nativeFieldCount + HASH_INDEX));
1034             newArray->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
1035             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
1036         }
1037     } else {
1038         JSHandle<TaggedArray> newArray = vm->GetFactory()->NewSTaggedArrayWithoutInit(RESOLVED_MAX_SIZE);
1039         newArray->SetExtraLength(0);
1040         newArray->Set(thread, HASH_INDEX, value);
1041         newArray->Set(thread, FUNCTION_EXTRA_INDEX, pointer);
1042         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
1043     }
1044 }
1045 
SetProfileTypeInfo(const JSThread * thread,const JSHandle<JSFunction> & func,const JSHandle<JSTaggedValue> & value,BarrierMode mode)1046 void JSFunction::SetProfileTypeInfo(const JSThread *thread, const JSHandle<JSFunction> &func,
1047                                     const JSHandle<JSTaggedValue> &value, BarrierMode mode)
1048 {
1049     JSHandle<ProfileTypeInfoCell> handleRaw(thread, func->GetRawProfileTypeInfo());
1050     if (handleRaw->IsEmptyProfileTypeInfoCell(thread)) {
1051         JSHandle<ProfileTypeInfoCell> handleProfileTypeInfoCell =
1052             thread->GetEcmaVM()->GetFactory()->NewProfileTypeInfoCell(value);
1053         func->SetRawProfileTypeInfo(thread, handleProfileTypeInfoCell, WRITE_BARRIER);
1054         return;
1055     }
1056     handleRaw->SetValue(thread, value, mode);
1057 }
1058 
UpdateProfileTypeInfoCell(JSThread * thread,JSHandle<FunctionTemplate> literalFunc,JSHandle<JSFunction> targetFunc)1059 void JSFunction::UpdateProfileTypeInfoCell(JSThread *thread, JSHandle<FunctionTemplate> literalFunc,
1060                                            JSHandle<JSFunction> targetFunc)
1061 {
1062     auto profileTypeInfoCellVal = literalFunc->GetRawProfileTypeInfo();
1063     ASSERT(profileTypeInfoCellVal.IsProfileTypeInfoCell());
1064     auto profileTypeInfoCell = ProfileTypeInfoCell::Cast(profileTypeInfoCellVal);
1065     if (profileTypeInfoCell->IsEmptyProfileTypeInfoCell(thread)) {
1066         JSHandle<JSTaggedValue> handleUndefined(thread, JSTaggedValue::Undefined());
1067         JSHandle<ProfileTypeInfoCell> newProfileTypeInfoCell =
1068             thread->GetEcmaVM()->GetFactory()->NewProfileTypeInfoCell(handleUndefined);
1069         literalFunc->SetRawProfileTypeInfo(thread, newProfileTypeInfoCell);
1070         targetFunc->SetRawProfileTypeInfo(thread, newProfileTypeInfoCell);
1071     } else {
1072         ProfileTypeInfoCell::Cast(profileTypeInfoCell)->UpdateProfileTypeInfoCellType(thread);
1073         targetFunc->SetRawProfileTypeInfo(thread, profileTypeInfoCellVal);
1074     }
1075 }
1076 
SetJitMachineCodeCache(const JSThread * thread,const JSHandle<MachineCode> & machineCode)1077 void JSFunction::SetJitMachineCodeCache(const JSThread *thread, const JSHandle<MachineCode> &machineCode)
1078 {
1079     JSHandle<ProfileTypeInfoCell> handleRaw(thread, GetRawProfileTypeInfo());
1080     ASSERT(!handleRaw->IsEmptyProfileTypeInfoCell(thread));
1081     handleRaw->SetMachineCode(thread, machineCode.GetTaggedValue().CreateAndGetWeakRef(), WRITE_BARRIER);
1082 }
1083 
GetFunctionExtraInfo() const1084 JSTaggedValue JSFunction::GetFunctionExtraInfo() const
1085 {
1086     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
1087     JSTaggedValue value(hashField);
1088     if (value.IsHeapObject()) {
1089         if (value.IsTaggedArray()) {
1090             TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
1091             uint32_t nativeFieldCount = array->GetExtraLength();
1092             if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
1093                 return array->Get(nativeFieldCount + FUNCTION_EXTRA_INDEX);
1094             }
1095         }
1096         if (value.IsJSNativePointer()) {
1097             return value;
1098         }
1099         JSType valueType = value.GetTaggedObject()->GetClass()->GetObjectType();
1100         JSType thisType = this->GetClass()->GetObjectType();
1101         LOG_ECMA(FATAL) << "this branch is unreachable, thisType is " << static_cast<uint8_t>(thisType)
1102                         << ", value type is " << static_cast<uint8_t>(valueType);
1103         UNREACHABLE();
1104     }
1105     return JSTaggedValue::Undefined();
1106 }
1107 
GetNativeFunctionExtraInfo() const1108 JSTaggedValue JSFunction::GetNativeFunctionExtraInfo() const
1109 {
1110     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
1111     JSTaggedValue value(hashField);
1112     if (value.CheckIsJSNativePointer()) {
1113         return value;
1114     }
1115     return JSTaggedValue::Undefined();
1116 }
1117 
InitializeForConcurrentFunction(JSThread * thread,JSHandle<JSFunction> & func)1118 void JSFunction::InitializeForConcurrentFunction(JSThread *thread, JSHandle<JSFunction> &func)
1119 {
1120     JSHandle<Method> method(thread, func->GetMethod());
1121     JSMutableHandle<JSTaggedValue> sendableEnv(thread, JSTaggedValue::Undefined());
1122     if (func->IsSharedFunction() && !func->GetModule().IsUndefined()) {
1123         sendableEnv.Update(SourceTextModule::Cast(func->GetModule())->GetSendableEnv());
1124     }
1125     const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
1126     if (jsPandaFile == nullptr) {
1127         LOG_ECMA(ERROR) << "JSPandaFile is nullptr";
1128         return;
1129     }
1130     ecmascript::CString moduleName = jsPandaFile->GetJSPandaFileDesc();
1131     ecmascript::CString recordName = method->GetRecordNameStr();
1132 
1133     // check ESM or CJS
1134     ecmascript::JSRecordInfo *recordInfo = nullptr;
1135     bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(recordName, &recordInfo);
1136     if (!hasRecord) {
1137         CString msg = "Cannot find module '" + recordName + "' , which is application Entry Point";
1138         LOG_ECMA(ERROR) << msg;
1139         return;
1140     }
1141     if (!jsPandaFile->IsModule(recordInfo)) {
1142         LOG_ECMA(DEBUG) << "Current function is not from ES Module's file.";
1143         return;
1144     }
1145     ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
1146     JSHandle<ecmascript::JSTaggedValue> moduleRecord;
1147     // check compileMode
1148     if (jsPandaFile->IsBundlePack()) {
1149         LOG_ECMA(DEBUG) << "CompileMode is jsbundle";
1150         moduleRecord = moduleManager->HostResolveImportedModule(moduleName);
1151     } else {
1152         LOG_ECMA(DEBUG) << "CompileMode is esmodule";
1153         moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(moduleName, recordName);
1154     }
1155     RETURN_IF_ABRUPT_COMPLETION(thread);
1156     ecmascript::SourceTextModule::Instantiate(thread, moduleRecord);
1157     JSHandle<ecmascript::SourceTextModule> module = JSHandle<ecmascript::SourceTextModule>::Cast(moduleRecord);
1158     module->SetStatus(ecmascript::ModuleStatus::INSTANTIATED);
1159     ecmascript::SourceTextModule::EvaluateForConcurrent(thread, module, method);
1160     if (!jsPandaFile->IsBundlePack() && func->IsSharedFunction()) {
1161         JSHandle<JSTaggedValue> sendableClassRecord = moduleManager->GenerateSendableFuncModule(moduleRecord);
1162         SourceTextModule::Cast(sendableClassRecord.GetTaggedValue())->SetSendableEnv(thread, sendableEnv);
1163         func->SetModule(thread, sendableClassRecord);
1164     } else {
1165         func->SetModule(thread, moduleRecord);
1166     }
1167 
1168     // for debugger, to notify the script loaded and parsed which the concurrent function is in
1169     auto *notificationMgr = thread->GetEcmaVM()->GetJsDebuggerManager()->GetNotificationManager();
1170     notificationMgr->LoadModuleEvent(moduleName, recordName);
1171 }
1172 
IsSendableOrConcurrentFunction() const1173 bool JSFunction::IsSendableOrConcurrentFunction() const
1174 {
1175     if (this->GetClass()->IsJSSharedFunction() || this->GetClass()->IsJSSharedAsyncFunction() ||
1176         this->GetFunctionKind() == ecmascript::FunctionKind::CONCURRENT_FUNCTION) {
1177         return true;
1178     }
1179     return false;
1180 }
1181 
IsSharedFunction() const1182 bool JSFunction::IsSharedFunction() const
1183 {
1184     if (this->GetClass()->IsJSSharedFunction() || this->GetClass()->IsJSSharedAsyncFunction()) {
1185         return true;
1186     }
1187     return false;
1188 }
1189 
SetCompiledFuncEntry(uintptr_t codeEntry,bool isFastCall)1190 void JSFunctionBase::SetCompiledFuncEntry(uintptr_t codeEntry, bool isFastCall)
1191 {
1192     ASSERT(codeEntry != 0);
1193     SetCodeEntry(codeEntry);
1194     SetIsCompiledFastCall(isFastCall);
1195     SetCompiledCodeBit(true);
1196 }
1197 
SetJitCompiledFuncEntry(JSThread * thread,JSHandle<MachineCode> & machineCode,bool isFastCall)1198 void JSFunction::SetJitCompiledFuncEntry(JSThread *thread, JSHandle<MachineCode> &machineCode, bool isFastCall)
1199 {
1200     uintptr_t codeEntry = machineCode->GetFuncAddr();
1201     ASSERT(codeEntry != 0);
1202 
1203     SetMachineCode(thread, machineCode);
1204     SetCompiledFuncEntry(codeEntry, isFastCall);
1205 }
1206 
ClearCompiledCodeFlags()1207 void JSFunctionBase::ClearCompiledCodeFlags()
1208 {
1209     SetCompiledCodeBit(false);
1210     SetIsCompiledFastCall(false);
1211 }
1212 
1213 }  // namespace panda::ecmascript
1214