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 "macros.h"
17 #include "runtime/include/class_linker.h"
18 #include "runtime/include/runtime.h"
19 #include "runtime/include/value-inl.h"
20 #include "plugins/ets/runtime/types/ets_array.h"
21 #include "plugins/ets/runtime/types/ets_method.h"
22 #include "plugins/ets/runtime/napi/ets_scoped_objects_fix.h"
23 #include "plugins/ets/runtime/types/ets_primitives.h"
24 #include "types/ets_type.h"
25
26 namespace ark::ets {
27
28 class EtsObject;
29
IsMethod(const PandaString & td)30 bool EtsMethod::IsMethod(const PandaString &td)
31 {
32 return td[0] == METHOD_PREFIX;
33 }
34
FromTypeDescriptor(const PandaString & td)35 EtsMethod *EtsMethod::FromTypeDescriptor(const PandaString &td)
36 {
37 EtsClassLinker *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
38 if (td[0] == METHOD_PREFIX) {
39 // here we resolve method in existing class, which is stored as pointer to panda file + entity id
40 uint64_t filePtr;
41 uint64_t id;
42 const auto scanfStr = std::string_view {td}.substr(1).data();
43 // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg,cert-err34-c)
44 [[maybe_unused]] auto res = sscanf_s(scanfStr, "%" PRIu64 ";%" PRIu64 ";", &filePtr, &id);
45 // NOLINTEND(cppcoreguidelines-pro-type-vararg,cert-err34-c)
46 [[maybe_unused]] static constexpr int SCANF_PARAM_CNT = 2;
47 ASSERT(res == SCANF_PARAM_CNT);
48 auto pandaFile = reinterpret_cast<const panda_file::File *>(filePtr);
49 return EtsMethod::FromRuntimeMethod(classLinker->GetMethod(*pandaFile, panda_file::File::EntityId(id)));
50 }
51 ASSERT(td[0] == CLASS_TYPE_PREFIX);
52 auto type = classLinker->GetClass(td.c_str());
53
54 auto method = type->GetMethod(LAMBDA_METHOD_NAME);
55 if (method != nullptr) {
56 return method;
57 }
58
59 return type->GetMethod(FN_INVOKE_METHOD_NAME);
60 }
61
Invoke(napi::ScopedManagedCodeFix * s,Value * args)62 EtsValue EtsMethod::Invoke(napi::ScopedManagedCodeFix *s, Value *args)
63 {
64 Value res = GetPandaMethod()->Invoke(s->GetEtsCoroutine(), args);
65 if (GetReturnValueType() == EtsType::VOID) {
66 // Return any value, will be ignored
67 return EtsValue(0);
68 }
69 if (GetReturnValueType() == EtsType::OBJECT) {
70 auto *obj = reinterpret_cast<EtsObject *>(res.GetAs<ObjectHeader *>());
71 if (obj == nullptr) {
72 return EtsValue(nullptr);
73 }
74 return EtsValue(napi::ScopedManagedCodeFix::AddLocalRef(s->EtsNapiEnv(), obj));
75 }
76
77 return EtsValue(res.GetAs<EtsLong>());
78 }
79
GetNumArgSlots() const80 uint32_t EtsMethod::GetNumArgSlots() const
81 {
82 uint32_t numOfSlots = 0;
83 auto proto = GetPandaMethod()->GetProto();
84 auto &shorty = proto.GetShorty();
85 auto shortyEnd = shorty.end();
86 // must skip the return type
87 auto shortyIt = shorty.begin() + 1;
88 for (; shortyIt != shortyEnd; ++shortyIt) {
89 auto argTypeId = shortyIt->GetId();
90 // double and long arguments take two slots
91 if (argTypeId == panda_file::Type::TypeId::I64 || argTypeId == panda_file::Type::TypeId::F64) {
92 numOfSlots += 2U;
93 } else {
94 numOfSlots += 1U;
95 }
96 }
97 if (!IsStatic()) {
98 ++numOfSlots;
99 }
100 return numOfSlots;
101 }
102
ResolveArgType(uint32_t idx)103 EtsClass *EtsMethod::ResolveArgType(uint32_t idx)
104 {
105 if (!IsStatic()) {
106 if (idx == 0) {
107 return GetClass();
108 }
109 }
110
111 // get reference type
112 EtsClassLinker *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
113 auto type = GetPandaMethod()->GetArgType(idx);
114 if (!type.IsPrimitive()) {
115 size_t refIdx = 0;
116 size_t shortEnd = IsStatic() ? (idx + 1) : idx; // first is return type
117 auto proto = GetPandaMethod()->GetProto();
118 for (size_t shortIdx = 0; shortIdx < shortEnd; shortIdx++) {
119 if (proto.GetShorty()[shortIdx].IsReference()) {
120 refIdx++;
121 }
122 }
123 ASSERT(refIdx <= proto.GetRefTypes().size());
124 return classLinker->GetClass(proto.GetRefTypes()[refIdx].data(), false, GetClass()->GetLoadContext());
125 }
126
127 // get primitive type
128 switch (type.GetId()) {
129 case panda_file::Type::TypeId::U1:
130 return classLinker->GetClassRoot(EtsClassRoot::BOOLEAN);
131 case panda_file::Type::TypeId::I8:
132 return classLinker->GetClassRoot(EtsClassRoot::BYTE);
133 case panda_file::Type::TypeId::I16:
134 return classLinker->GetClassRoot(EtsClassRoot::SHORT);
135 case panda_file::Type::TypeId::U16:
136 return classLinker->GetClassRoot(EtsClassRoot::CHAR);
137 case panda_file::Type::TypeId::I32:
138 return classLinker->GetClassRoot(EtsClassRoot::INT);
139 case panda_file::Type::TypeId::I64:
140 return classLinker->GetClassRoot(EtsClassRoot::LONG);
141 case panda_file::Type::TypeId::F32:
142 return classLinker->GetClassRoot(EtsClassRoot::FLOAT);
143 case panda_file::Type::TypeId::F64:
144 return classLinker->GetClassRoot(EtsClassRoot::DOUBLE);
145 default:
146 LOG(FATAL, RUNTIME) << "ResolveArgType: not a valid ets type for " << type;
147 return nullptr;
148 };
149 }
150
GetMethodSignature(bool includeReturnType) const151 PandaString EtsMethod::GetMethodSignature(bool includeReturnType) const
152 {
153 PandaOStringStream signature;
154 auto proto = GetPandaMethod()->GetProto();
155 auto &shorty = proto.GetShorty();
156 auto &refTypes = proto.GetRefTypes();
157
158 auto refIt = refTypes.begin();
159 panda_file::Type returnType = shorty[0];
160 if (!returnType.IsPrimitive()) {
161 ++refIt;
162 }
163
164 auto shortyEnd = shorty.end();
165 auto shortyIt = shorty.begin() + 1;
166 for (; shortyIt != shortyEnd; ++shortyIt) {
167 if ((*shortyIt).IsPrimitive()) {
168 signature << panda_file::Type::GetSignatureByTypeId(*shortyIt);
169 } else {
170 signature << *refIt;
171 ++refIt;
172 }
173 }
174
175 if (includeReturnType) {
176 signature << ":";
177 if (returnType.IsPrimitive()) {
178 signature << panda_file::Type::GetSignatureByTypeId(returnType);
179 } else {
180 signature << refTypes[0];
181 }
182 }
183 return signature.str();
184 }
185
GetDescriptor() const186 PandaString EtsMethod::GetDescriptor() const
187 {
188 constexpr size_t TD_MAX_SIZE = 256;
189 std::array<char, TD_MAX_SIZE> actualTd; // NOLINT(cppcoreguidelines-pro-type-member-init)
190 // initialize in printf
191 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
192 snprintf_s(actualTd.data(), actualTd.size(), actualTd.size() - 1, "%c%" PRIu64 ";%" PRIu64 ";", METHOD_PREFIX,
193 reinterpret_cast<uint64_t>(GetPandaMethod()->GetPandaFile()),
194 static_cast<uint64_t>(GetPandaMethod()->GetFileId().GetOffset()));
195 return {actualTd.data()};
196 }
197
198 } // namespace ark::ets
199