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