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