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 ScopedMutatorLock lock;
27 auto *caller = MethodCast(method);
28 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*caller);
29 return static_cast<EtsClassLinkerExtension *>(Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx))
30 ->GetPromiseClass();
31 }
32 return PandaRuntimeInterface::GetClass(method, id);
33 }
34
ResolveLookUpField(FieldPtr rawField,ClassPtr klass)35 compiler::RuntimeInterface::FieldPtr EtsRuntimeInterface::ResolveLookUpField(FieldPtr rawField, ClassPtr klass)
36 {
37 ScopedMutatorLock lock;
38 ASSERT(rawField != nullptr);
39 ASSERT(klass != nullptr);
40 return ClassCast(klass)->LookupFieldByName(FieldCast(rawField)->GetName());
41 }
42
43 template <panda_file::Type::TypeId FIELD_TYPE>
GetLookUpCall(FieldPtr rawField,ClassPtr klass,bool isSetter)44 compiler::RuntimeInterface::MethodPtr EtsRuntimeInterface::GetLookUpCall(FieldPtr rawField, ClassPtr klass,
45 bool isSetter)
46 {
47 if (isSetter) {
48 return ClassCast(klass)->LookupSetterByName<FIELD_TYPE>(FieldCast(rawField)->GetName());
49 }
50 return ClassCast(klass)->LookupGetterByName<FIELD_TYPE>(FieldCast(rawField)->GetName());
51 }
52
ResolveLookUpCall(FieldPtr rawField,ClassPtr klass,bool isSetter)53 compiler::RuntimeInterface::MethodPtr EtsRuntimeInterface::ResolveLookUpCall(FieldPtr rawField, ClassPtr klass,
54 bool isSetter)
55 {
56 ScopedMutatorLock lock;
57 ASSERT(rawField != nullptr);
58 ASSERT(klass != nullptr);
59 switch (FieldCast(rawField)->GetTypeId()) {
60 case panda_file::Type::TypeId::U1:
61 return GetLookUpCall<panda_file::Type::TypeId::U1>(rawField, klass, isSetter);
62 case panda_file::Type::TypeId::U8:
63 return GetLookUpCall<panda_file::Type::TypeId::U8>(rawField, klass, isSetter);
64 case panda_file::Type::TypeId::I8:
65 return GetLookUpCall<panda_file::Type::TypeId::I8>(rawField, klass, isSetter);
66 case panda_file::Type::TypeId::I16:
67 return GetLookUpCall<panda_file::Type::TypeId::I16>(rawField, klass, isSetter);
68 case panda_file::Type::TypeId::U16:
69 return GetLookUpCall<panda_file::Type::TypeId::U16>(rawField, klass, isSetter);
70 case panda_file::Type::TypeId::I32:
71 return GetLookUpCall<panda_file::Type::TypeId::I32>(rawField, klass, isSetter);
72 case panda_file::Type::TypeId::U32:
73 return GetLookUpCall<panda_file::Type::TypeId::U32>(rawField, klass, isSetter);
74 case panda_file::Type::TypeId::I64:
75 return GetLookUpCall<panda_file::Type::TypeId::I64>(rawField, klass, isSetter);
76 case panda_file::Type::TypeId::U64:
77 return GetLookUpCall<panda_file::Type::TypeId::U64>(rawField, klass, isSetter);
78 case panda_file::Type::TypeId::F32:
79 return GetLookUpCall<panda_file::Type::TypeId::F32>(rawField, klass, isSetter);
80 case panda_file::Type::TypeId::F64:
81 return GetLookUpCall<panda_file::Type::TypeId::F64>(rawField, klass, isSetter);
82 case panda_file::Type::TypeId::REFERENCE:
83 return GetLookUpCall<panda_file::Type::TypeId::REFERENCE>(rawField, klass, isSetter);
84 default: {
85 UNREACHABLE();
86 break;
87 }
88 }
89 return nullptr;
90 }
91
GetUndefinedObject() const92 uint64_t EtsRuntimeInterface::GetUndefinedObject() const
93 {
94 return ToUintPtr(PandaEtsVM::GetCurrent()->GetUndefinedObject());
95 }
96
GetInteropCallKind(MethodPtr methodPtr) const97 compiler::RuntimeInterface::InteropCallKind EtsRuntimeInterface::GetInteropCallKind(MethodPtr methodPtr) const
98 {
99 auto className = GetClassNameFromMethod(methodPtr);
100 auto classNameSuffix = className.substr(className.find_last_of('.') + 1);
101 if (classNameSuffix == "$jsnew") {
102 return InteropCallKind::NEW_INSTANCE;
103 }
104 if (classNameSuffix != "$jscall") {
105 return InteropCallKind::UNKNOWN;
106 }
107
108 auto method = MethodCast(methodPtr);
109
110 ScopedMutatorLock lock;
111
112 ASSERT(method->GetArgType(0).IsReference()); // arg0 is always a reference
113 if (method->GetArgType(1).IsReference()) {
114 auto pf = method->GetPandaFile();
115 panda_file::ProtoDataAccessor pda(*pf, panda_file::MethodDataAccessor::GetProtoId(*pf, method->GetFileId()));
116 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
117 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*method);
118 auto linkerCtx = static_cast<EtsClassLinkerExtension *>(classLinker->GetExtension(ctx))->GetBootContext();
119 uint32_t const argReftypeShift = method->GetReturnType().IsReference() ? 1 : 0;
120 auto cls = classLinker->GetClass(*pf, pda.GetReferenceType(1 + argReftypeShift), linkerCtx);
121 if (!cls->IsStringClass()) {
122 return InteropCallKind::CALL_BY_VALUE;
123 }
124 } else {
125 // arg1 and arg2 are start position and length of qualified name
126 ASSERT(method->GetArgType(1).GetId() == panda_file::Type::TypeId::I32);
127 ASSERT(method->GetArgType(2U).GetId() == panda_file::Type::TypeId::I32);
128 }
129 return InteropCallKind::CALL;
130 }
131
GetFuncPropName(MethodPtr methodPtr,uint32_t strId) const132 char *EtsRuntimeInterface::GetFuncPropName(MethodPtr methodPtr, uint32_t strId) const
133 {
134 auto method = MethodCast(methodPtr);
135 auto pf = method->GetPandaFile();
136 auto str = reinterpret_cast<const char *>(pf->GetStringData(ark::panda_file::File::EntityId(strId)).data);
137 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
138 return const_cast<char *>(std::strrchr(str, '.') + 1);
139 }
140
GetFuncPropNameOffset(MethodPtr methodPtr,uint32_t strId) const141 uint64_t EtsRuntimeInterface::GetFuncPropNameOffset(MethodPtr methodPtr, uint32_t strId) const
142 {
143 auto pf = MethodCast(methodPtr)->GetPandaFile();
144 auto str = GetFuncPropName(methodPtr, strId);
145 return reinterpret_cast<uint64_t>(str) - reinterpret_cast<uint64_t>(pf->GetBase());
146 }
147
IsMethodStringConcat(MethodPtr method) const148 bool EtsRuntimeInterface::IsMethodStringConcat(MethodPtr method) const
149 {
150 return GetClassNameFromMethod(method) == "std.core.String" &&
151 MethodCast(method)->GetProto().GetSignature() == "([Lstd/core/String;)Lstd/core/String;";
152 }
153
IsMethodStringBuilderConstructorWithStringArg(MethodPtr method) const154 bool EtsRuntimeInterface::IsMethodStringBuilderConstructorWithStringArg(MethodPtr method) const
155 {
156 return MethodCast(method)->IsConstructor() && GetClassNameFromMethod(method) == "std.core.StringBuilder" &&
157 MethodCast(method)->GetProto().GetSignature() == "(Lstd/core/String;)V";
158 }
159
IsMethodStringBuilderConstructorWithCharArrayArg(MethodPtr method) const160 bool EtsRuntimeInterface::IsMethodStringBuilderConstructorWithCharArrayArg(MethodPtr method) const
161 {
162 return MethodCast(method)->IsConstructor() && GetClassNameFromMethod(method) == "std.core.StringBuilder" &&
163 MethodCast(method)->GetProto().GetSignature() == "([C)V";
164 }
165
IsMethodStringBuilderDefaultConstructor(MethodPtr method) const166 bool EtsRuntimeInterface::IsMethodStringBuilderDefaultConstructor(MethodPtr method) const
167 {
168 return MethodCast(method)->IsConstructor() && GetClassNameFromMethod(method) == "std.core.StringBuilder" &&
169 MethodCast(method)->GetProto().GetSignature() == "()V";
170 }
171
IsMethodStringBuilderToString(MethodPtr method) const172 bool EtsRuntimeInterface::IsMethodStringBuilderToString(MethodPtr method) const
173 {
174 return GetMethodFullName(method, false) == "std.core.StringBuilder::toString" &&
175 MethodCast(method)->GetProto().GetSignature() == "()Lstd/core/String;";
176 }
177
IsMethodStringBuilderAppend(MethodPtr method) const178 bool EtsRuntimeInterface::IsMethodStringBuilderAppend(MethodPtr method) const
179 {
180 return GetMethodFullName(method, false) == "std.core.StringBuilder::append";
181 }
182
IsClassStringBuilder(ClassPtr klass) const183 bool EtsRuntimeInterface::IsClassStringBuilder(ClassPtr klass) const
184 {
185 return ClassCast(klass)->GetName() == "std.core.StringBuilder";
186 }
187
GetClassOffsetObjectsArray(MethodPtr method) const188 uint32_t EtsRuntimeInterface::GetClassOffsetObjectsArray(MethodPtr method) const
189 {
190 auto pf = MethodCast(method)->GetPandaFile();
191 return pf->GetClassId(utf::CStringAsMutf8("[Lstd/core/Object;")).GetOffset();
192 }
193
GetClassOffsetObject(MethodPtr method) const194 uint32_t EtsRuntimeInterface::GetClassOffsetObject(MethodPtr method) const
195 {
196 auto pf = MethodCast(method)->GetPandaFile();
197 return pf->GetClassId(utf::CStringAsMutf8("std.core.Object")).GetOffset();
198 }
199
GetStringBuilderClass() const200 EtsRuntimeInterface::ClassPtr EtsRuntimeInterface::GetStringBuilderClass() const
201 {
202 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(SourceLanguage::ETS);
203 return static_cast<EtsClassLinkerExtension *>(Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx))
204 ->GetStringBuilderClass();
205 }
206
GetStringBuilderDefaultConstructor() const207 EtsRuntimeInterface::MethodPtr EtsRuntimeInterface::GetStringBuilderDefaultConstructor() const
208 {
209 auto classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
210 for (auto ctor : classLinker->GetStringBuilderClass()->GetConstructors()) {
211 if (IsMethodStringBuilderDefaultConstructor(ctor)) {
212 return ctor;
213 }
214 }
215
216 UNREACHABLE();
217 }
218
GetMethodId(MethodPtr method) const219 uint32_t EtsRuntimeInterface::GetMethodId(MethodPtr method) const
220 {
221 ASSERT(method != nullptr);
222 return static_cast<EtsMethod *>(method)->GetMethodId();
223 }
224
GetFieldStringBuilderBuffer(ClassPtr klass) const225 EtsRuntimeInterface::FieldPtr EtsRuntimeInterface::GetFieldStringBuilderBuffer(ClassPtr klass) const
226 {
227 ASSERT(IsClassStringBuilder(klass));
228 return ClassCast(klass)->GetInstanceFieldByName(utf::CStringAsMutf8("buf"));
229 }
230
GetFieldStringBuilderIndex(ClassPtr klass) const231 EtsRuntimeInterface::FieldPtr EtsRuntimeInterface::GetFieldStringBuilderIndex(ClassPtr klass) const
232 {
233 ASSERT(IsClassStringBuilder(klass));
234 return ClassCast(klass)->GetInstanceFieldByName(utf::CStringAsMutf8("index"));
235 }
236
GetFieldStringBuilderLength(ClassPtr klass) const237 EtsRuntimeInterface::FieldPtr EtsRuntimeInterface::GetFieldStringBuilderLength(ClassPtr klass) const
238 {
239 ASSERT(IsClassStringBuilder(klass));
240 return ClassCast(klass)->GetInstanceFieldByName(utf::CStringAsMutf8("length"));
241 }
242
GetFieldStringBuilderCompress(ClassPtr klass) const243 EtsRuntimeInterface::FieldPtr EtsRuntimeInterface::GetFieldStringBuilderCompress(ClassPtr klass) const
244 {
245 ASSERT(IsClassStringBuilder(klass));
246 return ClassCast(klass)->GetInstanceFieldByName(utf::CStringAsMutf8("compress"));
247 }
248
IsFieldStringBuilderBuffer(FieldPtr field) const249 bool EtsRuntimeInterface::IsFieldStringBuilderBuffer(FieldPtr field) const
250 {
251 return IsClassStringBuilder(FieldCast(field)->GetClass()) && GetFieldName(field) == "buf";
252 }
253
IsFieldStringBuilderIndex(FieldPtr field) const254 bool EtsRuntimeInterface::IsFieldStringBuilderIndex(FieldPtr field) const
255 {
256 return IsClassStringBuilder(FieldCast(field)->GetClass()) && GetFieldName(field) == "index";
257 }
258
IsIntrinsicStringBuilderToString(IntrinsicId id) const259 bool EtsRuntimeInterface::IsIntrinsicStringBuilderToString(IntrinsicId id) const
260 {
261 return id == RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_SB_TO_STRING;
262 }
263
IsIntrinsicStringBuilderAppendString(IntrinsicId id) const264 bool EtsRuntimeInterface::IsIntrinsicStringBuilderAppendString(IntrinsicId id) const
265 {
266 return id == IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING;
267 }
268
IsIntrinsicStringBuilderAppend(IntrinsicId id) const269 bool EtsRuntimeInterface::IsIntrinsicStringBuilderAppend(IntrinsicId id) const
270 {
271 switch (id) {
272 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_FLOAT:
273 return true;
274 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_DOUBLE:
275 return true;
276 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_LONG:
277 return true;
278 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_INT:
279 return true;
280 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_BYTE:
281 return true;
282 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_SHORT:
283 return true;
284 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_CHAR:
285 return true;
286 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_BOOL:
287 return true;
288 case IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING:
289 return true;
290 default:
291 return false;
292 }
293 }
294
ConvertTypeToStringBuilderAppendIntrinsicId(compiler::DataType::Type type) const295 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::ConvertTypeToStringBuilderAppendIntrinsicId(
296 compiler::DataType::Type type) const
297 {
298 switch (type) {
299 case compiler::DataType::BOOL:
300 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_BOOL;
301 case compiler::DataType::INT8:
302 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_CHAR;
303 case compiler::DataType::UINT8:
304 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_BYTE;
305 case compiler::DataType::INT16:
306 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_SHORT;
307 case compiler::DataType::INT32:
308 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_INT;
309 case compiler::DataType::INT64:
310 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_LONG;
311 case compiler::DataType::FLOAT64:
312 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_DOUBLE;
313 case compiler::DataType::FLOAT32:
314 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_FLOAT;
315 case compiler::DataType::REFERENCE:
316 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING;
317 default:
318 UNREACHABLE();
319 }
320 return IntrinsicId::INVALID;
321 }
322
GetStringConcatStringsIntrinsicId(size_t numArgs) const323 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::GetStringConcatStringsIntrinsicId(size_t numArgs) const
324 {
325 // NOLINTBEGIN(readability-magic-numbers)
326 switch (numArgs) {
327 case 2U:
328 return IntrinsicId::INTRINSIC_STD_CORE_STRING_CONCAT2;
329 case 3U:
330 return IntrinsicId::INTRINSIC_STD_CORE_STRING_CONCAT3;
331 case 4U:
332 return IntrinsicId::INTRINSIC_STD_CORE_STRING_CONCAT4;
333 default:
334 UNREACHABLE();
335 }
336 // NOLINTEND(readability-magic-numbers)
337 }
338
GetStringIsCompressedIntrinsicId() const339 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::GetStringIsCompressedIntrinsicId() const
340 {
341 return IntrinsicId::INTRINSIC_STD_CORE_STRING_IS_COMPRESSED;
342 }
343
GetStringBuilderAppendStringIntrinsicId() const344 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::GetStringBuilderAppendStringIntrinsicId() const
345 {
346 return IntrinsicId::INTRINSIC_STD_CORE_SB_APPEND_STRING;
347 }
348
GetStringBuilderToStringIntrinsicId() const349 EtsRuntimeInterface::IntrinsicId EtsRuntimeInterface::GetStringBuilderToStringIntrinsicId() const
350 {
351 return IntrinsicId::INTRINSIC_STD_CORE_SB_TO_STRING;
352 }
353
IsClassValueTyped(ClassPtr klass) const354 bool EtsRuntimeInterface::IsClassValueTyped(ClassPtr klass) const
355 {
356 return EtsClass::FromRuntimeClass(ClassCast(klass))->IsValueTyped();
357 }
358
GetDoubleToStringCache() const359 void *EtsRuntimeInterface::GetDoubleToStringCache() const
360 {
361 return ark::ets::PandaEtsVM::GetCurrent()->GetDoubleToStringCache();
362 }
363
364 } // namespace ark::ets
365