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