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 return type->GetMethod(LAMBDA_METHOD_NAME);
54 }
55
Invoke(napi::ScopedManagedCodeFix * s,Value * args)56 EtsValue EtsMethod::Invoke(napi::ScopedManagedCodeFix *s, Value *args)
57 {
58 Value res = GetPandaMethod()->Invoke(s->GetEtsCoroutine(), args);
59 if (GetReturnValueType() == EtsType::VOID) {
60 // Return any value, will be ignored
61 return EtsValue(0);
62 }
63 if (GetReturnValueType() == EtsType::OBJECT) {
64 auto *obj = reinterpret_cast<EtsObject *>(res.GetAs<ObjectHeader *>());
65 if (obj == nullptr) {
66 return EtsValue(nullptr);
67 }
68 return EtsValue(napi::ScopedManagedCodeFix::AddLocalRef(s->EtsNapiEnv(), obj));
69 }
70
71 return EtsValue(res.GetAs<EtsLong>());
72 }
73
GetNumArgSlots() const74 uint32_t EtsMethod::GetNumArgSlots() const
75 {
76 uint32_t numOfSlots = 0;
77 auto proto = GetPandaMethod()->GetProto();
78 auto &shorty = proto.GetShorty();
79 auto shortyEnd = shorty.end();
80 // must skip the return type
81 auto shortyIt = shorty.begin() + 1;
82 for (; shortyIt != shortyEnd; ++shortyIt) {
83 auto argTypeId = shortyIt->GetId();
84 // double and long arguments take two slots
85 if (argTypeId == panda_file::Type::TypeId::I64 || argTypeId == panda_file::Type::TypeId::F64) {
86 numOfSlots += 2U;
87 } else {
88 numOfSlots += 1U;
89 }
90 }
91 if (!IsStatic()) {
92 ++numOfSlots;
93 }
94 return numOfSlots;
95 }
96
ResolveArgType(uint32_t idx)97 EtsClass *EtsMethod::ResolveArgType(uint32_t idx)
98 {
99 if (!IsStatic()) {
100 if (idx == 0) {
101 return GetClass();
102 }
103 }
104
105 // get reference type
106 EtsClassLinker *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
107 auto type = GetPandaMethod()->GetArgType(idx);
108 if (!type.IsPrimitive()) {
109 size_t refIdx = 0;
110 size_t shortEnd = IsStatic() ? (idx + 1) : idx; // first is return type
111 auto proto = GetPandaMethod()->GetProto();
112 for (size_t shortIdx = 0; shortIdx < shortEnd; shortIdx++) {
113 if (proto.GetShorty()[shortIdx].IsReference()) {
114 refIdx++;
115 }
116 }
117 ASSERT(refIdx <= proto.GetRefTypes().size());
118 return classLinker->GetClass(proto.GetRefTypes()[refIdx].data(), false, GetClass()->GetClassLoader());
119 }
120
121 // get primitive type
122 switch (type.GetId()) {
123 case panda_file::Type::TypeId::U1:
124 return classLinker->GetClassRoot(EtsClassRoot::BOOLEAN);
125 case panda_file::Type::TypeId::I8:
126 return classLinker->GetClassRoot(EtsClassRoot::BYTE);
127 case panda_file::Type::TypeId::I16:
128 return classLinker->GetClassRoot(EtsClassRoot::SHORT);
129 case panda_file::Type::TypeId::U16:
130 return classLinker->GetClassRoot(EtsClassRoot::CHAR);
131 case panda_file::Type::TypeId::I32:
132 return classLinker->GetClassRoot(EtsClassRoot::INT);
133 case panda_file::Type::TypeId::I64:
134 return classLinker->GetClassRoot(EtsClassRoot::LONG);
135 case panda_file::Type::TypeId::F32:
136 return classLinker->GetClassRoot(EtsClassRoot::FLOAT);
137 case panda_file::Type::TypeId::F64:
138 return classLinker->GetClassRoot(EtsClassRoot::DOUBLE);
139 default:
140 LOG(FATAL, RUNTIME) << "ResolveArgType: not a valid ets type for " << type;
141 return nullptr;
142 };
143 }
144
GetMethodSignature(bool includeReturnType) const145 PandaString EtsMethod::GetMethodSignature(bool includeReturnType) const
146 {
147 PandaOStringStream signature;
148 auto proto = GetPandaMethod()->GetProto();
149 auto &shorty = proto.GetShorty();
150 auto &refTypes = proto.GetRefTypes();
151
152 auto refIt = refTypes.begin();
153 panda_file::Type returnType = shorty[0];
154 if (!returnType.IsPrimitive()) {
155 ++refIt;
156 }
157
158 auto shortyEnd = shorty.end();
159 auto shortyIt = shorty.begin() + 1;
160 for (; shortyIt != shortyEnd; ++shortyIt) {
161 if ((*shortyIt).IsPrimitive()) {
162 signature << panda_file::Type::GetSignatureByTypeId(*shortyIt);
163 } else {
164 signature << *refIt;
165 ++refIt;
166 }
167 }
168
169 if (includeReturnType) {
170 signature << ":";
171 if (returnType.IsPrimitive()) {
172 signature << panda_file::Type::GetSignatureByTypeId(returnType);
173 } else {
174 signature << refTypes[0];
175 }
176 }
177 return signature.str();
178 }
179
GetDescriptor() const180 PandaString EtsMethod::GetDescriptor() const
181 {
182 constexpr size_t TD_MAX_SIZE = 256;
183 std::array<char, TD_MAX_SIZE> actualTd; // NOLINT(cppcoreguidelines-pro-type-member-init)
184 // initialize in printf
185 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
186 snprintf_s(actualTd.data(), actualTd.size(), actualTd.size() - 1, "%c%" PRIu64 ";%" PRIu64 ";", METHOD_PREFIX,
187 reinterpret_cast<uint64_t>(GetPandaMethod()->GetPandaFile()),
188 static_cast<uint64_t>(GetPandaMethod()->GetFileId().GetOffset()));
189 return {actualTd.data()};
190 }
191
192 } // namespace ark::ets
193