1 /**
2 * Copyright (c) 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 "stdlib_ani_helpers.h"
17 #include "libpandabase/utils/logger.h"
18
19 namespace ark::ets::stdlib {
20
StdlibLogFatal(const char * msg)21 void StdlibLogFatal(const char *msg)
22 {
23 LOG(FATAL, STDLIB) << msg;
24 UNREACHABLE();
25 }
26
StdlibLogFatal(const char * msg,ani_status status)27 void StdlibLogFatal(const char *msg, ani_status status)
28 {
29 LOG(FATAL, STDLIB) << (std::string(msg) + " status = " + StatusToString(status) + "(" + std::to_string(status) +
30 ")");
31 UNREACHABLE();
32 }
33
ThrowNewError(ani_env * env,ani_class errorClass,std::string_view msg,const char * ctorSignature)34 ANI_EXPORT void ThrowNewError(ani_env *env, ani_class errorClass, std::string_view msg, const char *ctorSignature)
35 {
36 ASSERT(env != nullptr);
37
38 ani_method ctor;
39 ANI_FATAL_IF_ERROR(env->Class_FindMethod(errorClass, "<ctor>", ctorSignature, &ctor));
40
41 ani_string message = CreateUtf8String(env, msg.data(), msg.size());
42 if (message == nullptr) {
43 // Exception occured in CreateUtf8String.
44 return;
45 }
46
47 ani_object errorObject;
48 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
49 ANI_FATAL_IF_ERROR(env->Object_New(errorClass, ctor, &errorObject, message));
50
51 ANI_FATAL_IF_ERROR(env->ThrowError(reinterpret_cast<ani_error>(errorObject)));
52 }
53
ThrowNewError(ani_env * env,std::string_view classDescriptor,std::string_view msg,const char * ctorSignature)54 ANI_EXPORT void ThrowNewError(ani_env *env, std::string_view classDescriptor, std::string_view msg,
55 const char *ctorSignature)
56 {
57 ASSERT(env != nullptr);
58
59 ani_class errCls;
60 ANI_FATAL_IF_ERROR(env->FindClass(classDescriptor.data(), &errCls));
61 ThrowNewError(env, errCls, msg, ctorSignature);
62 }
63
ConvertFromAniString(ani_env * env,ani_string aniStr)64 ANI_EXPORT std::string ConvertFromAniString(ani_env *env, ani_string aniStr)
65 {
66 ani_size strSz;
67 ANI_FATAL_IF_ERROR(env->String_GetUTF8Size(aniStr, &strSz));
68
69 std::string buffer;
70 buffer.resize(strSz + 1U);
71
72 ani_size nmbCopiedBytes;
73 ANI_FATAL_IF_ERROR(env->String_GetUTF8SubString(aniStr, 0U, strSz, buffer.data(), buffer.size(), &nmbCopiedBytes));
74 ANI_FATAL_IF(nmbCopiedBytes != strSz);
75
76 buffer.resize(strSz);
77 return buffer;
78 }
79
StatusToString(ani_status status)80 ANI_EXPORT std::string StatusToString(ani_status status)
81 {
82 constexpr size_t STATUS_NUM = static_cast<size_t>(ANI_INVALID_VERSION) + 1U;
83
84 static std::array<std::string, STATUS_NUM> statusToStringTable {
85 "ANI_OK",
86 "ANI_ERROR",
87 "ANI_INVALID_ARGS",
88 "ANI_INVALID_TYPE",
89 "ANI_INVALID_DESCRIPTOR",
90 "ANI_INCORRECT_REF",
91 "ANI_PENDING_ERROR",
92 "ANI_NOT_FOUND",
93 "ANI_ALREADY_BINDED",
94 "ANI_OUT_OF_REF",
95 "ANI_OUT_OF_MEMORY",
96 "ANI_OUT_OF_RANGE",
97 "ANI_BUFFER_TO_SMALL",
98 "ANI_INVALID_VERSION",
99 };
100
101 auto idx = static_cast<size_t>(status);
102 if (idx >= STATUS_NUM) {
103 StdlibLogFatal("Invalid status");
104 UNREACHABLE();
105 }
106 return statusToStringTable[idx];
107 }
108
CreateUtf8String(ani_env * env,const char * data,ani_size size)109 ANI_EXPORT ani_string CreateUtf8String(ani_env *env, const char *data, ani_size size)
110 {
111 ani_string result;
112
113 auto status = env->String_NewUTF8(data, size, &result);
114 if (status != ANI_OK) {
115 ani_boolean unhandledExc;
116 ANI_FATAL_IF_ERROR(env->ExistUnhandledError(&unhandledExc));
117 if (unhandledExc == ANI_TRUE) {
118 return nullptr;
119 }
120 UNREACHABLE();
121 }
122 return result;
123 }
124
CreateUtf16String(ani_env * env,const uint16_t * data,ani_size size)125 ANI_EXPORT ani_string CreateUtf16String(ani_env *env, const uint16_t *data, ani_size size)
126 {
127 ani_string result;
128
129 auto status = env->String_NewUTF16(data, size, &result);
130 if (status != ANI_OK) {
131 ani_boolean unhandledExc;
132 ANI_FATAL_IF_ERROR(env->ExistUnhandledError(&unhandledExc));
133 if (unhandledExc == ANI_TRUE) {
134 return nullptr;
135 }
136 UNREACHABLE();
137 }
138 return result;
139 }
140
GetFieldStrUndefined(ani_env * env,ani_object obj,const char * name)141 ANI_EXPORT std::string GetFieldStrUndefined(ani_env *env, ani_object obj, const char *name)
142 {
143 ani_ref ref = nullptr;
144 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Ref(obj, name, &ref));
145 ani_boolean isUndefined = ANI_FALSE;
146 ANI_FATAL_IF_ERROR(env->Reference_IsUndefined(ref, &isUndefined));
147 if (isUndefined == ANI_TRUE) {
148 return std::string();
149 }
150 auto aniStr = static_cast<ani_string>(ref);
151 ASSERT(aniStr != nullptr);
152 return ConvertFromAniString(env, aniStr);
153 }
154
GetFieldStr(ani_env * env,ani_object obj,const char * name)155 ANI_EXPORT std::string GetFieldStr(ani_env *env, ani_object obj, const char *name)
156 {
157 ani_ref ref = nullptr;
158 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Ref(obj, name, &ref));
159 auto aniStr = static_cast<ani_string>(ref);
160 ASSERT(aniStr != nullptr);
161 return ConvertFromAniString(env, aniStr);
162 }
163
164 } // namespace ark::ets::stdlib
165