1 /**
2 * Copyright 2023 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "include/js_api/mstensor_napi.h"
18 #include <climits>
19 #include <string.h>
20 #include <map>
21 #include "src/common/log.h"
22
23 namespace mindspore {
24 thread_local napi_ref MSTensorNapi::constructor_ = nullptr;
25 const std::string CLASS_NAME = "MSTensor";
26
27 #define GET_PARAMS(env, info, num) \
28 size_t argc = num; \
29 napi_value argv[num] = {0}; \
30 napi_value thisVar = nullptr; \
31 void *data; \
32 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)
33
34 const std::unordered_map<std::string, napi_typedarray_type> kDTypeMap{
35 {"int32", napi_int32_array},
36 {"float32", napi_float32_array},
37 {"int8", napi_int8_array},
38 {"uint8", napi_uint8_array},
39 };
40
41 namespace {
42 const int ARGS_TWO = 2;
43 }
44
MSTensorNapi()45 MSTensorNapi::MSTensorNapi() { MS_LOG(DEBUG) << "MSLITE MSTensorNapi Instances create."; }
46
~MSTensorNapi()47 MSTensorNapi::~MSTensorNapi() {
48 if (nativeMSTensor_ != nullptr) {
49 nativeMSTensor_ = nullptr;
50 }
51 MS_LOG(INFO) << "MSLITE MSTensorNapi Instances destroy.";
52 }
53
Constructor(napi_env env,napi_callback_info info)54 napi_value MSTensorNapi::Constructor(napi_env env, napi_callback_info info) {
55 napi_value jsThis = nullptr;
56 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
57 if (status != napi_ok || jsThis == nullptr) {
58 MS_LOG(ERROR) << "Failed to retrieve details about the callback";
59 return nullptr;
60 }
61
62 std::unique_ptr<MSTensorNapi> tensorNapi = std::make_unique<MSTensorNapi>();
63 if (tensorNapi == nullptr) {
64 MS_LOG(ERROR) << "No memory";
65 return nullptr;
66 }
67
68 tensorNapi->env_ = env;
69 status = napi_wrap(env, jsThis, reinterpret_cast<void *>(tensorNapi.get()), MSTensorNapi::Finalize, nullptr, nullptr);
70 if (status == napi_ok) {
71 tensorNapi.release();
72 return jsThis;
73 }
74
75 MS_LOG(ERROR) << "Constructor fail.";
76 return nullptr;
77 }
78
Finalize(napi_env env,void * nativeObject,void * finalize)79 void MSTensorNapi::Finalize(napi_env env, void *nativeObject, void *finalize) {
80 (void)env;
81 (void)finalize;
82 if (nativeObject != nullptr) {
83 delete reinterpret_cast<MSTensorNapi *>(nativeObject);
84 }
85 MS_LOG(INFO) << "Finalize success.";
86 }
87
NewInstance(napi_env env,mindspore::MSTensor tensor)88 napi_value MSTensorNapi::NewInstance(napi_env env, mindspore::MSTensor tensor) {
89 napi_value cons = GetConstructor(env);
90 if (cons == nullptr) {
91 MS_LOG(ERROR) << "NewInstance GetConstructor is nullptr!";
92 return nullptr;
93 }
94 napi_value instance;
95 napi_status status = napi_new_instance(env, cons, 0, nullptr, &instance);
96 if (status != napi_ok) {
97 MS_LOG(ERROR) << "NewInstance napi_new_instance failed! code: " << status;
98 return nullptr;
99 }
100
101 MSTensorNapi *proxy = nullptr;
102 status = napi_unwrap(env, instance, reinterpret_cast<void **>(&proxy));
103 if (proxy == nullptr) {
104 MS_LOG(ERROR) << "NewInstance native instance is nullptr! code: " << status;
105 return instance;
106 }
107 // MSTensor 不需要new 内存,直接获取Model.getInputs()
108 proxy->nativeMSTensor_ = std::make_unique<mindspore::MSTensor>(tensor);
109 if (proxy->nativeMSTensor_ == nullptr) {
110 MS_LOG(ERROR) << "NewInstance native tensor unique ptr is nullptr!";
111 return instance;
112 }
113 return instance;
114 }
115
GetConstructor(napi_env env)116 napi_value MSTensorNapi::GetConstructor(napi_env env) {
117 napi_value cons;
118 if (constructor_ != nullptr) {
119 napi_get_reference_value(env, constructor_, &cons);
120 return cons;
121 }
122
123 MS_LOG(INFO) << "Get msTensorNapi constructor.";
124 napi_property_descriptor properties[] = {
125 DECLARE_NAPI_GETTER("name", GetName),
126 DECLARE_NAPI_GETTER("shape", GetShape),
127 DECLARE_NAPI_GETTER("elementNum", GetElementNum),
128 DECLARE_NAPI_GETTER("dtype", GetDtype),
129 DECLARE_NAPI_GETTER("format", GetFormat),
130 DECLARE_NAPI_GETTER("dataSize", GetDataSize),
131
132 DECLARE_NAPI_FUNCTION("getData", GetDataBuffer),
133 DECLARE_NAPI_FUNCTION("setData", SetData),
134 };
135
136 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
137 sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons);
138 if (status != napi_ok) {
139 MS_LOG(ERROR) << "MSLITE Failed to define MSTensor class";
140 return nullptr;
141 }
142
143 status = napi_create_reference(env, cons, 1, &constructor_);
144 if (status != napi_ok) {
145 MS_LOG(ERROR) << "MSLITE Failed to create reference of constructor";
146 return nullptr;
147 }
148
149 return cons;
150 }
151
GetName(napi_env env,napi_callback_info info)152 napi_value MSTensorNapi::GetName(napi_env env, napi_callback_info info) {
153 napi_value undefinedResult = nullptr;
154 napi_get_undefined(env, &undefinedResult);
155 napi_value jsThis = nullptr;
156 napi_value jsResult = nullptr;
157 MSTensorNapi *tensor = nullptr;
158
159 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
160 if (status != napi_ok || jsThis == nullptr) {
161 MS_LOG(ERROR) << "Failed to retrieve details about the callback";
162 return undefinedResult;
163 }
164
165 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&tensor));
166 if (status != napi_ok || tensor == nullptr) {
167 MS_LOG(ERROR) << "get tensor napi error";
168 return undefinedResult;
169 }
170
171 status = napi_create_string_utf8(env, tensor->nativeMSTensor_->Name().c_str(), NAPI_AUTO_LENGTH, &jsResult);
172 if (status != napi_ok) {
173 MS_LOG(ERROR) << "napi_create_string_utf8 error";
174 return undefinedResult;
175 }
176
177 MS_LOG(INFO) << "GetName success.";
178 return jsResult;
179 }
180
GetShape(napi_env env,napi_callback_info info)181 napi_value MSTensorNapi::GetShape(napi_env env, napi_callback_info info) {
182 napi_value undefinedResult = nullptr;
183 napi_get_undefined(env, &undefinedResult);
184 napi_value jsThis = nullptr;
185 napi_value jsResult = nullptr;
186 MSTensorNapi *tensor = nullptr;
187
188 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
189 if (status != napi_ok || jsThis == nullptr) {
190 MS_LOG(ERROR) << "Failed to retrieve details about the callback";
191 return undefinedResult;
192 }
193
194 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&tensor));
195 if (status != napi_ok || tensor == nullptr) {
196 MS_LOG(ERROR) << "get tensor napi error";
197 return undefinedResult;
198 }
199
200 // return array
201 auto shape = tensor->nativeMSTensor_->Shape();
202 size_t size = shape.size();
203 napi_create_array_with_length(env, size, &jsResult);
204 for (size_t i = 0; i < size; i++) {
205 napi_value num;
206 status = napi_create_int32(env, shape.at(i), &num);
207 if (status != napi_ok) {
208 MS_LOG(ERROR) << "napi_create_int32 error";
209 return undefinedResult;
210 }
211 napi_set_element(env, jsResult, i, num);
212 }
213
214 MS_LOG(INFO) << "GetShape success.";
215 return jsResult;
216 }
217
GetElementNum(napi_env env,napi_callback_info info)218 napi_value MSTensorNapi::GetElementNum(napi_env env, napi_callback_info info) {
219 napi_value undefinedResult = nullptr;
220 napi_get_undefined(env, &undefinedResult);
221 napi_value jsThis = nullptr;
222 napi_value jsResult = nullptr;
223 MSTensorNapi *tensor = nullptr;
224
225 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
226 if (status != napi_ok || jsThis == nullptr) {
227 MS_LOG(ERROR) << "Failed to retrieve details about the callback";
228 return undefinedResult;
229 }
230
231 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&tensor));
232 if (status != napi_ok || tensor == nullptr) {
233 MS_LOG(ERROR) << "get tensor napi error";
234 return undefinedResult;
235 }
236
237 status = napi_create_int32(env, tensor->nativeMSTensor_->ElementNum(), &jsResult);
238 if (status != napi_ok) {
239 MS_LOG(ERROR) << "napi_create_int32 error";
240 return undefinedResult;
241 }
242
243 MS_LOG(INFO) << "GetElementNum success.";
244 return jsResult;
245 }
246
GetDtype(napi_env env,napi_callback_info info)247 napi_value MSTensorNapi::GetDtype(napi_env env, napi_callback_info info) {
248 napi_value undefinedResult = nullptr;
249 napi_get_undefined(env, &undefinedResult);
250 napi_value jsThis = nullptr;
251 napi_value jsResult = nullptr;
252 MSTensorNapi *tensor = nullptr;
253
254 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
255 if (status != napi_ok || jsThis == nullptr) {
256 MS_LOG(ERROR) << "Failed to retrieve details about the callback";
257 return undefinedResult;
258 }
259
260 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&tensor));
261 if (status != napi_ok || tensor == nullptr) {
262 MS_LOG(ERROR) << "get tensor napi error";
263 return undefinedResult;
264 }
265
266 status = napi_create_int32(env, static_cast<int32_t>(tensor->nativeMSTensor_->DataType()), &jsResult);
267 if (status != napi_ok) {
268 MS_LOG(ERROR) << "napi_create_int32 error";
269 return undefinedResult;
270 }
271
272 MS_LOG(INFO) << "GetDtype success.";
273 return jsResult;
274 }
275
GetFormat(napi_env env,napi_callback_info info)276 napi_value MSTensorNapi::GetFormat(napi_env env, napi_callback_info info) {
277 napi_value undefinedResult = nullptr;
278 napi_get_undefined(env, &undefinedResult);
279 napi_value jsThis = nullptr;
280 napi_value jsResult = nullptr;
281 MSTensorNapi *tensor = nullptr;
282
283 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
284 if (status != napi_ok || jsThis == nullptr) {
285 MS_LOG(ERROR) << "Failed to retrieve details about the callback";
286 return undefinedResult;
287 }
288
289 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&tensor));
290 if (status != napi_ok || tensor == nullptr) {
291 MS_LOG(ERROR) << "get tensor napi error";
292 return undefinedResult;
293 }
294
295 status = napi_create_int32(env, static_cast<int32_t>(tensor->nativeMSTensor_->format()), &jsResult);
296 if (status != napi_ok) {
297 MS_LOG(ERROR) << "napi_create_int32 error";
298 return undefinedResult;
299 }
300
301 MS_LOG(INFO) << "GetFormat success.";
302 return jsResult;
303 }
304
GetDataSize(napi_env env,napi_callback_info info)305 napi_value MSTensorNapi::GetDataSize(napi_env env, napi_callback_info info) {
306 napi_value undefinedResult = nullptr;
307 napi_get_undefined(env, &undefinedResult);
308 napi_value jsThis = nullptr;
309 napi_value jsResult = nullptr;
310 MSTensorNapi *tensor = nullptr;
311
312 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
313 if (status != napi_ok || jsThis == nullptr) {
314 MS_LOG(ERROR) << "Failed to retrieve details about the callback";
315 return undefinedResult;
316 }
317
318 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&tensor));
319 if (status != napi_ok || tensor == nullptr) {
320 MS_LOG(ERROR) << "get tensor napi error";
321 return undefinedResult;
322 }
323
324 status = napi_create_int32(env, tensor->nativeMSTensor_->DataSize(), &jsResult);
325 if (status != napi_ok) {
326 MS_LOG(ERROR) << "napi_create_int32 error";
327 return undefinedResult;
328 }
329
330 MS_LOG(INFO) << "GetDataSize success.";
331 return jsResult;
332 }
333
GetDataBuffer(napi_env env,napi_callback_info info)334 napi_value MSTensorNapi::GetDataBuffer(napi_env env, napi_callback_info info) {
335 napi_value undefinedResult = nullptr;
336 napi_get_undefined(env, &undefinedResult);
337
338 napi_value jsThis = nullptr;
339 napi_value jsResult = nullptr;
340 MSTensorNapi *tensor = nullptr;
341
342 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
343 if (status != napi_ok || jsThis == nullptr) {
344 MS_LOG(ERROR) << "Failed to retrieve details about the callback";
345 return undefinedResult;
346 }
347
348 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&tensor));
349 if (status != napi_ok || tensor == nullptr) {
350 MS_LOG(ERROR) << "get tensor napi error";
351 return undefinedResult;
352 }
353
354 size_t byte_length = tensor->nativeMSTensor_->DataSize();
355 auto tensor_data = tensor->nativeMSTensor_->MutableData();
356 if (tensor_data == nullptr) {
357 MS_LOG(ERROR) << "tensor_data is null.";
358 return undefinedResult;
359 }
360
361 void *data = nullptr;
362 status = napi_create_arraybuffer(env, byte_length, &data, &jsResult);
363 if (status != napi_ok) {
364 MS_LOG(ERROR) << "napi_create_arraybuffer error";
365 return undefinedResult;
366 }
367 if (data == nullptr || jsResult == nullptr) {
368 MS_LOG(ERROR) << "napi_create_arraybuffer error";
369 return undefinedResult;
370 }
371
372 memcpy(data, tensor_data, byte_length);
373 MS_LOG(INFO) << "GetDataBuffer success.";
374 return jsResult;
375 }
376
SetData(napi_env env,napi_callback_info info)377 napi_value MSTensorNapi::SetData(napi_env env, napi_callback_info info) {
378 napi_value undefinedResult = nullptr;
379 napi_get_undefined(env, &undefinedResult);
380 MSTensorNapi *tensor = nullptr;
381
382 GET_PARAMS(env, info, ARGS_TWO);
383
384 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&tensor));
385 if (status != napi_ok || tensor == nullptr) {
386 MS_LOG(ERROR) << "get tensor napi error";
387 return undefinedResult;
388 }
389
390 // convert napi_value to c++ type data
391 void *js_data = nullptr;
392 size_t length = 0;
393 status = napi_get_arraybuffer_info(env, argv[0], &js_data, &length);
394 if (status != napi_ok || js_data == nullptr) {
395 MS_LOG(ERROR) << "Get js data error.";
396 return undefinedResult;
397 }
398
399 if (tensor->nativeMSTensor_->DataSize() != length) {
400 MS_LOG(ERROR) << "tensor size is: " << static_cast<int>(tensor->nativeMSTensor_->DataSize())
401 << "but data length got " << length;
402 return undefinedResult;
403 }
404
405 // memcpy
406 auto tensor_data = tensor->nativeMSTensor_->MutableData();
407 if (tensor_data == nullptr) {
408 MS_LOG(ERROR) << "malloc data for tensor failed.";
409 return undefinedResult;
410 }
411 memcpy(tensor_data, js_data, length);
412
413 MS_LOG(INFO) << "SetFloatData success.";
414 return undefinedResult;
415 }
416 } // namespace mindspore