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