• 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     ASSERT(target->IsConstructor());
552     JSHandle<JSTaggedValue> newTarget = info->GetNewTarget();
553     JSMutableHandle<JSTaggedValue> newTargetMutable(thread, newTarget.GetTaggedValue());
554     if (JSTaggedValue::SameValue(func.GetTaggedValue(), newTarget.GetTaggedValue())) {
555         newTargetMutable.Update(target.GetTaggedValue());
556     }
557 
558     JSHandle<TaggedArray> boundArgs(thread, func->GetBoundArguments());
559     const uint32_t boundLength = boundArgs->GetLength();
560     const uint32_t argsLength = info->GetArgsNumber() + boundLength;
561     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
562     EcmaRuntimeCallInfo *runtimeInfo =
563         EcmaInterpreter::NewRuntimeCallInfo(thread, target, undefined, newTargetMutable, argsLength);
564     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
565     if (boundLength == 0) {
566         runtimeInfo->SetCallArg(argsLength, 0, info, 0);
567     } else {
568         // 0 ~ boundLength is boundArgs; boundLength ~ argsLength is args of EcmaRuntimeCallInfo.
569         runtimeInfo->SetCallArg(boundLength, boundArgs);
570         runtimeInfo->SetCallArg(argsLength, boundLength, info, 0);
571     }
572     return JSFunction::Construct(runtimeInfo);
573 }
574 
ProxyRevocFunctions(const JSThread * thread,const JSHandle<JSProxyRevocFunction> & revoker)575 void JSProxyRevocFunction::ProxyRevocFunctions(const JSThread *thread, const JSHandle<JSProxyRevocFunction> &revoker)
576 {
577     // 1.Let p be the value of F’s [[RevocableProxy]] internal slot.
578     JSTaggedValue proxy = revoker->GetRevocableProxy();
579     // 2.If p is null, return undefined.
580     if (proxy.IsNull()) {
581         return;
582     }
583 
584     // 3.Set the value of F’s [[RevocableProxy]] internal slot to null.
585     revoker->SetRevocableProxy(thread, JSTaggedValue::Null());
586 
587     // 4.Assert: p is a Proxy object.
588     ASSERT(proxy.IsJSProxy());
589     JSHandle<JSProxy> proxyHandle(thread, proxy);
590 
591     // 5 ~ 6 Set internal slot of p to null.
592     proxyHandle->SetTarget(thread, JSTaggedValue::Null());
593     proxyHandle->SetHandler(thread, JSTaggedValue::Null());
594     proxyHandle->SetIsRevoked(true);
595 }
596 
AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo * argv)597 JSTaggedValue JSFunction::AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo *argv)
598 {
599     THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(),
600                                 "Under strict mode, 'caller' and 'arguments' properties must not be accessed.",
601                                 JSTaggedValue::Exception());
602 }
603 
IntlNameGetter(JSThread * thread,const JSHandle<JSObject> & self)604 JSTaggedValue JSIntlBoundFunction::IntlNameGetter(JSThread *thread, [[maybe_unused]] const JSHandle<JSObject> &self)
605 {
606     return thread->GlobalConstants()->GetEmptyString();
607 }
608 
SetFunctionNameNoPrefix(JSThread * thread,JSFunction * func,JSTaggedValue name)609 void JSFunction::SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name)
610 {
611     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
612     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
613     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
614 
615     JSHandle<JSTaggedValue> funcHandle(thread, func);
616     {
617         JSMutableHandle<JSTaggedValue> nameHandle(thread, JSTaggedValue::Undefined());
618         if (!name.IsSymbol()) {
619             nameHandle.Update(name);
620         } else {
621             JSHandle<JSTaggedValue> nameBegin(thread, name);
622             JSTaggedValue description = JSSymbol::Cast(name.GetTaggedObject())->GetDescription();
623             if (description.IsUndefined()) {
624                 nameHandle.Update(globalConst->GetEmptyString());
625             } else {
626                 JSHandle<EcmaString> leftBrackets(globalConst->GetHandledLeftSquareBracketString());
627                 JSHandle<EcmaString> rightBrackets(globalConst->GetHandledRightSquareBracketString());
628                 JSHandle<EcmaString> concatName = factory->ConcatFromString(leftBrackets,
629                     JSHandle<EcmaString>(thread, JSSymbol::Cast(nameBegin->GetTaggedObject())->GetDescription()));
630                 concatName = factory->ConcatFromString(concatName, rightBrackets);
631                 nameHandle.Update(concatName.GetTaggedValue());
632             }
633         }
634         PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
635         JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, globalConst->GetHandledNameString(), nameDesc);
636     }
637 }
638 
GetInstanceJSHClass(JSThread * thread,JSHandle<JSFunction> constructor,JSHandle<JSTaggedValue> newTarget)639 JSHandle<JSHClass> JSFunction::GetInstanceJSHClass(JSThread *thread, JSHandle<JSFunction> constructor,
640                                                    JSHandle<JSTaggedValue> newTarget)
641 {
642     JSHandle<JSHClass> ctorInitialJSHClass(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
643     // newTarget is construct itself
644     if (newTarget.GetTaggedValue() == constructor.GetTaggedValue()) {
645         return ctorInitialJSHClass;
646     }
647 
648     // newTarget is derived-class of constructor
649     if (newTarget->IsJSFunction()) {
650         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
651         if (newTargetFunc->IsDerivedConstructor()) {
652             JSMutableHandle<JSTaggedValue> mutableNewTarget(thread, newTarget.GetTaggedValue());
653             JSMutableHandle<JSTaggedValue> mutableNewTargetProto(thread, JSTaggedValue::Undefined());
654             while (!mutableNewTargetProto->IsNull()) {
655                 mutableNewTargetProto.Update(JSTaggedValue::GetPrototype(thread, mutableNewTarget));
656                 if (mutableNewTargetProto.GetTaggedValue() == constructor.GetTaggedValue()) {
657                     return GetOrCreateDerivedJSHClass(thread, newTargetFunc, ctorInitialJSHClass);
658                 }
659                 mutableNewTarget.Update(mutableNewTargetProto.GetTaggedValue());
660             }
661         }
662     }
663 
664     // ECMA2015 9.1.15 3.Let proto be Get(constructor, "prototype").
665     JSMutableHandle<JSTaggedValue> prototype(thread, JSTaggedValue::Undefined());
666     if (newTarget->IsJSFunction()) {
667         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
668         FunctionKind kind = newTargetFunc->GetFunctionKind();
669         if (HasPrototype(kind)) {
670             prototype.Update(PrototypeGetter(thread, JSHandle<JSObject>::Cast(newTargetFunc)));
671         }
672     } else {
673         // Such case: bound function and define a "prototype" property.
674         JSHandle<JSTaggedValue> customizePrototype =
675             JSTaggedValue::GetProperty(thread, newTarget, thread->GlobalConstants()->GetHandledPrototypeString())
676                 .GetValue();
677         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread);
678         prototype.Update(customizePrototype.GetTaggedValue());
679         // Reload JSHClass of constructor, where the lookup of 'prototype' property may change it.
680         ctorInitialJSHClass = JSHandle<JSHClass>(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
681     }
682 
683     if (!prototype->IsECMAObject()) {
684         prototype.Update(constructor->GetFunctionPrototype());
685     }
686 
687     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
688     newJSHClass->SetPrototype(thread, prototype);
689 
690     return newJSHClass;
691 }
692 
GetOrCreateDerivedJSHClass(JSThread * thread,JSHandle<JSFunction> derived,JSHandle<JSHClass> ctorInitialJSHClass)693 JSHandle<JSHClass> JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle<JSFunction> derived,
694                                                           JSHandle<JSHClass> ctorInitialJSHClass)
695 {
696     JSTaggedValue protoOrHClass(derived->GetProtoOrHClass());
697     // has cached JSHClass, return directly
698     if (protoOrHClass.IsJSHClass()) {
699         return JSHandle<JSHClass>(thread, protoOrHClass);
700     }
701 
702     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
703     // guarante derived has function prototype
704     JSHandle<JSTaggedValue> prototype(thread, derived->GetProtoOrHClass());
705     ASSERT(!prototype->IsHole());
706     newJSHClass->SetPrototype(thread, prototype);
707     derived->SetProtoOrHClass(thread, newJSHClass);
708     return newJSHClass;
709 }
710 
711 // Those interface below is discarded
InitializeJSFunction(JSThread * thread,const JSHandle<GlobalEnv> & env,const JSHandle<JSFunction> & func,FunctionKind kind)712 void JSFunction::InitializeJSFunction(JSThread *thread, [[maybe_unused]] const JSHandle<GlobalEnv> &env,
713                                       const JSHandle<JSFunction> &func, FunctionKind kind)
714 {
715     InitializeJSFunction(thread, func, kind);
716 }
717 
NameSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)718 bool JSFunction::NameSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
719                             [[maybe_unused]] bool mayThrow)
720 {
721     if (self->IsPropertiesDict()) {
722         // replace setter with value
723         JSHandle<JSTaggedValue> nameString = thread->GlobalConstants()->GetHandledNameString();
724         return self->UpdatePropertyInDictionary(thread, nameString.GetTaggedValue(), value.GetTaggedValue());
725     }
726     self->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, value.GetTaggedValue());
727     return true;
728 }
729 
SetFunctionExtraInfo(JSThread * thread,void * nativeFunc,const DeleteEntryPoint & deleter,void * data,size_t nativeBindingsize)730 void JSFunction::SetFunctionExtraInfo(JSThread *thread, void *nativeFunc,
731                                       const DeleteEntryPoint &deleter, void *data, size_t nativeBindingsize)
732 {
733     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
734     EcmaVM *vm = thread->GetEcmaVM();
735     JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
736     JSHandle<ECMAObject> obj(thread, this);
737     JSHandle<JSNativePointer> pointer = vm->GetFactory()->NewJSNativePointer(nativeFunc, deleter, data,
738         false, nativeBindingsize);
739     if (!obj->HasHash()) {
740         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
741         return;
742     }
743     if (value->IsHeapObject()) {
744         if (value->IsJSNativePointer()) {
745             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
746             return;
747         }
748         JSHandle<TaggedArray> array(value);
749 
750         uint32_t nativeFieldCount = array->GetExtraLength();
751         if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
752             array->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
753         } else {
754             JSHandle<TaggedArray> newArray = vm->GetFactory()->NewTaggedArray(nativeFieldCount + RESOLVED_MAX_SIZE);
755             newArray->SetExtraLength(nativeFieldCount);
756             for (uint32_t i = 0; i < nativeFieldCount; i++) {
757                 newArray->Set(thread, i, array->Get(i));
758             }
759             newArray->Set(thread, nativeFieldCount + HASH_INDEX, array->Get(nativeFieldCount + HASH_INDEX));
760             newArray->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
761             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
762         }
763     } else {
764         JSHandle<TaggedArray> newArray = vm->GetFactory()->NewTaggedArray(RESOLVED_MAX_SIZE);
765         newArray->SetExtraLength(0);
766         newArray->Set(thread, HASH_INDEX, value);
767         newArray->Set(thread, FUNCTION_EXTRA_INDEX, pointer);
768         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
769     }
770 }
771 
GetFunctionExtraInfo() const772 JSTaggedValue JSFunction::GetFunctionExtraInfo() const
773 {
774     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
775     JSTaggedValue value(hashField);
776     if (value.IsHeapObject()) {
777         if (value.IsTaggedArray()) {
778             TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
779             uint32_t nativeFieldCount = array->GetExtraLength();
780             if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
781                 return array->Get(nativeFieldCount + FUNCTION_EXTRA_INDEX);
782             }
783         }
784         if (value.IsJSNativePointer()) {
785             return value;
786         }
787         LOG_ECMA(FATAL) << "this branch is unreachable";
788         UNREACHABLE();
789     }
790     return JSTaggedValue::Undefined();
791 }
792 
GetNativeFunctionExtraInfo() const793 JSTaggedValue JSFunction::GetNativeFunctionExtraInfo() const
794 {
795     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
796     JSTaggedValue value(hashField);
797     if (value.CheckIsJSNativePointer()) {
798         return value;
799     }
800     return JSTaggedValue::Undefined();
801 }
802 
GetRecordName() const803 JSTaggedValue JSFunction::GetRecordName() const
804 {
805     JSTaggedValue module = GetModule();
806     if (module.IsSourceTextModule()) {
807         JSTaggedValue recordName = SourceTextModule::Cast(module.GetTaggedObject())->GetEcmaModuleRecordName();
808         if (!recordName.IsString()) {
809             LOG_INTERPRETER(DEBUG) << "module record name is undefined";
810             return JSTaggedValue::Hole();
811         }
812         return recordName;
813     }
814     if (module.IsString()) {
815         return module;
816     }
817     LOG_INTERPRETER(DEBUG) << "record name is undefined";
818     return JSTaggedValue::Hole();
819 }
820 }  // namespace panda::ecmascript
821