1 /*
2 * Copyright (c) 2021 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 "ark_native_function.h"
17
18 #ifdef ENABLE_CONTAINER_SCOPE
19 #include "core/common/container_scope.h"
20 #endif
21
22 #include "utils/log.h"
23
24 using panda::ArrayRef;
25 using panda::NativePointerRef;
26 using panda::FunctionRef;
27 using panda::StringRef;
ArkNativeFunction(ArkNativeEngine * engine,Local<JSValueRef> value)28 ArkNativeFunction::ArkNativeFunction(ArkNativeEngine* engine, Local<JSValueRef> value) : ArkNativeObject(engine, value)
29 {
30 #ifdef ENABLE_CONTAINER_SCOPE
31 scopeId_ = OHOS::Ace::ContainerScope::CurrentId();
32 #endif
33 }
34
35 // common function
ArkNativeFunction(ArkNativeEngine * engine,const char * name,size_t length,NativeCallback cb,void * value)36 ArkNativeFunction::ArkNativeFunction(ArkNativeEngine* engine,
37 const char* name,
38 size_t length,
39 NativeCallback cb,
40 void* value)
41 : ArkNativeFunction(engine, JSValueRef::Undefined(engine->GetEcmaVm()))
42 {
43 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
44 LocalScope scope(vm);
45
46 NativeFunctionInfo* funcInfo = NativeFunctionInfo::CreateNewInstance();
47 if (funcInfo == nullptr) {
48 HILOG_ERROR("funcInfo is nullptr");
49 return;
50 }
51 funcInfo->engine = engine;
52 funcInfo->callback = cb;
53 funcInfo->data = value;
54
55 Local<FunctionRef> fn = FunctionRef::New(vm, NativeFunctionCallBack,
56 [](void* externalPointer, void* data) {
57 auto info = reinterpret_cast<NativeFunctionInfo*>(data);
58 if (info != nullptr) {
59 delete info;
60 }
61 },
62 reinterpret_cast<void*>(funcInfo));
63 Local<StringRef> fnName = StringRef::NewFromUtf8(vm, name);
64 fn->SetName(vm, fnName);
65
66 Global<JSValueRef> globalFn(vm, fn);
67 value_ = globalFn;
68 }
69
70
71 // class function
ArkNativeFunction(ArkNativeEngine * engine,const char * name,NativeCallback cb,void * value)72 ArkNativeFunction::ArkNativeFunction(ArkNativeEngine* engine,
73 const char* name,
74 NativeCallback cb,
75 void* value)
76 : ArkNativeFunction(engine, JSValueRef::Undefined(engine->GetEcmaVm()))
77 {
78 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
79 LocalScope scope(vm);
80
81 NativeFunctionInfo* funcInfo = NativeFunctionInfo::CreateNewInstance();
82 if (funcInfo == nullptr) {
83 HILOG_ERROR("funcInfo is nullptr");
84 return;
85 }
86 funcInfo->engine = engine;
87 funcInfo->callback = cb;
88 funcInfo->data = value;
89
90 Local<FunctionRef> fn = FunctionRef::NewClassFunction(vm, NativeClassFunctionCallBack,
91 [](void* externalPointer, void* data) {
92 auto info = reinterpret_cast<NativeFunctionInfo*>(data);
93 if (info != nullptr) {
94 delete info;
95 }
96 },
97 reinterpret_cast<void*>(funcInfo));
98 Local<StringRef> fnName = StringRef::NewFromUtf8(vm, name);
99 fn->SetName(vm, fnName);
100
101 Global<JSValueRef> globalFn(vm, fn);
102 value_ = globalFn;
103 }
104
~ArkNativeFunction()105 ArkNativeFunction::~ArkNativeFunction()
106 {
107 }
108
GetInterface(int interfaceId)109 void* ArkNativeFunction::GetInterface(int interfaceId)
110 {
111 return (NativeFunction::INTERFACE_ID == interfaceId) ? (NativeFunction*)this
112 : ArkNativeObject::GetInterface(interfaceId);
113 }
114
NativeFunctionCallBack(EcmaVM * vm,Local<JSValueRef> thisObj,const Local<JSValueRef> argv[],int32_t length,void * data)115 Local<JSValueRef> ArkNativeFunction::NativeFunctionCallBack(EcmaVM* vm,
116 Local<JSValueRef> thisObj,
117 const Local<JSValueRef> argv[],
118 int32_t length,
119 void* data)
120 {
121 panda::EscapeLocalScope scope(vm);
122 auto info = reinterpret_cast<NativeFunctionInfo*>(data);
123 auto engine = reinterpret_cast<ArkNativeEngine*>(info->engine);
124 auto cb = info->callback;
125 if (engine == nullptr) {
126 HILOG_ERROR("native engine is null");
127 return JSValueRef::Undefined(vm);
128 }
129
130 NativeCallbackInfo cbInfo = { 0 };
131 NativeScopeManager* scopeManager = engine->GetScopeManager();
132 if (scopeManager == nullptr) {
133 HILOG_ERROR("scope manager is null");
134 return JSValueRef::Undefined(vm);
135 }
136 NativeScope* nativeScope = scopeManager->Open();
137 cbInfo.thisVar = ArkNativeEngine::ArkValueToNativeValue(engine, thisObj);
138 cbInfo.function = nullptr;
139 cbInfo.argc = static_cast<size_t>(length);
140 cbInfo.argv = nullptr;
141 cbInfo.functionInfo = info;
142 if (cbInfo.argc > 0) {
143 cbInfo.argv = new NativeValue* [cbInfo.argc];
144 for (size_t i = 0; i < cbInfo.argc; i++) {
145 cbInfo.argv[i] = ArkNativeEngine::ArkValueToNativeValue(engine, argv[i]);
146 }
147 }
148
149 NativeValue* result = nullptr;
150 if (cb != nullptr) {
151 result = cb(engine, &cbInfo);
152 }
153
154 if (cbInfo.argv != nullptr) {
155 delete[] cbInfo.argv;
156 cbInfo.argv = nullptr;
157 }
158
159 Local<JSValueRef> localRet = JSValueRef::Undefined(vm);
160 if (result == nullptr) {
161 if (engine->IsExceptionPending()) {
162 [[maybe_unused]] NativeValue* error = engine->GetAndClearLastException();
163 }
164 } else {
165 Global<JSValueRef> ret = *result;
166 localRet = ret.ToLocal(vm);
167 }
168 scopeManager->Close(nativeScope);
169 if (localRet.IsEmpty()) {
170 return scope.Escape(JSValueRef::Undefined(vm));
171 }
172 return scope.Escape(localRet);
173 }
174
NativeClassFunctionCallBack(EcmaVM * vm,Local<JSValueRef> function,Local<JSValueRef> newTarget,const Local<JSValueRef> argv[],int32_t length,void * data)175 Local<JSValueRef> ArkNativeFunction::NativeClassFunctionCallBack(EcmaVM* vm,
176 Local<JSValueRef> function,
177 Local<JSValueRef> newTarget,
178 const Local<JSValueRef> argv[],
179 int32_t length,
180 void* data)
181 {
182 panda::EscapeLocalScope scope(vm);
183 auto info = reinterpret_cast<NativeFunctionInfo*>(data);
184 auto engine = reinterpret_cast<ArkNativeEngine*>(info->engine);
185 auto cb = info->callback;
186 if (engine == nullptr) {
187 HILOG_ERROR("native engine is null");
188 return JSValueRef::Undefined(vm);
189 }
190
191 NativeCallbackInfo cbInfo = { 0 };
192 NativeScopeManager* scopeManager = engine->GetScopeManager();
193 if (scopeManager == nullptr) {
194 HILOG_ERROR("scope manager is null");
195 return JSValueRef::Undefined(vm);
196 }
197 NativeScope* nativeScope = scopeManager->Open();
198 cbInfo.thisVar = ArkNativeEngine::ArkValueToNativeValue(engine, function);
199 cbInfo.function = ArkNativeEngine::ArkValueToNativeValue(engine, newTarget);
200 cbInfo.argc = static_cast<size_t>(length);
201 cbInfo.argv = nullptr;
202 cbInfo.functionInfo = info;
203 if (cbInfo.argc > 0) {
204 cbInfo.argv = new NativeValue* [cbInfo.argc];
205 for (size_t i = 0; i < cbInfo.argc; i++) {
206 cbInfo.argv[i] = ArkNativeEngine::ArkValueToNativeValue(engine, argv[i]);
207 }
208 }
209
210 NativeValue* result = nullptr;
211 if (cb != nullptr) {
212 result = cb(engine, &cbInfo);
213 }
214
215 if (cbInfo.argv != nullptr) {
216 delete[] cbInfo.argv;
217 cbInfo.argv = nullptr;
218 }
219
220 Global<JSValueRef> ret(vm, JSValueRef::Undefined(vm));
221 if (result == nullptr) {
222 if (engine->IsExceptionPending()) {
223 [[maybe_unused]] NativeValue* error = engine->GetAndClearLastException();
224 }
225 } else {
226 ret = *result;
227 }
228 auto localRet = ret.ToLocal(vm);
229 scopeManager->Close(nativeScope);
230 if (localRet.IsEmpty()) {
231 return scope.Escape(JSValueRef::Undefined(vm));
232 }
233 return scope.Escape(localRet);
234 }
235
GetFunctionPrototype()236 NativeValue* ArkNativeFunction::GetFunctionPrototype()
237 {
238 auto vm = engine_->GetEcmaVm();
239 LocalScope scope(vm);
240 Global<FunctionRef> func = value_;
241 Local<JSValueRef> prototype = func->GetFunctionPrototype(vm);
242 return ArkNativeEngine::ArkValueToNativeValue(engine_, prototype);
243 }
244