1 /*
2 * Copyright (c) 2021-2025 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 <cctype>
17 #include "ets_coroutine.h"
18 #include "handle_scope.h"
19 #include "include/mem/panda_containers.h"
20 #include "macros.h"
21 #include "mem/mem.h"
22 #include "mem/vm_handle.h"
23 #include "types/ets_array.h"
24 #include "types/ets_box_primitive.h"
25 #include "types/ets_box_primitive-inl.h"
26 #include "types/ets_class.h"
27 #include "types/ets_method.h"
28 #include "types/ets_object.h"
29 #include "types/ets_type.h"
30 #include "types/ets_type_comptime_traits.h"
31 #include "types/ets_typeapi_method.h"
32 #include "types/ets_typeapi_type.h"
33
34 namespace ark::ets::intrinsics {
35
36 namespace {
37 // NOTE: requires parent handle scope
TypeAPIMethodInvokeImplementation(EtsCoroutine * coro,EtsMethod * meth,EtsObject * recv,EtsArray * args)38 EtsObject *TypeAPIMethodInvokeImplementation(EtsCoroutine *coro, EtsMethod *meth, EtsObject *recv, EtsArray *args)
39 {
40 if (meth->IsAbstract()) {
41 ASSERT(recv != nullptr);
42 meth = recv->GetClass()->ResolveVirtualMethod(meth);
43 }
44 size_t methArgsCount = meth->GetNumArgs();
45 PandaVector<Value> realArgs {methArgsCount};
46 size_t firstRealArg = 0;
47 if (!meth->IsStatic()) {
48 realArgs[0] = Value(recv->GetCoreType());
49 firstRealArg = 1;
50 }
51
52 size_t argsLength = args->GetLength();
53 if (methArgsCount - firstRealArg != argsLength) {
54 UNREACHABLE();
55 }
56
57 for (size_t i = 0; i < argsLength; i++) {
58 // issue #14003
59 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
60 auto arg = args->GetCoreType()->Get<ObjectHeader *>(i);
61 auto argType = meth->GetArgType(firstRealArg + i);
62 if (argType == EtsType::OBJECT) {
63 realArgs[firstRealArg + i] = Value(arg);
64 continue;
65 }
66 EtsPrimitiveTypeEnumToComptimeConstant(argType, [&](auto type) -> void {
67 using T = EtsTypeEnumToCppType<decltype(type)::value>;
68 realArgs[firstRealArg + i] =
69 Value(EtsBoxPrimitive<T>::FromCoreType(EtsObject::FromCoreType(arg))->GetValue());
70 });
71 }
72
73 ASSERT(meth->GetPandaMethod()->GetNumArgs() == realArgs.size());
74 auto res = meth->GetPandaMethod()->Invoke(coro, realArgs.data());
75 if (res.IsReference()) {
76 return EtsObject::FromCoreType(res.GetAs<ObjectHeader *>());
77 }
78
79 if (meth->GetReturnValueType() == EtsType::VOID) {
80 return nullptr;
81 }
82
83 ASSERT(res.IsPrimitive());
84 // CC-OFFNXT(G.FMT.14-CPP) project code style
85 return EtsPrimitiveTypeEnumToComptimeConstant(meth->GetReturnValueType(), [&](auto type) -> EtsObject * {
86 using T = EtsTypeEnumToCppType<decltype(type)::value>;
87 return EtsBoxPrimitive<T>::Create(coro, res.GetAs<T>());
88 });
89 }
90
GetEtsMethod(ObjectHeader * methodTypeObj)91 EtsMethod *GetEtsMethod(ObjectHeader *methodTypeObj)
92 {
93 ASSERT(methodTypeObj != nullptr);
94 auto *methodType = EtsTypeAPIType::FromCoreType(methodTypeObj);
95 return EtsMethod::FromTypeDescriptor(methodType->GetRuntimeTypeDescriptor()->GetMutf8(),
96 methodType->GetContextLinker());
97 }
98 } // namespace
99
100 extern "C" {
TypeAPIMethodInvoke(ObjectHeader * methodTypeObj,EtsObject * recv,EtsArray * args)101 EtsObject *TypeAPIMethodInvoke(ObjectHeader *methodTypeObj, EtsObject *recv, EtsArray *args)
102 {
103 auto coro = EtsCoroutine::GetCurrent();
104 [[maybe_unused]] HandleScope<ObjectHeader *> scope {coro};
105 VMHandle<EtsObject> recvHandle {coro, recv->GetCoreType()};
106 VMHandle<EtsArray> argsHandle {coro, args->GetCoreType()};
107 // this method shouldn't trigger gc, because class is loaded,
108 // however static analyzer blames this line
109 auto *meth = GetEtsMethod(methodTypeObj);
110 ASSERT(meth != nullptr);
111 return TypeAPIMethodInvokeImplementation(coro, meth, recvHandle.GetPtr(), argsHandle.GetPtr());
112 }
113
TypeAPIMethodInvokeConstructor(ObjectHeader * methodTypeObj,EtsArray * args)114 EtsObject *TypeAPIMethodInvokeConstructor(ObjectHeader *methodTypeObj, EtsArray *args)
115 {
116 auto coro = EtsCoroutine::GetCurrent();
117 [[maybe_unused]] HandleScope<ObjectHeader *> scope {coro};
118 VMHandle<EtsArray> argsHandle {coro, args->GetCoreType()};
119
120 auto *meth = GetEtsMethod(methodTypeObj);
121 ASSERT(meth != nullptr);
122 ASSERT(meth->IsConstructor());
123 auto klass = meth->GetClass()->GetRuntimeClass();
124 auto initedObj = ObjectHeader::Create(coro, klass);
125 ASSERT(initedObj->ClassAddr<Class>() == klass);
126 VMHandle<EtsObject> ret {coro, initedObj};
127 TypeAPIMethodInvokeImplementation(coro, meth, ret.GetPtr(), argsHandle.GetPtr());
128 return ret.GetPtr();
129 }
130 }
131
132 } // namespace ark::ets::intrinsics
133