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