• 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_tagged_value.h"
24 #include "ecmascript/jspandafile/class_info_extractor.h"
25 #include "ecmascript/js_handle.h"
26 #include "ecmascript/js_promise.h"
27 #include "ecmascript/js_tagged_value-inl.h"
28 #include "ecmascript/mem/c_containers.h"
29 #include "ecmascript/module/js_module_source_text.h"
30 #include "ecmascript/object_factory.h"
31 #include "ecmascript/tagged_array.h"
32 #include "ecmascript/require/js_require_manager.h"
33 
34 namespace panda::ecmascript {
InitializeJSFunction(JSThread * thread,const JSHandle<JSFunction> & func,FunctionKind kind)35 void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle<JSFunction> &func, FunctionKind kind)
36 {
37     func->SetProtoOrHClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER);
38     func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
39     func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
40     func->SetModule(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
41     func->SetMethod(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
42 
43     auto globalConst = thread->GlobalConstants();
44     if (HasPrototype(kind)) {
45         JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionPrototypeAccessor();
46         if (kind == FunctionKind::BASE_CONSTRUCTOR || kind == FunctionKind::GENERATOR_FUNCTION ||
47             kind == FunctionKind::ASYNC_GENERATOR_FUNCTION) {
48             func->SetPropertyInlinedProps(thread, PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
49             accessor = globalConst->GetHandledFunctionNameAccessor();
50             func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
51             JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
52             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
53             JSHandle<JSFunction> objFun(env->GetObjectFunction());
54             JSHandle<JSObject> initialGeneratorFuncPrototype = factory->NewJSObjectByConstructor(objFun);
55             if (kind == FunctionKind::ASYNC_GENERATOR_FUNCTION) {
56                 JSObject::SetPrototype(thread, initialGeneratorFuncPrototype, env->GetAsyncGeneratorPrototype());
57                 func->SetProtoOrHClass(thread, initialGeneratorFuncPrototype);
58             }
59             if (kind == FunctionKind::GENERATOR_FUNCTION) {
60                 JSObject::SetPrototype(thread, initialGeneratorFuncPrototype, env->GetGeneratorPrototype());
61                 func->SetProtoOrHClass(thread, initialGeneratorFuncPrototype);
62             }
63         } else if (!JSFunction::IsClassConstructor(kind)) {  // class ctor do nothing
64             PropertyDescriptor desc(thread, accessor, kind != FunctionKind::BUILTIN_CONSTRUCTOR, false, false);
65             [[maybe_unused]] bool success = JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(func),
66                                                                         globalConst->GetHandledPrototypeString(), desc);
67             ASSERT(success);
68         }
69     } else if (HasAccessor(kind)) {
70         JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionNameAccessor();
71         func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
72     }
73 }
74 
NewJSFunctionPrototype(JSThread * thread,const JSHandle<JSFunction> & func)75 JSHandle<JSObject> JSFunction::NewJSFunctionPrototype(JSThread *thread, const JSHandle<JSFunction> &func)
76 {
77     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
78     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
79     JSHandle<JSFunction> objFun(env->GetObjectFunction());
80     JSHandle<JSObject> funPro = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(objFun);
81     func->SetFunctionPrototype(thread, funPro.GetTaggedValue());
82 
83     // set "constructor" in prototype
84     JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
85     PropertyDescriptor descriptor(thread, JSHandle<JSTaggedValue>::Cast(func), true, false, true);
86     JSObject::DefineOwnProperty(thread, funPro, constructorKey, descriptor);
87 
88     return funPro;
89 }
90 
GetOrCreateInitialJSHClass(JSThread * thread,const JSHandle<JSFunction> & fun)91 JSHClass *JSFunction::GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle<JSFunction> &fun)
92 {
93     JSTaggedValue protoOrHClass(fun->GetProtoOrHClass());
94     if (protoOrHClass.IsJSHClass()) {
95         return reinterpret_cast<JSHClass *>(protoOrHClass.GetTaggedObject());
96     }
97 
98     JSHandle<JSTaggedValue> proto;
99     if (!fun->HasFunctionPrototype()) {
100         proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, fun));
101     } else {
102         proto = JSHandle<JSTaggedValue>(thread, fun->GetProtoOrHClass());
103     }
104 
105     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
106     JSHandle<JSHClass> hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, proto);
107     fun->SetProtoOrHClass(thread, hclass);
108     return *hclass;
109 }
110 
PrototypeGetter(JSThread * thread,const JSHandle<JSObject> & self)111 JSTaggedValue JSFunction::PrototypeGetter(JSThread *thread, const JSHandle<JSObject> &self)
112 {
113     JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(self);
114     if (!func->HasFunctionPrototype()) {
115         NewJSFunctionPrototype(thread, func);
116     }
117     return JSFunction::Cast(*self)->GetFunctionPrototype();
118 }
119 
PrototypeSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)120 bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
121                                  [[maybe_unused]] bool mayThrow)
122 {
123     JSHandle<JSFunction> func(self);
124     JSTaggedValue protoOrHClass = func->GetProtoOrHClass();
125     if (protoOrHClass.IsJSHClass()) {
126         // need transition
127         JSHandle<JSHClass> hclass(thread, protoOrHClass);
128         JSHandle<JSHClass> newClass = JSHClass::TransitionProto(thread, hclass, value);
129         if (value->IsECMAObject()) {
130             JSObject::Cast(value->GetTaggedObject())->GetJSHClass()->SetIsPrototype(true);
131         }
132         func->SetProtoOrHClass(thread, newClass);
133     } else {
134         func->SetFunctionPrototype(thread, value.GetTaggedValue());
135     }
136     return true;
137 }
138 
NameGetter(JSThread * thread,const JSHandle<JSObject> & self)139 JSTaggedValue JSFunction::NameGetter(JSThread *thread, const JSHandle<JSObject> &self)
140 {
141     JSTaggedValue method = JSHandle<JSFunction>::Cast(self)->GetMethod();
142     if (method.IsUndefined()) {
143         return JSTaggedValue::Undefined();
144     }
145     Method *target = Method::Cast(method.GetTaggedObject());
146     if (target->IsNativeWithCallField()) {
147         return JSTaggedValue::Undefined();
148     }
149     std::string funcName = target->ParseFunctionName();
150     if (funcName.empty()) {
151         return thread->GlobalConstants()->GetEmptyString();
152     }
153     if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::GETTER_FUNCTION) {
154         funcName.insert(0, "get ");
155     }
156     if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::SETTER_FUNCTION) {
157         funcName.insert(0, "set ");
158     }
159 
160     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
161     return factory->NewFromStdString(funcName).GetTaggedValue();
162 }
163 
OrdinaryHasInstance(JSThread * thread,const JSHandle<JSTaggedValue> & constructor,const JSHandle<JSTaggedValue> & obj)164 bool JSFunction::OrdinaryHasInstance(JSThread *thread, const JSHandle<JSTaggedValue> &constructor,
165                                      const JSHandle<JSTaggedValue> &obj)
166 {
167     // 1. If IsCallable(C) is false, return false.
168     if (!constructor->IsCallable()) {
169         return false;
170     }
171 
172     // 2. If C has a [[BoundTargetFunction]] internal slot, then
173     //    a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
174     //    b. Return InstanceofOperator(O,BC)  (see 12.9.4).
175     if (constructor->IsBoundFunction()) {
176         JSHandle<JSBoundFunction> boundFunction(thread, JSBoundFunction::Cast(constructor->GetTaggedObject()));
177         JSTaggedValue boundTarget = boundFunction->GetBoundTarget();
178         return JSObject::InstanceOf(thread, obj, JSHandle<JSTaggedValue>(thread, boundTarget));
179     }
180     // 3. If Type(O) is not Object, return false
181     if (!obj->IsECMAObject()) {
182         return false;
183     }
184 
185     // 4. Let P be Get(C, "prototype").
186     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
187     JSHandle<JSTaggedValue> constructorPrototype =
188         JSTaggedValue::GetProperty(thread, constructor, globalConst->GetHandledPrototypeString()).GetValue();
189 
190     // 5. ReturnIfAbrupt(P).
191     // no throw exception, so needn't return
192     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
193 
194     // 6. If Type(P) is not Object, throw a TypeError exception.
195     if (!constructorPrototype->IsECMAObject()) {
196         THROW_TYPE_ERROR_AND_RETURN(thread, "HasInstance: is not Object", false);
197     }
198 
199     // 7. Repeat
200     //    a.Let O be O.[[GetPrototypeOf]]().
201     //    b.ReturnIfAbrupt(O).
202     //    c.If O is null, return false.
203     //    d.If SameValue(P, O) is true, return true.
204     JSMutableHandle<JSTaggedValue> object(thread, obj.GetTaggedValue());
205     while (!object->IsNull()) {
206         if (JSTaggedValue::SameValue(object, constructorPrototype)) {
207             return true;
208         }
209         object.Update(JSTaggedValue::GetPrototype(thread, object));
210         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
211     }
212     return false;
213 }
214 
MakeConstructor(JSThread * thread,const JSHandle<JSFunction> & func,const JSHandle<JSTaggedValue> & proto,bool writable)215 bool JSFunction::MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &func,
216                                  const JSHandle<JSTaggedValue> &proto, bool writable)
217 {
218     ASSERT_PRINT(proto->IsHeapObject() || proto->IsUndefined(), "proto must be JSObject or Undefined");
219     ASSERT_PRINT(func->IsConstructor(), "func must be Constructor type");
220     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
221     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
222     JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
223 
224     ASSERT_PRINT(func->GetProtoOrHClass().IsHole() && func->IsExtensible(),
225                  "function doesn't has proto_type property and is extensible object");
226     ASSERT_PRINT(JSObject::HasProperty(thread, JSHandle<JSObject>(func), constructorKey),
227                  "function must have constructor");
228 
229     // proto.constructor = func
230     bool status = false;
231     if (proto->IsUndefined()) {
232         // Let prototype be ObjectCreate(%ObjectPrototype%).
233         JSHandle<JSTaggedValue> objPrototype = env->GetObjectFunctionPrototype();
234         PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
235         status = JSTaggedValue::DefinePropertyOrThrow(thread, objPrototype, constructorKey, constructorDesc);
236     } else {
237         PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
238         status = JSTaggedValue::DefinePropertyOrThrow(thread, proto, constructorKey, constructorDesc);
239     }
240     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
241 
242     ASSERT_PRINT(status, "DefineProperty construct failed");
243     // func.prototype = proto
244     // Let status be DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]:
245     // prototype, [[Writable]]: writablePrototype, [[Enumerable]]: false, [[Configurable]]: false}).
246     func->SetFunctionPrototype(thread, proto.GetTaggedValue());
247 
248     ASSERT_PRINT(status, "DefineProperty proto_type failed");
249     return status;
250 }
251 
Call(EcmaRuntimeCallInfo * info)252 JSTaggedValue JSFunction::Call(EcmaRuntimeCallInfo *info)
253 {
254     if (info == nullptr) {
255         return JSTaggedValue::Exception();
256     }
257 
258     JSThread *thread = info->GetThread();
259     // 1. ReturnIfAbrupt(F).
260     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
261     JSHandle<JSTaggedValue> func = info->GetFunction();
262     // 2. If argumentsList was not passed, let argumentsList be a new empty List.
263     // 3. If IsCallable(F) is false, throw a TypeError exception.
264     if (!func->IsCallable()) {
265         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
266         THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
267     }
268 
269     auto *hclass = func->GetTaggedObject()->GetClass();
270     if (hclass->IsClassConstructor()) {
271         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
272         THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", JSTaggedValue::Exception());
273     }
274     return EcmaInterpreter::Execute(info);
275 }
276 
Construct(EcmaRuntimeCallInfo * info)277 JSTaggedValue JSFunction::Construct(EcmaRuntimeCallInfo *info)
278 {
279     if (info == nullptr) {
280         return JSTaggedValue::Exception();
281     }
282 
283     JSThread *thread = info->GetThread();
284     JSHandle<JSTaggedValue> func(info->GetFunction());
285     JSHandle<JSTaggedValue> target = info->GetNewTarget();
286     if (target->IsUndefined()) {
287         target = func;
288         info->SetNewTarget(target.GetTaggedValue());
289     }
290     if (!(func->IsConstructor() && target->IsConstructor())) {
291         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
292         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
293     }
294 
295     if (func->IsJSFunction()) {
296         return JSFunction::ConstructInternal(info);
297     } else if (func->IsJSProxy()) {
298         return JSProxy::ConstructInternal(info);
299     } else {
300         ASSERT(func->IsBoundFunction());
301         return JSBoundFunction::ConstructInternal(info);
302     }
303 }
304 
Invoke(EcmaRuntimeCallInfo * info,const JSHandle<JSTaggedValue> & key)305 JSTaggedValue JSFunction::Invoke(EcmaRuntimeCallInfo *info, const JSHandle<JSTaggedValue> &key)
306 {
307     if (info == nullptr) {
308         return JSTaggedValue::Exception();
309     }
310 
311     ASSERT(JSTaggedValue::IsPropertyKey(key));
312     JSThread *thread = info->GetThread();
313     JSHandle<JSTaggedValue> thisArg = info->GetThis();
314     JSHandle<JSTaggedValue> func(JSTaggedValue::GetProperty(thread, thisArg, key).GetValue());
315     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
316     info->SetFunction(func.GetTaggedValue());
317     return JSFunction::Call(info);
318 }
319 
InvokeOptimizedEntrypoint(JSThread * thread,JSHandle<JSFunction> mainFunc,JSHandle<JSTaggedValue> & thisArg,std::string_view entryPoint,CJSInfo * cjsInfo)320 JSTaggedValue JSFunction::InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<JSFunction> mainFunc,
321     JSHandle<JSTaggedValue> &thisArg, std::string_view entryPoint, CJSInfo* cjsInfo)
322 {
323     if (mainFunc->IsClassConstructor()) {
324         {
325             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
326             JSHandle<JSObject> error =
327                 factory->GetJSError(ErrorType::TYPE_ERROR, "class constructor cannot called without 'new'");
328             thread->SetException(error.GetTaggedValue());
329         }
330         return thread->GetException();
331     }
332     Method *method = mainFunc->GetCallTarget();
333     size_t actualNumArgs = method->GetNumArgs();
334     const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
335     JSTaggedValue res;
336     std::vector<JSTaggedType> args;
337 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
338     RuntimeStubs::StartCallTimer(thread->GetGlueAddr(), mainFunc.GetTaggedType(), true);
339 #endif
340     if (method->IsFastCall()) {
341         // do not modify this log to INFO, this will call many times
342         LOG_ECMA(DEBUG) << "start to execute aot entry: " << entryPoint;
343         args = JSFunction::GetArgsData(true, thisArg, mainFunc, cjsInfo);
344         res = thread->GetEcmaVM()->FastCallAot(actualNumArgs, args.data(), prevFp);
345     } else {
346         args = JSFunction::GetArgsData(false, thisArg, mainFunc, cjsInfo);
347         // do not modify this log to INFO, this will call many times
348         LOG_ECMA(DEBUG) << "start to execute aot entry: " << entryPoint;
349         res = thread->GetCurrentEcmaContext()->ExecuteAot(actualNumArgs, args.data(), prevFp, false);
350     }
351 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
352     RuntimeStubs::EndCallTimer(thread->GetGlueAddr(), mainFunc.GetTaggedType());
353 #endif
354     if (thread->HasPendingException()) {
355         return thread->GetException();
356     }
357     return res;
358 }
359 
GetArgsData(bool isFastCall,JSHandle<JSTaggedValue> & thisArg,JSHandle<JSFunction> mainFunc,CJSInfo * cjsInfo)360 std::vector<JSTaggedType> JSFunction::GetArgsData(bool isFastCall, JSHandle<JSTaggedValue> &thisArg,
361     JSHandle<JSFunction> mainFunc, CJSInfo* cjsInfo)
362 {
363     size_t argsNum;
364     uint32_t mandatoryNum;
365     Method *method = mainFunc->GetCallTarget();
366     size_t actualNumArgs = method->GetNumArgs();
367     if (isFastCall) {
368         argsNum = actualNumArgs + NUM_MANDATORY_JSFUNC_ARGS - 1;
369         mandatoryNum = NUM_MANDATORY_JSFUNC_ARGS - 1;
370     } else {
371         argsNum = actualNumArgs + NUM_MANDATORY_JSFUNC_ARGS;
372         mandatoryNum = NUM_MANDATORY_JSFUNC_ARGS;
373     }
374     std::vector<JSTaggedType> args(argsNum, JSTaggedValue::Undefined().GetRawData());
375     args[0] = mainFunc.GetTaggedValue().GetRawData();
376     if (isFastCall) {
377         args[1] = thisArg.GetTaggedValue().GetRawData(); // 1: args number
378     } else {
379         args[2] = thisArg.GetTaggedValue().GetRawData(); // 2: args number
380     }
381     if (cjsInfo != nullptr) {
382         args[mandatoryNum++] = cjsInfo->exportsHdl.GetTaggedValue().GetRawData();
383         args[mandatoryNum++] = cjsInfo->requireHdl.GetTaggedValue().GetRawData();
384         args[mandatoryNum++] = cjsInfo->moduleHdl.GetTaggedValue().GetRawData();
385         args[mandatoryNum++] = cjsInfo->filenameHdl.GetTaggedValue().GetRawData();
386         args[mandatoryNum] = cjsInfo->dirnameHdl.GetTaggedValue().GetRawData();
387     }
388     return args;
389 }
390 
InvokeOptimizedEntrypoint(JSThread * thread,JSHandle<JSFunction> func,EcmaRuntimeCallInfo * info)391 JSTaggedValue JSFunction::InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<JSFunction> func,
392     EcmaRuntimeCallInfo *info)
393 {
394     Method *method = func->GetCallTarget();
395     JSTaggedValue resultValue;
396     uint32_t numArgs = method->GetNumArgsWithCallField();
397     bool needPushUndefined = numArgs > info->GetArgsNumber();
398     const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
399 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
400     RuntimeStubs::StartCallTimer(thread->GetGlueAddr(), func.GetTaggedType(), true);
401 #endif
402     if (method->IsFastCall()) {
403         if (needPushUndefined) {
404             info = EcmaInterpreter::ReBuildRuntimeCallInfo(thread, info, numArgs);
405             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
406         }
407         JSTaggedType *stackArgs = info->GetArgs();
408         stackArgs[1] = stackArgs[0];
409         resultValue = thread->GetEcmaVM()->FastCallAot(info->GetArgsNumber(), stackArgs + 1, prevFp);
410     } else {
411         resultValue = thread->GetCurrentEcmaContext()->ExecuteAot(info->GetArgsNumber(),
412             info->GetArgs(), prevFp, needPushUndefined);
413     }
414 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
415     RuntimeStubs::EndCallTimer(thread->GetGlueAddr(), func.GetTaggedType());
416 #endif
417     return resultValue;
418 }
419 
420 // [[Construct]]
ConstructInternal(EcmaRuntimeCallInfo * info)421 JSTaggedValue JSFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
422 {
423     if (info == nullptr) {
424         return JSTaggedValue::Exception();
425     }
426 
427     JSThread *thread = info->GetThread();
428     JSHandle<JSFunction> func(info->GetFunction());
429     JSHandle<JSTaggedValue> newTarget(info->GetNewTarget());
430     ASSERT(newTarget->IsECMAObject());
431     if (!func->IsConstructor()) {
432         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
433         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
434     }
435 
436     JSHandle<JSTaggedValue> obj(thread, JSTaggedValue::Undefined());
437     if (func->IsBase()) {
438         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
439         obj = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(func, newTarget));
440         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
441     }
442 
443     JSTaggedValue resultValue;
444     info->SetThis(obj.GetTaggedValue());
445     Method *method = func->GetCallTarget();
446     if (method->IsAotWithCallField() && func->IsClassConstructor()) {
447         resultValue = InvokeOptimizedEntrypoint(thread, func, info);
448         const JSTaggedType *curSp = thread->GetCurrentSPFrame();
449         InterpretedEntryFrame *entryState = InterpretedEntryFrame::GetFrameFromSp(curSp);
450         JSTaggedType *prevSp = entryState->base.prev;
451         thread->SetCurrentSPFrame(prevSp);
452     } else {
453         method->SetAotCodeBit(false); // if Construct is not ClassConstructor, don't run aot
454         resultValue = EcmaInterpreter::Execute(info);
455     }
456     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
457     // 9.3.2 [[Construct]] (argumentsList, newTarget)
458     if (resultValue.IsECMAObject()) {
459         return resultValue;
460     }
461 
462     if (func->IsBase()) {
463         return obj.GetTaggedValue();
464     }
465 
466     // derived ctor(sub class) return the obj which created by base ctor(parent class)
467     if (func->IsDerivedConstructor()) {
468         return resultValue;
469     }
470 
471     if (!resultValue.IsUndefined()) {
472         RETURN_STACK_BEFORE_THROW_IF_ASM(thread);
473         THROW_TYPE_ERROR_AND_RETURN(thread, "function is non-constructor", JSTaggedValue::Exception());
474     }
475     return obj.GetTaggedValue();
476 }
477 
GetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func)478 JSHandle<JSTaggedValue> JSFunctionBase::GetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func)
479 {
480     JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
481 
482     return JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(func), nameKey).GetValue();
483 }
484 
SetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & prefix)485 bool JSFunctionBase::SetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func,
486                                      const JSHandle<JSTaggedValue> &name, const JSHandle<JSTaggedValue> &prefix)
487 {
488     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
489     ASSERT_PRINT(name->IsStringOrSymbol(), "name must be string or symbol");
490     bool needPrefix = false;
491     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
492     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
493     if (!prefix->IsUndefined()) {
494         ASSERT_PRINT(prefix->IsString(), "prefix must be string");
495         needPrefix = true;
496     }
497     // If Type(name) is Symbol, then
498     // Let description be name’s [[Description]] value.
499     // If description is undefined, let name be the empty String.
500     // Else, let name be the concatenation of "[", description, and "]".
501     JSHandle<EcmaString> functionName;
502     if (name->IsSymbol()) {
503         JSTaggedValue description = JSHandle<JSSymbol>::Cast(name)->GetDescription();
504         JSHandle<EcmaString> descriptionHandle(thread, description);
505         if (description.IsUndefined()) {
506             functionName = factory->GetEmptyString();
507         } else {
508             JSHandle<EcmaString> leftBrackets(globalConst->GetHandledLeftSquareBracketString());
509             JSHandle<EcmaString> rightBrackets(globalConst->GetHandledRightSquareBracketString());
510             functionName = factory->ConcatFromString(leftBrackets, descriptionHandle);
511             functionName = factory->ConcatFromString(functionName, rightBrackets);
512         }
513     } else {
514         functionName = JSHandle<EcmaString>::Cast(name);
515     }
516     EcmaString *newString;
517     if (needPrefix) {
518         JSHandle<EcmaString> handlePrefixString = JSTaggedValue::ToString(thread, prefix);
519         JSHandle<EcmaString> spaceString(globalConst->GetHandledSpaceString());
520         JSHandle<EcmaString> concatString = factory->ConcatFromString(handlePrefixString, spaceString);
521         newString = *factory->ConcatFromString(concatString, functionName);
522     } else {
523         newString = *functionName;
524     }
525     JSHandle<JSTaggedValue> nameHandle(thread, newString);
526     JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
527     PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
528     JSHandle<JSTaggedValue> funcHandle(func);
529     return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, nameKey, nameDesc);
530 }
531 
SetFunctionLength(JSThread * thread,const JSHandle<JSFunction> & func,JSTaggedValue length,bool cfg)532 bool JSFunction::SetFunctionLength(JSThread *thread, const JSHandle<JSFunction> &func, JSTaggedValue length, bool cfg)
533 {
534     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
535     ASSERT_PRINT(length.IsInteger(), "length must be integer");
536     JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
537     ASSERT_PRINT(!JSTaggedValue::Less(thread, JSHandle<JSTaggedValue>(thread, length),
538                                       JSHandle<JSTaggedValue>(thread, JSTaggedValue(0))),
539                  "length must be non negative integer");
540     PropertyDescriptor lengthDesc(thread, JSHandle<JSTaggedValue>(thread, length), false, false, cfg);
541     JSHandle<JSTaggedValue> funcHandle(func);
542     return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, lengthKeyHandle, lengthDesc);
543 }
544 
545 // 9.4.1.2[[Construct]](argumentsList, newTarget)
ConstructInternal(EcmaRuntimeCallInfo * info)546 JSTaggedValue JSBoundFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
547 {
548     JSThread *thread = info->GetThread();
549     JSHandle<JSBoundFunction> func(info->GetFunction());
550     JSHandle<JSTaggedValue> target(thread, func->GetBoundTarget());
551     if (!target->IsConstructor()) {
552         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
553     }
554     ASSERT(target->IsConstructor());
555     JSHandle<JSTaggedValue> newTarget = info->GetNewTarget();
556     JSMutableHandle<JSTaggedValue> newTargetMutable(thread, newTarget.GetTaggedValue());
557     if (JSTaggedValue::SameValue(func.GetTaggedValue(), newTarget.GetTaggedValue())) {
558         newTargetMutable.Update(target.GetTaggedValue());
559     }
560 
561     JSHandle<TaggedArray> boundArgs(thread, func->GetBoundArguments());
562     const uint32_t boundLength = boundArgs->GetLength();
563     const uint32_t argsLength = info->GetArgsNumber() + boundLength;
564     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
565     EcmaRuntimeCallInfo *runtimeInfo =
566         EcmaInterpreter::NewRuntimeCallInfo(thread, target, undefined, newTargetMutable, argsLength);
567     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
568     if (boundLength == 0) {
569         runtimeInfo->SetCallArg(argsLength, 0, info, 0);
570     } else {
571         // 0 ~ boundLength is boundArgs; boundLength ~ argsLength is args of EcmaRuntimeCallInfo.
572         runtimeInfo->SetCallArg(boundLength, boundArgs);
573         runtimeInfo->SetCallArg(argsLength, boundLength, info, 0);
574     }
575     return JSFunction::Construct(runtimeInfo);
576 }
577 
ProxyRevocFunctions(const JSThread * thread,const JSHandle<JSProxyRevocFunction> & revoker)578 void JSProxyRevocFunction::ProxyRevocFunctions(const JSThread *thread, const JSHandle<JSProxyRevocFunction> &revoker)
579 {
580     // 1.Let p be the value of F’s [[RevocableProxy]] internal slot.
581     JSTaggedValue proxy = revoker->GetRevocableProxy();
582     // 2.If p is null, return undefined.
583     if (proxy.IsNull()) {
584         return;
585     }
586 
587     // 3.Set the value of F’s [[RevocableProxy]] internal slot to null.
588     revoker->SetRevocableProxy(thread, JSTaggedValue::Null());
589 
590     // 4.Assert: p is a Proxy object.
591     ASSERT(proxy.IsJSProxy());
592     JSHandle<JSProxy> proxyHandle(thread, proxy);
593 
594     // 5 ~ 6 Set internal slot of p to null.
595     proxyHandle->SetTarget(thread, JSTaggedValue::Null());
596     proxyHandle->SetHandler(thread, JSTaggedValue::Null());
597     proxyHandle->SetIsRevoked(true);
598 }
599 
AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo * argv)600 JSTaggedValue JSFunction::AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo *argv)
601 {
602     THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(),
603                                 "Under strict mode, 'caller' and 'arguments' properties must not be accessed.",
604                                 JSTaggedValue::Exception());
605 }
606 
IntlNameGetter(JSThread * thread,const JSHandle<JSObject> & self)607 JSTaggedValue JSIntlBoundFunction::IntlNameGetter(JSThread *thread, [[maybe_unused]] const JSHandle<JSObject> &self)
608 {
609     return thread->GlobalConstants()->GetEmptyString();
610 }
611 
SetFunctionNameNoPrefix(JSThread * thread,JSFunction * func,JSTaggedValue name)612 void JSFunction::SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name)
613 {
614     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
615     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
616     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
617 
618     JSHandle<JSTaggedValue> funcHandle(thread, func);
619     {
620         JSMutableHandle<JSTaggedValue> nameHandle(thread, JSTaggedValue::Undefined());
621         if (!name.IsSymbol()) {
622             nameHandle.Update(name);
623         } else {
624             JSHandle<JSTaggedValue> nameBegin(thread, name);
625             JSTaggedValue description = JSSymbol::Cast(name.GetTaggedObject())->GetDescription();
626             if (description.IsUndefined()) {
627                 nameHandle.Update(globalConst->GetEmptyString());
628             } else {
629                 JSHandle<EcmaString> leftBrackets(globalConst->GetHandledLeftSquareBracketString());
630                 JSHandle<EcmaString> rightBrackets(globalConst->GetHandledRightSquareBracketString());
631                 JSHandle<EcmaString> concatName = factory->ConcatFromString(leftBrackets,
632                     JSHandle<EcmaString>(thread, JSSymbol::Cast(nameBegin->GetTaggedObject())->GetDescription()));
633                 concatName = factory->ConcatFromString(concatName, rightBrackets);
634                 nameHandle.Update(concatName.GetTaggedValue());
635             }
636         }
637         PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
638         JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, globalConst->GetHandledNameString(), nameDesc);
639     }
640 }
641 
GetInstanceJSHClass(JSThread * thread,JSHandle<JSFunction> constructor,JSHandle<JSTaggedValue> newTarget)642 JSHandle<JSHClass> JSFunction::GetInstanceJSHClass(JSThread *thread, JSHandle<JSFunction> constructor,
643                                                    JSHandle<JSTaggedValue> newTarget)
644 {
645     JSHandle<JSHClass> ctorInitialJSHClass(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
646     // newTarget is construct itself
647     if (newTarget.GetTaggedValue() == constructor.GetTaggedValue()) {
648         return ctorInitialJSHClass;
649     }
650 
651     // newTarget is derived-class of constructor
652     if (newTarget->IsJSFunction()) {
653         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
654         if (newTargetFunc->IsDerivedConstructor()) {
655             JSMutableHandle<JSTaggedValue> mutableNewTarget(thread, newTarget.GetTaggedValue());
656             JSMutableHandle<JSTaggedValue> mutableNewTargetProto(thread, JSTaggedValue::Undefined());
657             while (!mutableNewTargetProto->IsNull()) {
658                 mutableNewTargetProto.Update(JSTaggedValue::GetPrototype(thread, mutableNewTarget));
659                 if (mutableNewTargetProto.GetTaggedValue() == constructor.GetTaggedValue()) {
660                     return GetOrCreateDerivedJSHClass(thread, newTargetFunc, ctorInitialJSHClass);
661                 }
662                 mutableNewTarget.Update(mutableNewTargetProto.GetTaggedValue());
663             }
664         }
665     }
666 
667     // ECMA2015 9.1.15 3.Let proto be Get(constructor, "prototype").
668     JSMutableHandle<JSTaggedValue> prototype(thread, JSTaggedValue::Undefined());
669     if (newTarget->IsJSFunction()) {
670         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
671         FunctionKind kind = newTargetFunc->GetFunctionKind();
672         if (HasPrototype(kind)) {
673             prototype.Update(PrototypeGetter(thread, JSHandle<JSObject>::Cast(newTargetFunc)));
674         }
675     } else {
676         // Such case: bound function and define a "prototype" property.
677         JSHandle<JSTaggedValue> customizePrototype =
678             JSTaggedValue::GetProperty(thread, newTarget, thread->GlobalConstants()->GetHandledPrototypeString())
679                 .GetValue();
680         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread);
681         prototype.Update(customizePrototype.GetTaggedValue());
682         // Reload JSHClass of constructor, where the lookup of 'prototype' property may change it.
683         ctorInitialJSHClass = JSHandle<JSHClass>(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
684     }
685 
686     if (!prototype->IsECMAObject()) {
687         prototype.Update(constructor->GetFunctionPrototype());
688     }
689 
690     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
691     newJSHClass->SetPrototype(thread, prototype);
692 
693     return newJSHClass;
694 }
695 
GetOrCreateDerivedJSHClass(JSThread * thread,JSHandle<JSFunction> derived,JSHandle<JSHClass> ctorInitialJSHClass)696 JSHandle<JSHClass> JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle<JSFunction> derived,
697                                                           JSHandle<JSHClass> ctorInitialJSHClass)
698 {
699     JSTaggedValue protoOrHClass(derived->GetProtoOrHClass());
700     // has cached JSHClass, return directly
701     if (protoOrHClass.IsJSHClass()) {
702         return JSHandle<JSHClass>(thread, protoOrHClass);
703     }
704 
705     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
706     // guarante derived has function prototype
707     JSHandle<JSTaggedValue> prototype(thread, derived->GetProtoOrHClass());
708     ASSERT(!prototype->IsHole());
709     newJSHClass->SetPrototype(thread, prototype);
710     derived->SetProtoOrHClass(thread, newJSHClass);
711     return newJSHClass;
712 }
713 
714 // Those interface below is discarded
InitializeJSFunction(JSThread * thread,const JSHandle<GlobalEnv> & env,const JSHandle<JSFunction> & func,FunctionKind kind)715 void JSFunction::InitializeJSFunction(JSThread *thread, [[maybe_unused]] const JSHandle<GlobalEnv> &env,
716                                       const JSHandle<JSFunction> &func, FunctionKind kind)
717 {
718     InitializeJSFunction(thread, func, kind);
719 }
720 
NameSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)721 bool JSFunction::NameSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
722                             [[maybe_unused]] bool mayThrow)
723 {
724     if (self->IsPropertiesDict()) {
725         // replace setter with value
726         JSHandle<JSTaggedValue> nameString = thread->GlobalConstants()->GetHandledNameString();
727         return self->UpdatePropertyInDictionary(thread, nameString.GetTaggedValue(), value.GetTaggedValue());
728     }
729     self->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, value.GetTaggedValue());
730     return true;
731 }
732 
SetFunctionExtraInfo(JSThread * thread,void * nativeFunc,const DeleteEntryPoint & deleter,void * data,size_t nativeBindingsize)733 void JSFunction::SetFunctionExtraInfo(JSThread *thread, void *nativeFunc,
734                                       const DeleteEntryPoint &deleter, void *data, size_t nativeBindingsize)
735 {
736     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
737     EcmaVM *vm = thread->GetEcmaVM();
738     JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
739     JSHandle<ECMAObject> obj(thread, this);
740     JSHandle<JSNativePointer> pointer = vm->GetFactory()->NewJSNativePointer(nativeFunc, deleter, data,
741         false, nativeBindingsize);
742     if (!obj->HasHash()) {
743         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
744         return;
745     }
746     if (value->IsHeapObject()) {
747         if (value->IsJSNativePointer()) {
748             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
749             return;
750         }
751         JSHandle<TaggedArray> array(value);
752 
753         uint32_t nativeFieldCount = array->GetExtraLength();
754         if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
755             array->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
756         } else {
757             JSHandle<TaggedArray> newArray = vm->GetFactory()->NewTaggedArray(nativeFieldCount + RESOLVED_MAX_SIZE);
758             newArray->SetExtraLength(nativeFieldCount);
759             for (uint32_t i = 0; i < nativeFieldCount; i++) {
760                 newArray->Set(thread, i, array->Get(i));
761             }
762             newArray->Set(thread, nativeFieldCount + HASH_INDEX, array->Get(nativeFieldCount + HASH_INDEX));
763             newArray->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
764             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
765         }
766     } else {
767         JSHandle<TaggedArray> newArray = vm->GetFactory()->NewTaggedArray(RESOLVED_MAX_SIZE);
768         newArray->SetExtraLength(0);
769         newArray->Set(thread, HASH_INDEX, value);
770         newArray->Set(thread, FUNCTION_EXTRA_INDEX, pointer);
771         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
772     }
773 }
774 
GetFunctionExtraInfo() const775 JSTaggedValue JSFunction::GetFunctionExtraInfo() const
776 {
777     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
778     JSTaggedValue value(hashField);
779     if (value.IsHeapObject()) {
780         if (value.IsTaggedArray()) {
781             TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
782             uint32_t nativeFieldCount = array->GetExtraLength();
783             if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
784                 return array->Get(nativeFieldCount + FUNCTION_EXTRA_INDEX);
785             }
786         }
787         if (value.IsJSNativePointer()) {
788             return value;
789         }
790         LOG_ECMA(FATAL) << "this branch is unreachable";
791         UNREACHABLE();
792     }
793     return JSTaggedValue::Undefined();
794 }
795 
GetNativeFunctionExtraInfo() const796 JSTaggedValue JSFunction::GetNativeFunctionExtraInfo() const
797 {
798     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
799     JSTaggedValue value(hashField);
800     if (value.CheckIsJSNativePointer()) {
801         return value;
802     }
803     return JSTaggedValue::Undefined();
804 }
805 
GetRecordName() const806 JSTaggedValue JSFunction::GetRecordName() const
807 {
808     JSTaggedValue module = GetModule();
809     if (module.IsSourceTextModule()) {
810         JSTaggedValue recordName = SourceTextModule::Cast(module.GetTaggedObject())->GetEcmaModuleRecordName();
811         if (!recordName.IsString()) {
812             LOG_INTERPRETER(DEBUG) << "module record name is undefined";
813             return JSTaggedValue::Hole();
814         }
815         return recordName;
816     }
817     if (module.IsString()) {
818         return module;
819     }
820     LOG_INTERPRETER(DEBUG) << "record name is undefined";
821     return JSTaggedValue::Hole();
822 }
823 }  // namespace panda::ecmascript
824