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;
28 using panda::JsiRuntimeCallInfo;
29 static constexpr uint32_t MAX_CHUNK_ARRAY_SIZE = 10;
30
ArkNativeFunction(ArkNativeEngine * engine,Local<JSValueRef> value)31 ArkNativeFunction::ArkNativeFunction(ArkNativeEngine* engine, Local<JSValueRef> value) : ArkNativeObject(engine, value)
32 {
33 #ifdef ENABLE_CONTAINER_SCOPE
34 scopeId_ = OHOS::Ace::ContainerScope::CurrentId();
35 #endif
36 }
37
38 // common function
ArkNativeFunction(ArkNativeEngine * engine,const char * name,size_t length,NativeCallback cb,void * value)39 ArkNativeFunction::ArkNativeFunction(ArkNativeEngine* engine,
40 const char* name,
41 size_t length,
42 NativeCallback cb,
43 void* value)
44 : ArkNativeFunction(engine, JSValueRef::Undefined(engine->GetEcmaVm()))
45 {
46 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
47 LocalScope scope(vm);
48
49 NativeFunctionInfo* funcInfo = NativeFunctionInfo::CreateNewInstance();
50 if (funcInfo == nullptr) {
51 HILOG_ERROR("funcInfo is nullptr");
52 return;
53 }
54 funcInfo->engine = engine;
55 funcInfo->callback = cb;
56 funcInfo->data = value;
57
58 Local<FunctionRef> fn = FunctionRef::New(vm, NativeFunctionCallBack,
59 [](void* externalPointer, void* data) {
60 auto info = reinterpret_cast<NativeFunctionInfo*>(data);
61 if (info != nullptr) {
62 delete info;
63 }
64 },
65 reinterpret_cast<void*>(funcInfo), true);
66 Local<StringRef> fnName = StringRef::NewFromUtf8(vm, name);
67 fn->SetName(vm, fnName);
68
69 Global<JSValueRef> globalFn(vm, fn);
70 value_ = globalFn;
71 }
72
73
74 // class function
ArkNativeFunction(ArkNativeEngine * engine,const char * name,NativeCallback cb,void * value)75 ArkNativeFunction::ArkNativeFunction(ArkNativeEngine* engine,
76 const char* name,
77 NativeCallback cb,
78 void* value)
79 : ArkNativeFunction(engine, JSValueRef::Undefined(engine->GetEcmaVm()))
80 {
81 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
82 LocalScope scope(vm);
83
84 NativeFunctionInfo* funcInfo = NativeFunctionInfo::CreateNewInstance();
85 if (funcInfo == nullptr) {
86 HILOG_ERROR("funcInfo is nullptr");
87 return;
88 }
89 funcInfo->engine = engine;
90 funcInfo->callback = cb;
91 funcInfo->data = value;
92
93 Local<FunctionRef> fn = FunctionRef::NewClassFunction(vm, NativeFunctionCallBack,
94 [](void* externalPointer, void* data) {
95 auto info = reinterpret_cast<NativeFunctionInfo*>(data);
96 if (info != nullptr) {
97 delete info;
98 }
99 },
100 reinterpret_cast<void*>(funcInfo), true);
101 Local<StringRef> fnName = StringRef::NewFromUtf8(vm, name);
102 fn->SetName(vm, fnName);
103
104 Global<JSValueRef> globalFn(vm, fn);
105 value_ = globalFn;
106 }
107
~ArkNativeFunction()108 ArkNativeFunction::~ArkNativeFunction()
109 {
110 }
111
GetInterface(int interfaceId)112 void* ArkNativeFunction::GetInterface(int interfaceId)
113 {
114 return (NativeFunction::INTERFACE_ID == interfaceId) ? (NativeFunction*)this
115 : ArkNativeObject::GetInterface(interfaceId);
116 }
117
NativeFunctionCallBack(JsiRuntimeCallInfo * runtimeInfo)118 Local<JSValueRef> ArkNativeFunction::NativeFunctionCallBack(JsiRuntimeCallInfo *runtimeInfo)
119 {
120 EcmaVM *vm = runtimeInfo->GetVM();
121 panda::EscapeLocalScope scope(vm);
122 auto info = reinterpret_cast<NativeFunctionInfo*>(runtimeInfo->GetData());
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
137 StartNapiProfilerTrace(runtimeInfo);
138 NativeScope* nativeScope = scopeManager->Open();
139 cbInfo.thisVar = ArkNativeEngine::ArkValueToNativeValue(engine, runtimeInfo->GetThisRef());
140 cbInfo.function = ArkNativeEngine::ArkValueToNativeValue(engine, runtimeInfo->GetNewTargetRef());
141 cbInfo.argc = static_cast<size_t>(runtimeInfo->GetArgsNumber());
142 cbInfo.argv = nullptr;
143 cbInfo.functionInfo = info;
144 if (cbInfo.argc > 0) {
145 if (cbInfo.argc > MAX_CHUNK_ARRAY_SIZE) {
146 cbInfo.argv = new NativeValue* [cbInfo.argc];
147 } else {
148 cbInfo.argv = scopeManager->GetNativeChunk().NewArray<NativeValue *>(cbInfo.argc);
149 }
150 for (size_t i = 0; i < cbInfo.argc; i++) {
151 cbInfo.argv[i] = ArkNativeEngine::ArkValueToNativeValue(engine, runtimeInfo->GetCallArgRef(i));
152 }
153 }
154
155 if (engine->IsMixedDebugEnabled()) {
156 engine->NotifyNativeCalling(reinterpret_cast<void *>(cb));
157 }
158
159 NativeValue* result = nullptr;
160 if (cb != nullptr) {
161 result = cb(engine, &cbInfo);
162 }
163
164 if (cbInfo.argv != nullptr) {
165 if (cbInfo.argc > MAX_CHUNK_ARRAY_SIZE) {
166 delete[] cbInfo.argv;
167 } else {
168 scopeManager->GetNativeChunk().Delete(cbInfo.argv);
169 }
170 cbInfo.argv = nullptr;
171 }
172
173 Local<JSValueRef> localRet = JSValueRef::Undefined(vm);
174 if (result == nullptr) {
175 if (engine->IsExceptionPending()) {
176 [[maybe_unused]] NativeValue* error = engine->GetAndClearLastException();
177 }
178 } else {
179 Global<JSValueRef> ret = *result;
180 localRet = ret.ToLocal(vm);
181 }
182 scopeManager->Close(nativeScope);
183 FinishNapiProfilerTrace();
184 if (localRet.IsEmpty()) {
185 return scope.Escape(JSValueRef::Undefined(vm));
186 }
187 return scope.Escape(localRet);
188 }
189
GetNativePtrCallBack(void * data)190 void* ArkNativeFunction::GetNativePtrCallBack(void* data)
191 {
192 auto info = reinterpret_cast<NativeFunctionInfo*>(data);
193 auto cb = reinterpret_cast<void*>(info->callback);
194 return cb;
195 }
196
GetFunctionPrototype()197 NativeValue* ArkNativeFunction::GetFunctionPrototype()
198 {
199 auto vm = engine_->GetEcmaVm();
200 LocalScope scope(vm);
201 Global<FunctionRef> func = value_;
202 Local<JSValueRef> prototype = func->GetFunctionPrototype(vm);
203 return ArkNativeEngine::ArkValueToNativeValue(engine_, prototype);
204 }
205
GetSourceCodeInfo(ErrorPos pos)206 std::string ArkNativeFunction::GetSourceCodeInfo(ErrorPos pos)
207 {
208 if (pos.first == 0) {
209 return "";
210 }
211 auto vm = engine_->GetEcmaVm();
212 LocalScope scope(vm);
213 Global<FunctionRef> func = value_;
214 uint32_t line = pos.first;
215 uint32_t column = pos.second;
216 Local<panda::StringRef> sourceCode = func->GetSourceCode(vm, line);
217 std::string sourceCodeStr = sourceCode->ToString();
218 if (sourceCodeStr.empty()) {
219 return "";
220 }
221 std::string sourceCodeInfo = "SourceCode:\n";
222 sourceCodeInfo.append(sourceCodeStr).append("\n");
223 for (uint32_t k = 0; k < column - 1; k++) {
224 sourceCodeInfo.push_back(' ');
225 }
226 sourceCodeInfo.append("^\n");
227 return sourceCodeInfo;
228 }
229