• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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