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 <string>
17
18 #include "ets_runtime_interface.h"
19 #include "plugins/ets/runtime/ets_class_linker_extension.h"
20 #include "types/ets_method.h"
21
22 namespace ark::ets {
GetClass(MethodPtr method,IdType id) const23 compiler::RuntimeInterface::ClassPtr EtsRuntimeInterface::GetClass(MethodPtr method, IdType id) const
24 {
25 if (id == RuntimeInterface::MEM_PROMISE_CLASS_ID) {
26 return PandaEtsVM::GetCurrent()->GetClassLinker()->GetEtsClassLinkerExtension()->GetPromiseClass();
27 }
28 return PandaRuntimeInterface::GetClass(method, id);
29 }
30
ResolveLookUpField(FieldPtr rawField,ClassPtr klass)31 compiler::RuntimeInterface::FieldPtr EtsRuntimeInterface::ResolveLookUpField(FieldPtr rawField, ClassPtr klass)
32 {
33 ASSERT(rawField != nullptr);
34 ASSERT(klass != nullptr);
35 return ClassCast(klass)->LookupFieldByName(FieldCast(rawField)->GetName());
36 }
37
38 template <panda_file::Type::TypeId FIELD_TYPE>
GetLookUpCall(FieldPtr rawField,ClassPtr klass,bool isSetter)39 compiler::RuntimeInterface::MethodPtr EtsRuntimeInterface::GetLookUpCall(FieldPtr rawField, ClassPtr klass,
40 bool isSetter)
41 {
42 if (isSetter) {
43 return ClassCast(klass)->LookupSetterByName<FIELD_TYPE>(FieldCast(rawField)->GetName());
44 }
45 return ClassCast(klass)->LookupGetterByName<FIELD_TYPE>(FieldCast(rawField)->GetName());
46 }
47
ResolveLookUpCall(FieldPtr rawField,ClassPtr klass,bool isSetter)48 compiler::RuntimeInterface::MethodPtr EtsRuntimeInterface::ResolveLookUpCall(FieldPtr rawField, ClassPtr klass,
49 bool isSetter)
50 {
51 ASSERT(rawField != nullptr);
52 ASSERT(klass != nullptr);
53 switch (FieldCast(rawField)->GetTypeId()) {
54 case panda_file::Type::TypeId::U1:
55 return GetLookUpCall<panda_file::Type::TypeId::U1>(rawField, klass, isSetter);
56 case panda_file::Type::TypeId::U8:
57 return GetLookUpCall<panda_file::Type::TypeId::U8>(rawField, klass, isSetter);
58 case panda_file::Type::TypeId::I8:
59 return GetLookUpCall<panda_file::Type::TypeId::I8>(rawField, klass, isSetter);
60 case panda_file::Type::TypeId::I16:
61 return GetLookUpCall<panda_file::Type::TypeId::I16>(rawField, klass, isSetter);
62 case panda_file::Type::TypeId::U16:
63 return GetLookUpCall<panda_file::Type::TypeId::U16>(rawField, klass, isSetter);
64 case panda_file::Type::TypeId::I32:
65 return GetLookUpCall<panda_file::Type::TypeId::I32>(rawField, klass, isSetter);
66 case panda_file::Type::TypeId::U32:
67 return GetLookUpCall<panda_file::Type::TypeId::U32>(rawField, klass, isSetter);
68 case panda_file::Type::TypeId::I64:
69 return GetLookUpCall<panda_file::Type::TypeId::I64>(rawField, klass, isSetter);
70 case panda_file::Type::TypeId::U64:
71 return GetLookUpCall<panda_file::Type::TypeId::U64>(rawField, klass, isSetter);
72 case panda_file::Type::TypeId::F32:
73 return GetLookUpCall<panda_file::Type::TypeId::F32>(rawField, klass, isSetter);
74 case panda_file::Type::TypeId::F64:
75 return GetLookUpCall<panda_file::Type::TypeId::F64>(rawField, klass, isSetter);
76 case panda_file::Type::TypeId::REFERENCE:
77 return GetLookUpCall<panda_file::Type::TypeId::REFERENCE>(rawField, klass, isSetter);
78 default: {
79 UNREACHABLE();
80 break;
81 }
82 }
83 return nullptr;
84 }
85
GetUndefinedObject() const86 uint64_t EtsRuntimeInterface::GetUndefinedObject() const
87 {
88 return ToUintPtr(PandaEtsVM::GetCurrent()->GetUndefinedObject());
89 }
90
GetInteropCallKind(MethodPtr methodPtr) const91 compiler::RuntimeInterface::InteropCallKind EtsRuntimeInterface::GetInteropCallKind(MethodPtr methodPtr) const
92 {
93 auto className = GetClassNameFromMethod(methodPtr);
94 auto classNameSuffix = className.substr(className.find_last_of('.') + 1);
95 if (classNameSuffix == "$jsnew") {
96 return InteropCallKind::NEW_INSTANCE;
97 }
98 if (classNameSuffix != "$jscall") {
99 return InteropCallKind::UNKNOWN;
100 }
101
102 auto method = MethodCast(methodPtr);
103
104 ASSERT(method->GetArgType(0).IsReference()); // arg0 is always a reference
105 if (method->GetArgType(1).IsReference()) {
106 auto pf = method->GetPandaFile();
107 panda_file::ProtoDataAccessor pda(*pf, panda_file::MethodDataAccessor::GetProtoId(*pf, method->GetFileId()));
108 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
109 auto linkerCtx = method->GetClass()->GetLoadContext();
110 uint32_t const argReftypeShift = method->GetReturnType().IsReference() ? 1 : 0;
111 ScopedMutatorLock lock;
112 auto cls = classLinker->GetClass(*pf, pda.GetReferenceType(1 + argReftypeShift), linkerCtx);
113 if (!cls->IsStringClass()) {
114 return InteropCallKind::CALL_BY_VALUE;
115 }
116 } else {
117 // arg1 and arg2 are start position and length of qualified name
118 ASSERT(method->GetArgType(1).GetId() == panda_file::Type::TypeId::I32);
119 ASSERT(method->GetArgType(2U).GetId() == panda_file::Type::TypeId::I32);
120 }
121 return InteropCallKind::CALL;
122 }
123
GetFuncPropName(MethodPtr methodPtr,uint32_t strId) const124 char *EtsRuntimeInterface::GetFuncPropName(MethodPtr methodPtr, uint32_t strId) const
125 {
126 auto method = MethodCast(methodPtr);
127 auto pf = method->GetPandaFile();
128 auto str = reinterpret_cast<const char *>(pf->GetStringData(ark::panda_file::File::EntityId(strId)).data);
129 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
130 return const_cast<char *>(std::strrchr(str, '.') + 1);
131 }
132
GetFuncPropNameOffset(MethodPtr methodPtr,uint32_t strId) const133 uint64_t EtsRuntimeInterface::GetFuncPropNameOffset(MethodPtr methodPtr, uint32_t strId) const
134 {
135 auto pf = MethodCast(methodPtr)->GetPandaFile();
136 auto str = GetFuncPropName(methodPtr, strId);
137 return reinterpret_cast<uint64_t>(str) - reinterpret_cast<uint64_t>(pf->GetBase());
138 }
139
IsMethodStringConcat(MethodPtr method) const140 bool EtsRuntimeInterface::IsMethodStringConcat(MethodPtr method) const
141 {
142 return GetMethodFullName(method, false) == "std.core.String::concat" &&
143 MethodCast(method)->GetProto().GetSignature() == "([Lstd/core/String;)Lstd/core/String;";
144 }
145
IsMethodStringBuilderConstructorWithStringArg(MethodPtr method) const146 bool EtsRuntimeInterface::IsMethodStringBuilderConstructorWithStringArg(MethodPtr method) const
147 {
148 return MethodCast(method)->IsConstructor() && GetClassNameFromMethod(method) == "std.core.StringBuilder" &&
149 MethodCast(method)->GetProto().GetSignature() == "(Lstd/core/String;)V";
150 }
151
IsMethodStringBuilderConstructorWithCharArrayArg(MethodPtr method) const152 bool EtsRuntimeInterface::IsMethodStringBuilderConstructorWithCharArrayArg(MethodPtr method) const
153 {
154 return MethodCast(method)->IsConstructor() && GetClassNameFromMethod(method) == "std.core.StringBuilder" &&
155 MethodCast(method)->GetProto().GetSignature() == "([C)V";
156 }
157
IsMethodStringBuilderDefaultConstructor(MethodPtr method) const158 bool EtsRuntimeInterface::IsMethodStringBuilderDefaultConstructor(MethodPtr method) const
159 {
160 return MethodCast(method)->IsConstructor() && GetClassNameFromMethod(method) == "std.core.StringBuilder" &&
161 MethodCast(method)->GetProto().GetSignature() == "()V";
162 }
163
IsMethodStringBuilderToString(MethodPtr method) const164 bool EtsRuntimeInterface::IsMethodStringBuilderToString(MethodPtr method) const
165 {
166 return GetMethodFullName(method, false) == "std.core.StringBuilder::toString" &&
167 MethodCast(method)->GetProto().GetSignature() == "()Lstd/core/String;";
168 }
169
IsMethodStringBuilderAppend(MethodPtr method) const170 bool EtsRuntimeInterface::IsMethodStringBuilderAppend(MethodPtr method) const
171 {
172 return GetMethodFullName(method, false) == "std.core.StringBuilder::append";
173 }
174
IsClassStringBuilder(ClassPtr klass) const175 bool EtsRuntimeInterface::IsClassStringBuilder(ClassPtr klass) const
176 {
177 return ClassCast(klass)->GetName() == "std.core.StringBuilder";
178 }
179
GetClassOffsetObjectsArray(MethodPtr method) const180 uint32_t EtsRuntimeInterface::GetClassOffsetObjectsArray(MethodPtr method) const
181 {
182 auto pf = MethodCast(method)->GetPandaFile();
183 return pf->GetClassId(utf::CStringAsMutf8("[Lstd/core/Object;")).GetOffset();
184 }
185
GetClassOffsetObject(MethodPtr method) const186 uint32_t EtsRuntimeInterface::GetClassOffsetObject(MethodPtr method) const
187 {
188 auto pf = MethodCast(method)->GetPandaFile();
189 return pf->GetClassId(utf::CStringAsMutf8("std.core.Object")).GetOffset();
190 }
191
GetStringBuilderClass() const192 EtsRuntimeInterface::ClassPtr EtsRuntimeInterface::GetStringBuilderClass() const
193 {
194 return PandaEtsVM::GetCurrent()->GetClassLinker()->GetEtsClassLinkerExtension()->GetStringBuilderClass();
195 }
196
GetStringBuilderDefaultConstructor() const197 EtsRuntimeInterface::MethodPtr EtsRuntimeInterface::GetStringBuilderDefaultConstructor() const
198 {
199 auto classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
200 for (auto ctor : classLinker->GetStringBuilderClass()->GetConstructors()) {
201 if (IsMethodStringBuilderDefaultConstructor(ctor)) {
202 return ctor;
203 }
204 }
205
206 UNREACHABLE();
207 }
208
GetMethodId(MethodPtr method) const209 uint32_t EtsRuntimeInterface::GetMethodId(MethodPtr method) const
210 {
211 ASSERT(method != nullptr);
212 return static_cast<EtsMethod *>(method)->GetMethodId();
213 }
214
GetFieldStringBuilderBuffer(ClassPtr klass) const215 EtsRuntimeInterface::FieldPtr EtsRuntimeInterface::GetFieldStringBuilderBuffer(ClassPtr klass) const
216 {
217 ASSERT(IsClassStringBuilder(klass));
218 return ClassCast(klass)->GetInstanceFieldByName(utf::CStringAsMutf8("buf"));
219 }
220
GetFieldStringBuilderIndex(ClassPtr klass) const221 EtsRuntimeInterface::FieldPtr EtsRuntimeInterface::GetFieldStringBuilderIndex(ClassPtr klass) const
222 {
223 ASSERT(IsClassStringBuilder(klass));
224 return ClassCast(klass)->GetInstanceFieldByName(utf::CStringAsMutf8("index"));
225 }
226
GetFieldStringBuilderLength(ClassPtr klass) const227 EtsRuntimeInterface::FieldPtr EtsRuntimeInterface::GetFieldStringBuilderLength(ClassPtr klass) const
228 {
229 ASSERT(IsClassStringBuilder(klass));
230 return ClassCast(klass)->GetInstanceFieldByName(utf::CStringAsMutf8("length"));
231 }
232
GetFieldStringBuilderCompress(ClassPtr klass) const233 EtsRuntimeInterface::FieldPtr EtsRuntimeInterface::GetFieldStringBuilderCompress(ClassPtr klass) const
234 {
235 ASSERT(IsClassStringBuilder(klass));
236 return ClassCast(klass)->GetInstanceFieldByName(utf::CStringAsMutf8("compress"));
237 }
238
IsFieldStringBuilderBuffer(FieldPtr field) const239 bool EtsRuntimeInterface::IsFieldStringBuilderBuffer(FieldPtr field) const
240 {
241 return IsClassStringBuilder(FieldCast(field)->GetClass()) && GetFieldName(field) == "buf";
242 }
243
IsFieldStringBuilderIndex(FieldPtr field) const244 bool EtsRuntimeInterface::IsFieldStringBuilderIndex(FieldPtr field) const
245 {
246 return IsClassStringBuilder(FieldCast(field)->GetClass()) && GetFieldName(field) == "index";
247 }
248
IsIntrinsicStringBuilderToString(IntrinsicId id) const249 bool EtsRuntimeInterface::IsIntrinsicStringBuilderToString(IntrinsicId id) const
250 {
251 return id == RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_SB_TO_STRING;
252 }
253
IsIntrinsicStringBuilderAppendString(IntrinsicId id) const254 bool EtsRuntimeInterface::IsIntrinsicStringBuilderAppendString(IntrinsicId id) const
255 {
256 switch (id) {
257 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING:
258 return true;
259 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING2:
260 return true;
261 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING3:
262 return true;
263 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING4:
264 return true;
265 default:
266 return false;
267 }
268 }
269
IsIntrinsicStringBuilderAppend(IntrinsicId id) const270 bool EtsRuntimeInterface::IsIntrinsicStringBuilderAppend(IntrinsicId id) const
271 {
272 switch (id) {
273 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_FLOAT:
274 return true;
275 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_DOUBLE:
276 return true;
277 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_LONG:
278 return true;
279 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_INT:
280 return true;
281 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_BYTE:
282 return true;
283 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_SHORT:
284 return true;
285 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_CHAR:
286 return true;
287 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_BOOL:
288 return true;
289 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING:
290 return true;
291 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING2:
292 return true;
293 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING3:
294 return true;
295 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING4:
296 return true;
297 default:
298 return false;
299 }
300 }
301
ConvertTypeToStringBuilderAppendIntrinsicId(compiler::DataType::Type type) const302 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::ConvertTypeToStringBuilderAppendIntrinsicId(
303 compiler::DataType::Type type) const
304 {
305 switch (type) {
306 case compiler::DataType::BOOL:
307 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_BOOL;
308 case compiler::DataType::INT8:
309 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_CHAR;
310 case compiler::DataType::UINT8:
311 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_BYTE;
312 case compiler::DataType::INT16:
313 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_SHORT;
314 case compiler::DataType::INT32:
315 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_INT;
316 case compiler::DataType::INT64:
317 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_LONG;
318 case compiler::DataType::FLOAT64:
319 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_DOUBLE;
320 case compiler::DataType::FLOAT32:
321 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_FLOAT;
322 case compiler::DataType::REFERENCE:
323 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING;
324 default:
325 UNREACHABLE();
326 }
327 return IntrinsicId::INVALID;
328 }
329
GetStringConcatStringsIntrinsicId(size_t numArgs) const330 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::GetStringConcatStringsIntrinsicId(size_t numArgs) const
331 {
332 // NOLINTBEGIN(readability-magic-numbers)
333 switch (numArgs) {
334 case 2U:
335 return IntrinsicId::INTRINSIC_STD_CORE_STRING_CONCAT2;
336 case 3U:
337 return IntrinsicId::INTRINSIC_STD_CORE_STRING_CONCAT3;
338 case 4U:
339 return IntrinsicId::INTRINSIC_STD_CORE_STRING_CONCAT4;
340 default:
341 UNREACHABLE();
342 }
343 // NOLINTEND(readability-magic-numbers)
344 }
345
GetStringIsCompressedIntrinsicId() const346 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::GetStringIsCompressedIntrinsicId() const
347 {
348 return IntrinsicId::INTRINSIC_STD_CORE_STRING_IS_COMPRESSED;
349 }
350
GetStringBuilderAppendStringsIntrinsicId(size_t numArgs) const351 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::GetStringBuilderAppendStringsIntrinsicId(size_t numArgs) const
352 {
353 // NOLINTBEGIN(readability-magic-numbers)
354 switch (numArgs) {
355 case 1U:
356 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING;
357 case 2U:
358 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING2;
359 case 3U:
360 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING3;
361 case 4U:
362 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING4;
363 default:
364 UNREACHABLE();
365 }
366 // NOLINTEND(readability-magic-numbers)
367 }
368
GetStringBuilderToStringIntrinsicId() const369 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::GetStringBuilderToStringIntrinsicId() const
370 {
371 return IntrinsicId::INTRINSIC_STD_CORE_SB_TO_STRING;
372 }
373
IsClassValueTyped(ClassPtr klass) const374 bool EtsRuntimeInterface::IsClassValueTyped(ClassPtr klass) const
375 {
376 return EtsClass::FromRuntimeClass(ClassCast(klass))->IsValueTyped();
377 }
378
GetDoubleToStringCache() const379 void *EtsRuntimeInterface::GetDoubleToStringCache() const
380 {
381 return ark::ets::PandaEtsVM::GetCurrent()->GetDoubleToStringCache();
382 }
383
384 } // namespace ark::ets
385