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