• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/js_function.h"
17 
18 #include "ecmascript/base/error_type.h"
19 #include "ecmascript/ecma_macros.h"
20 #include "ecmascript/ecma_runtime_call_info.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/interpreter/interpreter-inl.h"
23 #include "ecmascript/js_hclass.h"
24 #include "ecmascript/js_tagged_value.h"
25 #include "ecmascript/jspandafile/class_info_extractor.h"
26 #include "ecmascript/js_handle.h"
27 #include "ecmascript/js_promise.h"
28 #include "ecmascript/js_tagged_value-inl.h"
29 #include "ecmascript/mem/c_containers.h"
30 #include "ecmascript/module/js_module_source_text.h"
31 #include "ecmascript/object_factory.h"
32 #include "ecmascript/tagged_array.h"
33 #include "ecmascript/require/js_require_manager.h"
34 
35 namespace panda::ecmascript {
InitializeJSFunction(JSThread * thread,const JSHandle<JSFunction> & func,FunctionKind kind)36 void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle<JSFunction> &func, FunctionKind kind)
37 {
38     func->SetProtoOrHClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER);
39     func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
40     func->SetWorkNodePointer(reinterpret_cast<uintptr_t>(nullptr));
41     func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
42     func->SetMethod(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
43 
44     auto globalConst = thread->GlobalConstants();
45     if (HasPrototype(kind)) {
46         JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionPrototypeAccessor();
47         if (kind == FunctionKind::BASE_CONSTRUCTOR || kind == FunctionKind::GENERATOR_FUNCTION ||
48             kind == FunctionKind::ASYNC_GENERATOR_FUNCTION || kind == FunctionKind::NONE_FUNCTION) {
49             func->SetPropertyInlinedProps(thread, PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
50             accessor = globalConst->GetHandledFunctionNameAccessor();
51             func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
52             accessor = globalConst->GetHandledFunctionLengthAccessor();
53             func->SetPropertyInlinedProps(thread, LENGTH_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
54             if (kind == FunctionKind::ASYNC_GENERATOR_FUNCTION) {
55                 // Not duplicate codes, it will slow the performace if combining and put outside!
56                 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
57                 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
58                 JSHandle<JSFunction> objFun(env->GetObjectFunction());
59                 JSHandle<JSObject> initialGeneratorFuncPrototype = factory->NewJSObjectByConstructor(objFun);
60                 JSObject::SetPrototype(thread, initialGeneratorFuncPrototype, env->GetAsyncGeneratorPrototype());
61                 func->SetProtoOrHClass(thread, initialGeneratorFuncPrototype);
62             }
63             if (kind == FunctionKind::GENERATOR_FUNCTION) {
64                 // Not duplicate codes, it will slow the performace if combining and put outside!
65                 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
66                 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
67                 JSHandle<JSFunction> objFun(env->GetObjectFunction());
68                 JSHandle<JSObject> initialGeneratorFuncPrototype = factory->NewJSObjectByConstructor(objFun);
69                 JSObject::SetPrototype(thread, initialGeneratorFuncPrototype, env->GetGeneratorPrototype());
70                 func->SetProtoOrHClass(thread, initialGeneratorFuncPrototype);
71             }
72         } else if (!JSFunction::IsClassConstructor(kind)) {  // class ctor do nothing
73             PropertyDescriptor desc(thread, accessor, kind != FunctionKind::BUILTIN_CONSTRUCTOR, false, false);
74             [[maybe_unused]] bool success = JSObject::DefineOwnProperty(
75                 thread, JSHandle<JSObject>(func), globalConst->GetHandledPrototypeString(), desc, SCheckMode::SKIP);
76             ASSERT(success);
77         }
78     } else if (HasAccessor(kind)) {
79         JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionNameAccessor();
80         func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
81         accessor = globalConst->GetHandledFunctionLengthAccessor();
82         func->SetPropertyInlinedProps(thread, LENGTH_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
83     }
84 }
85 
NewJSFunctionPrototype(JSThread * thread,const JSHandle<JSFunction> & func)86 JSHandle<JSObject> JSFunction::NewJSFunctionPrototype(JSThread *thread, const JSHandle<JSFunction> &func)
87 {
88     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
89     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
90     JSHandle<JSFunction> objFun(env->GetObjectFunction());
91     JSHandle<JSObject> funPro = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(objFun);
92     SetFunctionPrototypeOrInstanceHClass(thread, func, funPro.GetTaggedValue());
93 
94     // set "constructor" in prototype
95     JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
96     PropertyDescriptor descriptor(thread, JSHandle<JSTaggedValue>::Cast(func), true, false, true);
97     JSObject::DefineOwnProperty(thread, funPro, constructorKey, descriptor);
98 
99     return funPro;
100 }
101 
GetOrCreateInitialJSHClass(JSThread * thread,const JSHandle<JSFunction> & fun)102 JSHClass *JSFunction::GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle<JSFunction> &fun)
103 {
104     JSTaggedValue protoOrHClass(fun->GetProtoOrHClass());
105     if (protoOrHClass.IsJSHClass()) {
106         return reinterpret_cast<JSHClass *>(protoOrHClass.GetTaggedObject());
107     }
108 
109     JSHandle<JSTaggedValue> proto;
110     if (!fun->HasFunctionPrototype()) {
111         proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, fun));
112         if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
113             thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(fun.GetTaggedType(),
114                 JSTaggedType(proto->GetTaggedObject()->GetClass()), pgo::ProfileType::Kind::PrototypeId);
115         }
116     } else {
117         proto = JSHandle<JSTaggedValue>(thread, fun->GetProtoOrHClass());
118     }
119 
120     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
121     JSHandle<JSHClass> hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, proto);
122     fun->SetProtoOrHClass(thread, hclass);
123     if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
124         thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(fun.GetTaggedType(), hclass.GetTaggedType());
125     }
126     return *hclass;
127 }
128 
PrototypeGetter(JSThread * thread,const JSHandle<JSObject> & self)129 JSTaggedValue JSFunction::PrototypeGetter(JSThread *thread, const JSHandle<JSObject> &self)
130 {
131     JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(self);
132     if (!func->HasFunctionPrototype()) {
133         JSHandle<JSTaggedValue> proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, func));
134         if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
135             thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(func.GetTaggedType(),
136                 JSTaggedType(proto->GetTaggedObject()->GetClass()), pgo::ProfileType::Kind::PrototypeId);
137         }
138     }
139     return JSFunction::Cast(*self)->GetFunctionPrototype();
140 }
141 
PrototypeSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)142 bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
143                                  [[maybe_unused]] bool mayThrow)
144 {
145     JSHandle<JSFunction> func(self);
146     JSTaggedValue protoOrHClass = func->GetProtoOrHClass();
147     if (protoOrHClass.IsJSHClass()) {
148         // need transition
149         JSHandle<JSTaggedValue> hclass(thread, protoOrHClass);
150         JSHandle<JSTaggedValue> newClass = JSHClass::SetPrototypeWithNotification(thread, hclass, value);
151         func->SetProtoOrHClass(thread, newClass);
152     } else {
153         SetFunctionPrototypeOrInstanceHClass(thread, func, value.GetTaggedValue());
154     }
155     return true;
156 }
157 
SetFunctionPrototypeOrInstanceHClass(const JSThread * thread,const JSHandle<JSFunction> & fun,JSTaggedValue protoOrHClass)158 void JSFunction::SetFunctionPrototypeOrInstanceHClass(const JSThread *thread, const JSHandle<JSFunction> &fun,
159                                                       JSTaggedValue protoOrHClass)
160 {
161     JSHandle<JSTaggedValue> protoHandle(thread, protoOrHClass);
162     fun->SetProtoOrHClass(thread, protoHandle.GetTaggedValue());
163     if (protoHandle->IsJSHClass()) {
164         protoHandle = JSHandle<JSTaggedValue>(thread,
165                                               JSHClass::Cast(protoHandle->GetTaggedObject())->GetPrototype());
166     }
167     if (protoHandle->IsECMAObject()) {
168         JSHClass::OptimizePrototypeForIC(thread, protoHandle);
169     }
170 }
171 
NameGetter(JSThread * thread,const JSHandle<JSObject> & self)172 JSTaggedValue JSFunction::NameGetter(JSThread *thread, const JSHandle<JSObject> &self)
173 {
174     if (self->IsBoundFunction()) {
175         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
176         const GlobalEnvConstants *globalConst = thread->GlobalConstants();
177         JSHandle<JSBoundFunction> boundFunction(self);
178         JSHandle<JSTaggedValue> target(thread, boundFunction->GetBoundTarget());
179 
180         JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
181         JSHandle<JSTaggedValue> boundName = thread->GlobalConstants()->GetHandledBoundString();
182         JSHandle<JSTaggedValue> targetName = JSObject::GetProperty(thread, target, nameKey).GetValue();
183 
184         JSHandle<EcmaString> handlePrefixString = JSTaggedValue::ToString(thread, boundName);
185         JSHandle<EcmaString> spaceString(globalConst->GetHandledSpaceString());
186         JSHandle<EcmaString> concatString = factory->ConcatFromString(handlePrefixString, spaceString);
187 
188         EcmaString *newString;
189         if (!targetName->IsString()) {
190             JSHandle<EcmaString> emptyString = factory->GetEmptyString();
191             newString = *factory->ConcatFromString(concatString, emptyString);
192         } else {
193             JSHandle<EcmaString> functionName = JSHandle<EcmaString>::Cast(targetName);
194             newString = *factory->ConcatFromString(concatString, functionName);
195         }
196 
197         return JSTaggedValue(newString);
198     }
199 
200     JSTaggedValue method = JSHandle<JSFunction>::Cast(self)->GetMethod();
201     if (method.IsUndefined()) {
202         return JSTaggedValue::Undefined();
203     }
204     Method *target = Method::Cast(method.GetTaggedObject());
205     if (target->IsNativeWithCallField()) {
206         return JSTaggedValue::Undefined();
207     }
208     std::string funcName = target->ParseFunctionName();
209     if (funcName.empty()) {
210         return thread->GlobalConstants()->GetEmptyString();
211     }
212     if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::GETTER_FUNCTION) {
213         funcName.insert(0, "get ");
214     }
215     if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::SETTER_FUNCTION) {
216         funcName.insert(0, "set ");
217     }
218 
219     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
220     return factory->NewFromStdString(funcName).GetTaggedValue();
221 }
222 
LengthGetter(JSThread * thread,const JSHandle<JSObject> & self)223 JSTaggedValue JSFunction::LengthGetter(JSThread *thread, const JSHandle<JSObject> &self)
224 {
225     // LengthGetter only support BoundFunction
226     if (self->IsBoundFunction()) {
227         JSMutableHandle<JSBoundFunction> boundFunction(thread, self.GetTaggedValue());
228         JSHandle<JSTaggedValue> arguments(thread, boundFunction->GetBoundArguments());
229         uint32_t argsLength = TaggedArray::Cast(arguments->GetTaggedObject())->GetLength();
230         while (boundFunction->GetBoundTarget().IsBoundFunction()) {
231             boundFunction.Update(boundFunction->GetBoundTarget());
232             argsLength += TaggedArray::Cast(boundFunction->GetBoundArguments())->GetLength();
233         }
234 
235         JSHandle<JSTaggedValue> target(thread, boundFunction->GetBoundTarget());
236         JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
237 
238         bool targetHasLength =
239             JSTaggedValue::HasOwnProperty(thread, target, lengthKey);
240         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
241         uint32_t lengthValue = 0;
242         if (targetHasLength) {
243             JSHandle<JSTaggedValue> targetLength = JSTaggedValue::GetProperty(thread, target, lengthKey).GetValue();
244             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
245             if (targetLength->IsNumber()) {
246                 lengthValue =
247                     std::max(0u, static_cast<uint32_t>(JSTaggedValue::ToNumber(thread, targetLength).GetNumber()) -
248                              argsLength);
249                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
250             }
251         }
252         return JSTaggedValue(lengthValue);
253     }
254 
255     JSHandle<JSFunction> func(self);
256     return JSTaggedValue(func->GetLength());
257 }
258 
OrdinaryHasInstance(JSThread * thread,const JSHandle<JSTaggedValue> & constructor,const JSHandle<JSTaggedValue> & obj)259 bool JSFunction::OrdinaryHasInstance(JSThread *thread, const JSHandle<JSTaggedValue> &constructor,
260                                      const JSHandle<JSTaggedValue> &obj)
261 {
262     // 1. If IsCallable(C) is false, return false.
263     if (!constructor->IsCallable()) {
264         return false;
265     }
266 
267     // 2. If C has a [[BoundTargetFunction]] internal slot, then
268     //    a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
269     //    b. Return InstanceofOperator(O,BC)  (see 12.9.4).
270     if (constructor->IsBoundFunction()) {
271         STACK_LIMIT_CHECK(thread, false);
272         JSHandle<JSBoundFunction> boundFunction(thread, JSBoundFunction::Cast(constructor->GetTaggedObject()));
273         JSTaggedValue boundTarget = boundFunction->GetBoundTarget();
274         return JSObject::InstanceOf(thread, obj, JSHandle<JSTaggedValue>(thread, boundTarget));
275     }
276     // 3. If Type(O) is not Object, return false
277     if (!obj->IsECMAObject()) {
278         return false;
279     }
280 
281     // 4. Let P be Get(C, "prototype").
282     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
283     JSHandle<JSTaggedValue> prototypeString = globalConst->GetHandledPrototypeString();
284     JSMutableHandle<JSTaggedValue> constructorPrototype(thread, JSTaggedValue::Undefined());
285     if (constructor->IsJSFunction()) {
286         JSHandle<JSFunction> ctor(thread, constructor->GetTaggedObject());
287         JSHandle<JSTaggedValue> ctorProtoOrHclass(thread, ctor->GetProtoOrHClass());
288         if (!ctorProtoOrHclass->IsHole()) {
289             if (!ctorProtoOrHclass->IsJSHClass()) {
290                 constructorPrototype.Update(ctorProtoOrHclass);
291             } else {
292                 JSTaggedValue ctorProto = JSHClass::Cast(ctorProtoOrHclass->GetTaggedObject())->GetProto();
293                 constructorPrototype.Update(ctorProto);
294             }
295         } else {
296             constructorPrototype.Update(JSTaggedValue::GetProperty(thread, constructor, prototypeString).GetValue());
297         }
298     } else {
299         constructorPrototype.Update(JSTaggedValue::GetProperty(thread, constructor, prototypeString).GetValue());
300     }
301 
302     // 5. ReturnIfAbrupt(P).
303     // no throw exception, so needn't return
304     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
305 
306     // 6. If Type(P) is not Object, throw a TypeError exception.
307     if (!constructorPrototype->IsECMAObject()) {
308         THROW_TYPE_ERROR_AND_RETURN(thread, "HasInstance: is not Object", false);
309     }
310 
311     // 7. Repeat
312     //    a.Let O be O.[[GetPrototypeOf]]().
313     //    b.ReturnIfAbrupt(O).
314     //    c.If O is null, return false.
315     //    d.If SameValue(P, O) is true, return true.
316     JSMutableHandle<JSTaggedValue> object(thread, obj.GetTaggedValue());
317     while (!object->IsNull()) {
318         if (JSTaggedValue::SameValue(object, constructorPrototype)) {
319             return true;
320         }
321         object.Update(JSTaggedValue::GetPrototype(thread, object));
322         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
323     }
324     return false;
325 }
326 
MakeConstructor(JSThread * thread,const JSHandle<JSFunction> & func,const JSHandle<JSTaggedValue> & proto,bool writable)327 bool JSFunction::MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &func,
328                                  const JSHandle<JSTaggedValue> &proto, bool writable)
329 {
330     ASSERT_PRINT(proto->IsHeapObject() || proto->IsUndefined(), "proto must be JSObject or Undefined");
331     ASSERT_PRINT(func->IsConstructor(), "func must be Constructor type");
332     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
333     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
334     JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
335 
336     ASSERT_PRINT(func->GetProtoOrHClass().IsHole() && func->IsExtensible(),
337                  "function doesn't has proto_type property and is extensible object");
338     ASSERT_PRINT(JSObject::HasProperty(thread, JSHandle<JSObject>(func), constructorKey),
339                  "function must have constructor");
340 
341     // proto.constructor = func
342     bool status = false;
343     if (proto->IsUndefined()) {
344         // Let prototype be ObjectCreate(%ObjectPrototype%).
345         JSHandle<JSTaggedValue> objPrototype = env->GetObjectFunctionPrototype();
346         PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
347         status = JSTaggedValue::DefinePropertyOrThrow(thread, objPrototype, constructorKey, constructorDesc);
348     } else {
349         PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
350         status = JSTaggedValue::DefinePropertyOrThrow(thread, proto, constructorKey, constructorDesc);
351     }
352     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
353 
354     ASSERT_PRINT(status, "DefineProperty construct failed");
355     // func.prototype = proto
356     // Let status be DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]:
357     // prototype, [[Writable]]: writablePrototype, [[Enumerable]]: false, [[Configurable]]: false}).
358     SetFunctionPrototypeOrInstanceHClass(thread, func, proto.GetTaggedValue());
359 
360     ASSERT_PRINT(status, "DefineProperty proto_type failed");
361     return status;
362 }
363 
Call(EcmaRuntimeCallInfo * info)364 JSTaggedValue JSFunction::Call(EcmaRuntimeCallInfo *info)
365 {
366     if (info == nullptr) {
367         return JSTaggedValue::Exception();
368     }
369 
370     JSThread *thread = info->GetThread();
371     // 1. ReturnIfAbrupt(F).
372     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
373     JSHandle<JSTaggedValue> func = info->GetFunction();
374     // 2. If argumentsList was not passed, let argumentsList be a new empty List.
375     // 3. If IsCallable(F) is false, throw a TypeError exception.
376     if (!func->IsCallable()) {
377         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
378         THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
379     }
380 
381     auto *hclass = func->GetTaggedObject()->GetClass();
382     if (hclass->IsClassConstructor()) {
383         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
384         THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", JSTaggedValue::Exception());
385     }
386     return EcmaInterpreter::Execute(info);
387 }
388 
Construct(EcmaRuntimeCallInfo * info)389 JSTaggedValue JSFunction::Construct(EcmaRuntimeCallInfo *info)
390 {
391     if (info == nullptr) {
392         return JSTaggedValue::Exception();
393     }
394 
395     JSThread *thread = info->GetThread();
396     JSHandle<JSTaggedValue> func(info->GetFunction());
397     JSHandle<JSTaggedValue> target = info->GetNewTarget();
398     if (target->IsUndefined()) {
399         target = func;
400         info->SetNewTarget(target.GetTaggedValue());
401     }
402     if (!(func->IsConstructor() && target->IsConstructor())) {
403         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
404         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
405     }
406 
407     if (func->IsJSFunction()) {
408         return JSFunction::ConstructInternal(info);
409     } else if (func->IsJSProxy()) {
410         return JSProxy::ConstructInternal(info);
411     } else {
412         ASSERT(func->IsBoundFunction());
413         return JSBoundFunction::ConstructInternal(info);
414     }
415 }
416 
Invoke(EcmaRuntimeCallInfo * info,const JSHandle<JSTaggedValue> & key)417 JSTaggedValue JSFunction::Invoke(EcmaRuntimeCallInfo *info, const JSHandle<JSTaggedValue> &key)
418 {
419     if (info == nullptr) {
420         return JSTaggedValue::Exception();
421     }
422 
423     ASSERT(JSTaggedValue::IsPropertyKey(key));
424     JSThread *thread = info->GetThread();
425     JSHandle<JSTaggedValue> thisArg = info->GetThis();
426     JSHandle<JSTaggedValue> func(JSTaggedValue::GetProperty(thread, thisArg, key).GetValue());
427     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
428     info->SetFunction(func.GetTaggedValue());
429     return JSFunction::Call(info);
430 }
431 
InvokeOptimizedEntrypoint(JSThread * thread,JSHandle<JSFunction> mainFunc,JSHandle<JSTaggedValue> & thisArg,std::string_view entryPoint,CJSInfo * cjsInfo)432 JSTaggedValue JSFunction::InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<JSFunction> mainFunc,
433     JSHandle<JSTaggedValue> &thisArg, std::string_view entryPoint, CJSInfo* cjsInfo)
434 {
435     if (mainFunc->IsClassConstructor()) {
436         {
437             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
438             JSHandle<JSObject> error =
439                 factory->GetJSError(ErrorType::TYPE_ERROR, "class constructor cannot called without 'new'");
440             thread->SetException(error.GetTaggedValue());
441         }
442         return thread->GetException();
443     }
444     Method *method = mainFunc->GetCallTarget();
445     size_t actualNumArgs = method->GetNumArgs();
446     const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
447     JSTaggedValue res;
448     std::vector<JSTaggedType> args;
449 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
450     RuntimeStubs::StartCallTimer(thread->GetGlueAddr(), mainFunc.GetTaggedType(), true);
451 #endif
452     if (method->IsFastCall()) {
453         // do not modify this log to INFO, this will call many times
454         LOG_ECMA(DEBUG) << "start to execute aot entry: " << entryPoint;
455         args = JSFunction::GetArgsData(true, thisArg, mainFunc, cjsInfo);
456         res = thread->GetEcmaVM()->FastCallAot(actualNumArgs, args.data(), prevFp);
457     } else {
458         args = JSFunction::GetArgsData(false, thisArg, mainFunc, cjsInfo);
459         // do not modify this log to INFO, this will call many times
460         LOG_ECMA(DEBUG) << "start to execute aot entry: " << entryPoint;
461         res = thread->GetCurrentEcmaContext()->ExecuteAot(actualNumArgs, args.data(), prevFp, false);
462     }
463 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
464     RuntimeStubs::EndCallTimer(thread->GetGlueAddr(), mainFunc.GetTaggedType());
465 #endif
466     if (thread->HasPendingException()) {
467         return thread->GetException();
468     }
469     return res;
470 }
471 
GetArgsData(bool isFastCall,JSHandle<JSTaggedValue> & thisArg,JSHandle<JSFunction> mainFunc,CJSInfo * cjsInfo)472 std::vector<JSTaggedType> JSFunction::GetArgsData(bool isFastCall, JSHandle<JSTaggedValue> &thisArg,
473     JSHandle<JSFunction> mainFunc, CJSInfo* cjsInfo)
474 {
475     size_t argsNum;
476     uint32_t mandatoryNum;
477     Method *method = mainFunc->GetCallTarget();
478     size_t actualNumArgs = method->GetNumArgs();
479     if (isFastCall) {
480         argsNum = actualNumArgs + NUM_MANDATORY_JSFUNC_ARGS - 1;
481         mandatoryNum = NUM_MANDATORY_JSFUNC_ARGS - 1;
482     } else {
483         argsNum = actualNumArgs + NUM_MANDATORY_JSFUNC_ARGS;
484         mandatoryNum = NUM_MANDATORY_JSFUNC_ARGS;
485     }
486     std::vector<JSTaggedType> args(argsNum, JSTaggedValue::Undefined().GetRawData());
487     args[0] = mainFunc.GetTaggedValue().GetRawData();
488     if (isFastCall) {
489         args[1] = thisArg.GetTaggedValue().GetRawData(); // 1: args number
490     } else {
491         args[2] = thisArg.GetTaggedValue().GetRawData(); // 2: args number
492     }
493     if (cjsInfo != nullptr) {
494         args[mandatoryNum++] = cjsInfo->exportsHdl.GetTaggedValue().GetRawData();
495         args[mandatoryNum++] = cjsInfo->requireHdl.GetTaggedValue().GetRawData();
496         args[mandatoryNum++] = cjsInfo->moduleHdl.GetTaggedValue().GetRawData();
497         args[mandatoryNum++] = cjsInfo->filenameHdl.GetTaggedValue().GetRawData();
498         args[mandatoryNum] = cjsInfo->dirnameHdl.GetTaggedValue().GetRawData();
499     }
500     return args;
501 }
502 
InvokeOptimizedEntrypoint(JSThread * thread,JSHandle<JSFunction> func,EcmaRuntimeCallInfo * info)503 JSTaggedValue JSFunction::InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<JSFunction> func,
504     EcmaRuntimeCallInfo *info)
505 {
506     Method *method = func->GetCallTarget();
507     JSTaggedValue resultValue;
508     uint32_t numArgs = method->GetNumArgsWithCallField();
509     bool needPushUndefined = numArgs > info->GetArgsNumber();
510     const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
511 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
512     RuntimeStubs::StartCallTimer(thread->GetGlueAddr(), func.GetTaggedType(), true);
513 #endif
514     if (method->IsFastCall()) {
515         if (needPushUndefined) {
516             info = EcmaInterpreter::ReBuildRuntimeCallInfo(thread, info, numArgs);
517             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
518         }
519         JSTaggedType *stackArgs = info->GetArgs();
520         stackArgs[1] = stackArgs[0];
521         resultValue = thread->GetEcmaVM()->FastCallAot(info->GetArgsNumber(), stackArgs + 1, prevFp);
522     } else {
523         resultValue = thread->GetCurrentEcmaContext()->ExecuteAot(info->GetArgsNumber(),
524             info->GetArgs(), prevFp, needPushUndefined);
525     }
526 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
527     RuntimeStubs::EndCallTimer(thread->GetGlueAddr(), func.GetTaggedType());
528 #endif
529     return resultValue;
530 }
531 
532 // [[Construct]]
ConstructInternal(EcmaRuntimeCallInfo * info)533 JSTaggedValue JSFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
534 {
535     if (info == nullptr) {
536         return JSTaggedValue::Exception();
537     }
538 
539     JSThread *thread = info->GetThread();
540     JSHandle<JSFunction> func(info->GetFunction());
541     JSHandle<JSTaggedValue> newTarget(info->GetNewTarget());
542     ASSERT(newTarget->IsECMAObject());
543     if (!func->IsConstructor()) {
544         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
545         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
546     }
547 
548     JSHandle<JSTaggedValue> obj(thread, JSTaggedValue::Undefined());
549     if (func->IsBase()) {
550         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
551         obj = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(func, newTarget));
552         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
553     }
554 
555     JSTaggedValue resultValue;
556     info->SetThis(obj.GetTaggedValue());
557     Method *method = func->GetCallTarget();
558     if (method->IsAotWithCallField() && func->IsClassConstructor()) {
559         resultValue = InvokeOptimizedEntrypoint(thread, func, info);
560         const JSTaggedType *curSp = thread->GetCurrentSPFrame();
561         InterpretedEntryFrame *entryState = InterpretedEntryFrame::GetFrameFromSp(curSp);
562         JSTaggedType *prevSp = entryState->base.prev;
563         thread->SetCurrentSPFrame(prevSp);
564     } else {
565         method->SetAotCodeBit(false); // if Construct is not ClassConstructor, don't run aot
566         resultValue = EcmaInterpreter::Execute(info);
567     }
568     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
569     // 9.3.2 [[Construct]] (argumentsList, newTarget)
570     if (resultValue.IsECMAObject()) {
571         return resultValue;
572     }
573 
574     if (func->IsBase()) {
575         return obj.GetTaggedValue();
576     }
577 
578     // derived ctor(sub class) return the obj which created by base ctor(parent class)
579     if (func->IsDerivedConstructor()) {
580         return resultValue;
581     }
582 
583     if (!resultValue.IsUndefined()) {
584         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
585         THROW_TYPE_ERROR_AND_RETURN(thread, "function is non-constructor", JSTaggedValue::Exception());
586     }
587     return obj.GetTaggedValue();
588 }
589 
GetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func)590 JSHandle<JSTaggedValue> JSFunctionBase::GetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func)
591 {
592     JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
593 
594     return JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(func), nameKey).GetValue();
595 }
596 
SetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & prefix)597 bool JSFunctionBase::SetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func,
598                                      const JSHandle<JSTaggedValue> &name, const JSHandle<JSTaggedValue> &prefix)
599 {
600     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
601     ASSERT_PRINT(name->IsStringOrSymbol(), "name must be string or symbol");
602     bool needPrefix = false;
603     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
604     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
605     if (!prefix->IsUndefined()) {
606         ASSERT_PRINT(prefix->IsString(), "prefix must be string");
607         needPrefix = true;
608     }
609     // If Type(name) is Symbol, then
610     // Let description be name’s [[Description]] value.
611     // If description is undefined, let name be the empty String.
612     // Else, let name be the concatenation of "[", description, and "]".
613     JSHandle<EcmaString> functionName;
614     if (name->IsSymbol()) {
615         JSTaggedValue description = JSHandle<JSSymbol>::Cast(name)->GetDescription();
616         JSHandle<EcmaString> descriptionHandle(thread, description);
617         if (description.IsUndefined()) {
618             functionName = factory->GetEmptyString();
619         } else {
620             JSHandle<EcmaString> leftBrackets(globalConst->GetHandledLeftSquareBracketString());
621             JSHandle<EcmaString> rightBrackets(globalConst->GetHandledRightSquareBracketString());
622             functionName = factory->ConcatFromString(leftBrackets, descriptionHandle);
623             functionName = factory->ConcatFromString(functionName, rightBrackets);
624         }
625     } else {
626         functionName = JSHandle<EcmaString>::Cast(name);
627     }
628     EcmaString *newString;
629     if (needPrefix) {
630         JSHandle<EcmaString> handlePrefixString = JSTaggedValue::ToString(thread, prefix);
631         JSHandle<EcmaString> spaceString(globalConst->GetHandledSpaceString());
632         JSHandle<EcmaString> concatString = factory->ConcatFromString(handlePrefixString, spaceString);
633         newString = *factory->ConcatFromString(concatString, functionName);
634     } else {
635         newString = *functionName;
636     }
637     JSHandle<JSTaggedValue> nameHandle(thread, newString);
638     JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
639     PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
640     JSHandle<JSTaggedValue> funcHandle(func);
641     return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, nameKey, nameDesc);
642 }
643 
SetFunctionLength(JSThread * thread,const JSHandle<JSFunction> & func,JSTaggedValue length,bool cfg)644 bool JSFunction::SetFunctionLength(JSThread *thread, const JSHandle<JSFunction> &func, JSTaggedValue length, bool cfg)
645 {
646     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
647     ASSERT_PRINT(length.IsInteger(), "length must be integer");
648     JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
649     ASSERT_PRINT(!JSTaggedValue::Less(thread, JSHandle<JSTaggedValue>(thread, length),
650                                       JSHandle<JSTaggedValue>(thread, JSTaggedValue(0))),
651                  "length must be non negative integer");
652     PropertyDescriptor lengthDesc(thread, JSHandle<JSTaggedValue>(thread, length), false, false, cfg);
653     JSHandle<JSTaggedValue> funcHandle(func);
654     return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, lengthKeyHandle, lengthDesc);
655 }
656 
657 // 9.4.1.2[[Construct]](argumentsList, newTarget)
ConstructInternal(EcmaRuntimeCallInfo * info)658 JSTaggedValue JSBoundFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
659 {
660     JSThread *thread = info->GetThread();
661     JSHandle<JSBoundFunction> func(info->GetFunction());
662     JSHandle<JSTaggedValue> target(thread, func->GetBoundTarget());
663     if (!target->IsConstructor()) {
664         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
665     }
666     JSHandle<JSTaggedValue> newTarget = info->GetNewTarget();
667     JSMutableHandle<JSTaggedValue> newTargetMutable(thread, newTarget.GetTaggedValue());
668     if (JSTaggedValue::SameValue(func.GetTaggedValue(), newTarget.GetTaggedValue())) {
669         newTargetMutable.Update(target.GetTaggedValue());
670     }
671 
672     JSHandle<TaggedArray> boundArgs(thread, func->GetBoundArguments());
673     const uint32_t boundLength = boundArgs->GetLength();
674     const uint32_t argsLength = info->GetArgsNumber() + boundLength;
675     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
676     EcmaRuntimeCallInfo *runtimeInfo =
677         EcmaInterpreter::NewRuntimeCallInfo(thread, target, undefined, newTargetMutable, argsLength);
678     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
679     if (boundLength == 0) {
680         runtimeInfo->SetCallArg(argsLength, 0, info, 0);
681     } else {
682         // 0 ~ boundLength is boundArgs; boundLength ~ argsLength is args of EcmaRuntimeCallInfo.
683         runtimeInfo->SetCallArg(boundLength, boundArgs);
684         runtimeInfo->SetCallArg(argsLength, boundLength, info, 0);
685     }
686     return JSFunction::Construct(runtimeInfo);
687 }
688 
ProxyRevocFunctions(const JSThread * thread,const JSHandle<JSProxyRevocFunction> & revoker)689 void JSProxyRevocFunction::ProxyRevocFunctions(const JSThread *thread, const JSHandle<JSProxyRevocFunction> &revoker)
690 {
691     // 1.Let p be the value of F’s [[RevocableProxy]] internal slot.
692     JSTaggedValue proxy = revoker->GetRevocableProxy();
693     // 2.If p is null, return undefined.
694     if (proxy.IsNull()) {
695         return;
696     }
697 
698     // 3.Set the value of F’s [[RevocableProxy]] internal slot to null.
699     revoker->SetRevocableProxy(thread, JSTaggedValue::Null());
700 
701     // 4.Assert: p is a Proxy object.
702     ASSERT(proxy.IsJSProxy());
703     JSHandle<JSProxy> proxyHandle(thread, proxy);
704 
705     // 5 ~ 6 Set internal slot of p to null.
706     proxyHandle->SetTarget(thread, JSTaggedValue::Null());
707     proxyHandle->SetHandler(thread, JSTaggedValue::Null());
708     proxyHandle->SetIsRevoked(true);
709 }
710 
AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo * argv)711 JSTaggedValue JSFunction::AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo *argv)
712 {
713     THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(),
714                                 "Under strict mode, 'caller' and 'arguments' properties must not be accessed.",
715                                 JSTaggedValue::Exception());
716 }
717 
IntlNameGetter(JSThread * thread,const JSHandle<JSObject> & self)718 JSTaggedValue JSIntlBoundFunction::IntlNameGetter(JSThread *thread, [[maybe_unused]] const JSHandle<JSObject> &self)
719 {
720     return thread->GlobalConstants()->GetEmptyString();
721 }
722 
SetFunctionNameNoPrefix(JSThread * thread,JSFunction * func,JSTaggedValue name)723 void JSFunction::SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name)
724 {
725     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
726     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
727     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
728 
729     JSHandle<JSTaggedValue> funcHandle(thread, func);
730     {
731         JSMutableHandle<JSTaggedValue> nameHandle(thread, JSTaggedValue::Undefined());
732         if (!name.IsSymbol()) {
733             nameHandle.Update(name);
734         } else {
735             JSHandle<JSTaggedValue> nameBegin(thread, name);
736             JSTaggedValue description = JSSymbol::Cast(name.GetTaggedObject())->GetDescription();
737             if (description.IsUndefined()) {
738                 nameHandle.Update(globalConst->GetEmptyString());
739             } else {
740                 JSHandle<EcmaString> leftBrackets(globalConst->GetHandledLeftSquareBracketString());
741                 JSHandle<EcmaString> rightBrackets(globalConst->GetHandledRightSquareBracketString());
742                 JSHandle<EcmaString> concatName = factory->ConcatFromString(leftBrackets,
743                     JSHandle<EcmaString>(thread, JSSymbol::Cast(nameBegin->GetTaggedObject())->GetDescription()));
744                 concatName = factory->ConcatFromString(concatName, rightBrackets);
745                 nameHandle.Update(concatName.GetTaggedValue());
746             }
747         }
748         PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
749         JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, globalConst->GetHandledNameString(), nameDesc);
750     }
751 }
752 
GetInstanceJSHClass(JSThread * thread,JSHandle<JSFunction> constructor,JSHandle<JSTaggedValue> newTarget)753 JSHandle<JSHClass> JSFunction::GetInstanceJSHClass(JSThread *thread, JSHandle<JSFunction> constructor,
754                                                    JSHandle<JSTaggedValue> newTarget)
755 {
756     JSHandle<JSHClass> ctorInitialJSHClass(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
757     // newTarget is construct itself
758     if (newTarget.GetTaggedValue() == constructor.GetTaggedValue()) {
759         return ctorInitialJSHClass;
760     }
761 
762     // newTarget is derived-class of constructor
763     if (newTarget->IsJSFunction()) {
764         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
765         if (newTargetFunc->IsDerivedConstructor()) {
766             JSMutableHandle<JSTaggedValue> mutableNewTarget(thread, newTarget.GetTaggedValue());
767             JSMutableHandle<JSTaggedValue> mutableNewTargetProto(thread, JSTaggedValue::Undefined());
768             while (!mutableNewTargetProto->IsNull()) {
769                 mutableNewTargetProto.Update(JSTaggedValue::GetPrototype(thread, mutableNewTarget));
770                 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread);
771                 if (mutableNewTargetProto.GetTaggedValue() == constructor.GetTaggedValue()) {
772                     return GetOrCreateDerivedJSHClass(thread, newTargetFunc, ctorInitialJSHClass);
773                 }
774                 mutableNewTarget.Update(mutableNewTargetProto.GetTaggedValue());
775             }
776         }
777     }
778 
779     // ECMA2015 9.1.15 3.Let proto be Get(constructor, "prototype").
780     JSMutableHandle<JSTaggedValue> prototype(thread, JSTaggedValue::Undefined());
781     if (newTarget->IsJSFunction()) {
782         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
783         FunctionKind kind = newTargetFunc->GetFunctionKind();
784         if (HasPrototype(kind)) {
785             prototype.Update(PrototypeGetter(thread, JSHandle<JSObject>::Cast(newTargetFunc)));
786         }
787     } else {
788         // Such case: bound function and define a "prototype" property.
789         JSHandle<JSTaggedValue> customizePrototype =
790             JSTaggedValue::GetProperty(thread, newTarget, thread->GlobalConstants()->GetHandledPrototypeString())
791                 .GetValue();
792         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread);
793         prototype.Update(customizePrototype.GetTaggedValue());
794         // Reload JSHClass of constructor, where the lookup of 'prototype' property may change it.
795         ctorInitialJSHClass = JSHandle<JSHClass>(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
796     }
797 
798     if (!prototype->IsECMAObject()) {
799         prototype.Update(constructor->GetFunctionPrototype());
800     }
801 
802     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
803     newJSHClass->SetPrototype(thread, prototype);
804 
805     return newJSHClass;
806 }
807 
GetOrCreateDerivedJSHClass(JSThread * thread,JSHandle<JSFunction> derived,JSHandle<JSHClass> ctorInitialJSHClass)808 JSHandle<JSHClass> JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle<JSFunction> derived,
809                                                           JSHandle<JSHClass> ctorInitialJSHClass)
810 {
811     JSTaggedValue protoOrHClass(derived->GetProtoOrHClass());
812     // has cached JSHClass, return directly
813     if (protoOrHClass.IsJSHClass()) {
814         return JSHandle<JSHClass>(thread, protoOrHClass);
815     }
816 
817     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
818     // guarante derived has function prototype
819     JSHandle<JSTaggedValue> prototype(thread, derived->GetProtoOrHClass());
820     ASSERT(!prototype->IsHole());
821     newJSHClass->SetPrototype(thread, prototype);
822     derived->SetProtoOrHClass(thread, newJSHClass);
823 
824     if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
825         thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(derived.GetTaggedType(),
826             newJSHClass.GetTaggedType());
827     }
828 
829     return newJSHClass;
830 }
831 
832 // Those interface below is discarded
InitializeJSFunction(JSThread * thread,const JSHandle<GlobalEnv> & env,const JSHandle<JSFunction> & func,FunctionKind kind)833 void JSFunction::InitializeJSFunction(JSThread *thread, [[maybe_unused]] const JSHandle<GlobalEnv> &env,
834                                       const JSHandle<JSFunction> &func, FunctionKind kind)
835 {
836     InitializeJSFunction(thread, func, kind);
837 }
838 
NameSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)839 bool JSFunction::NameSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
840                             [[maybe_unused]] bool mayThrow)
841 {
842     if (self->IsPropertiesDict()) {
843         // replace setter with value
844         JSHandle<JSTaggedValue> nameString = thread->GlobalConstants()->GetHandledNameString();
845         return self->UpdatePropertyInDictionary(thread, nameString.GetTaggedValue(), value.GetTaggedValue());
846     }
847     self->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, value.GetTaggedValue());
848     return true;
849 }
850 
SetFunctionExtraInfo(JSThread * thread,void * nativeFunc,const DeleteEntryPoint & deleter,void * data,size_t nativeBindingsize)851 void JSFunction::SetFunctionExtraInfo(JSThread *thread, void *nativeFunc,
852                                       const DeleteEntryPoint &deleter, void *data, size_t nativeBindingsize)
853 {
854     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
855     EcmaVM *vm = thread->GetEcmaVM();
856     JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
857     JSHandle<ECMAObject> obj(thread, this);
858     JSHandle<JSNativePointer> pointer = vm->GetFactory()->NewJSNativePointer(nativeFunc, deleter, data,
859         false, nativeBindingsize);
860     if (!obj->HasHash()) {
861         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
862         return;
863     }
864     if (value->IsHeapObject()) {
865         if (value->IsJSNativePointer()) {
866             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
867             return;
868         }
869         JSHandle<TaggedArray> array(value);
870 
871         uint32_t nativeFieldCount = array->GetExtraLength();
872         if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
873             array->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
874         } else {
875             JSHandle<TaggedArray> newArray = vm->GetFactory()->NewTaggedArray(nativeFieldCount + RESOLVED_MAX_SIZE);
876             newArray->SetExtraLength(nativeFieldCount);
877             for (uint32_t i = 0; i < nativeFieldCount; i++) {
878                 newArray->Set(thread, i, array->Get(i));
879             }
880             newArray->Set(thread, nativeFieldCount + HASH_INDEX, array->Get(nativeFieldCount + HASH_INDEX));
881             newArray->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
882             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
883         }
884     } else {
885         JSHandle<TaggedArray> newArray = vm->GetFactory()->NewTaggedArray(RESOLVED_MAX_SIZE);
886         newArray->SetExtraLength(0);
887         newArray->Set(thread, HASH_INDEX, value);
888         newArray->Set(thread, FUNCTION_EXTRA_INDEX, pointer);
889         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
890     }
891 }
892 
GetFunctionExtraInfo() const893 JSTaggedValue JSFunction::GetFunctionExtraInfo() const
894 {
895     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
896     JSTaggedValue value(hashField);
897     if (value.IsHeapObject()) {
898         if (value.IsTaggedArray()) {
899             TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
900             uint32_t nativeFieldCount = array->GetExtraLength();
901             if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
902                 return array->Get(nativeFieldCount + FUNCTION_EXTRA_INDEX);
903             }
904         }
905         if (value.IsJSNativePointer()) {
906             return value;
907         }
908         LOG_ECMA(FATAL) << "this branch is unreachable";
909         UNREACHABLE();
910     }
911     return JSTaggedValue::Undefined();
912 }
913 
GetNativeFunctionExtraInfo() const914 JSTaggedValue JSFunction::GetNativeFunctionExtraInfo() const
915 {
916     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
917     JSTaggedValue value(hashField);
918     if (value.CheckIsJSNativePointer()) {
919         return value;
920     }
921     return JSTaggedValue::Undefined();
922 }
923 
InitializeForConcurrentFunction(JSThread * thread)924 void JSFunction::InitializeForConcurrentFunction(JSThread *thread)
925 {
926     JSHandle<Method> method(thread, this->GetMethod());
927     const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
928     if (jsPandaFile == nullptr) {
929         LOG_ECMA(ERROR) << "JSPandaFile is nullptr";
930         return;
931     }
932     ecmascript::CString moduleName = jsPandaFile->GetJSPandaFileDesc();
933     ecmascript::CString recordName = method->GetRecordNameStr();
934 
935     // for debugger, to notify the script loaded and parsed which the concurrent function is in
936     auto *notificationMgr = thread->GetEcmaVM()->GetJsDebuggerManager()->GetNotificationManager();
937     notificationMgr->LoadModuleEvent(moduleName, recordName);
938 
939     // check ESM or CJS
940     ecmascript::JSRecordInfo recordInfo;
941     bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(recordName, recordInfo);
942     if (!hasRecord) {
943         LOG_ECMA(ERROR) << "cannot find record '" << recordName << "', please check the request path.";
944         return;
945     }
946     if (!jsPandaFile->IsModule(recordInfo)) {
947         LOG_ECMA(DEBUG) << "Current function is not from ES Module's file.";
948         return;
949     }
950     ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
951     JSHandle<ecmascript::JSTaggedValue> moduleRecord;
952     // check compileMode
953     if (jsPandaFile->IsBundlePack()) {
954         LOG_ECMA(DEBUG) << "CompileMode is jsbundle";
955         moduleRecord = moduleManager->HostResolveImportedModule(moduleName);
956     } else {
957         LOG_ECMA(DEBUG) << "CompileMode is esmodule";
958         moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(moduleName, recordName);
959     }
960     RETURN_IF_ABRUPT_COMPLETION(thread);
961     ecmascript::SourceTextModule::Instantiate(thread, moduleRecord);
962     JSHandle<ecmascript::SourceTextModule> module = JSHandle<ecmascript::SourceTextModule>::Cast(moduleRecord);
963     module->SetStatus(ecmascript::ModuleStatus::INSTANTIATED);
964     ecmascript::SourceTextModule::EvaluateForConcurrent(thread, module, method);
965     method->SetModule(thread, module);
966 }
967 }  // namespace panda::ecmascript
968