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