1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 /*!
20  * \file org_apache_tvm_native_c_api.cc
21  * \brief tvm4j jni source file
22  */
23 #include "org_apache_tvm_native_c_api.h"  // generated by javah
24 #ifdef TVM4J_ANDROID
25 #include "tvm_runtime.h"
26 #else
27 #include <dlfcn.h>
28 #include <dmlc/logging.h>
29 #include <dmlc/thread_local.h>
30 #include <tvm/runtime/c_runtime_api.h>
31 #endif
32 #include <iostream>
33 #include <cstring>
34 #include <vector>
35 #include <thread>
36 
37 #include "jni_helper_func.h"
38 
39 JavaVM *_jvm;
40 void *_tvmHandle = nullptr;
41 struct TVMFuncArgsThreadLocalEntry {
42   std::vector<TVMValue> tvmFuncArgValues;
43   std::vector<int> tvmFuncArgTypes;
44   // for later release
45   std::vector<std::pair<jstring, const char *> > tvmFuncArgPushedStrs;
46   std::vector<std::pair<jbyteArray, TVMByteArray *> > tvmFuncArgPushedBytes;
47 };
48 typedef dmlc::ThreadLocalStore<TVMFuncArgsThreadLocalEntry> TVMFuncArgsThreadLocalStore;
49 
Java_org_apache_tvm_LibInfo_nativeLibInit(JNIEnv * env,jobject obj,jstring jtvmLibFile)50 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_nativeLibInit
51   (JNIEnv *env, jobject obj, jstring jtvmLibFile) {
52   if (_tvmHandle == NULL && !env->IsSameObject(jtvmLibFile, NULL)) {
53     const char *tvmLibFile = env->GetStringUTFChars(jtvmLibFile, 0);
54     _tvmHandle = dlopen(tvmLibFile, RTLD_LAZY | RTLD_GLOBAL);
55     env->ReleaseStringUTFChars(jtvmLibFile, tvmLibFile);
56     if (!_tvmHandle) {
57       fprintf(stderr, "%s\n", dlerror());
58       return 1;
59     }
60   }
61   return env->GetJavaVM(&_jvm);
62 }
63 
Java_org_apache_tvm_LibInfo_shutdown(JNIEnv * env,jobject obj)64 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_shutdown(JNIEnv *env, jobject obj) {
65   if (_tvmHandle) {
66     dlclose(_tvmHandle);
67   }
68   return 0;
69 }
70 
Java_org_apache_tvm_LibInfo_tvmGetLastError(JNIEnv * env,jobject obj)71 JNIEXPORT jstring JNICALL Java_org_apache_tvm_LibInfo_tvmGetLastError(JNIEnv * env, jobject obj) {
72   return env->NewStringUTF(TVMGetLastError());
73 }
74 
75 // Function
Java_org_apache_tvm_LibInfo_tvmFuncPushArgLong(JNIEnv * env,jobject obj,jlong arg)76 JNIEXPORT void JNICALL Java_org_apache_tvm_LibInfo_tvmFuncPushArgLong(
77   JNIEnv *env, jobject obj, jlong arg) {
78   TVMValue value;
79   value.v_int64 = static_cast<int64_t>(arg);
80   TVMFuncArgsThreadLocalEntry *e = TVMFuncArgsThreadLocalStore::Get();
81   e->tvmFuncArgValues.push_back(value);
82   e->tvmFuncArgTypes.push_back(kDLInt);
83 }
84 
Java_org_apache_tvm_LibInfo_tvmFuncPushArgDouble(JNIEnv * env,jobject obj,jdouble arg)85 JNIEXPORT void JNICALL Java_org_apache_tvm_LibInfo_tvmFuncPushArgDouble(
86   JNIEnv *env, jobject obj, jdouble arg) {
87   TVMValue value;
88   value.v_float64 = static_cast<double>(arg);
89   TVMFuncArgsThreadLocalEntry *e = TVMFuncArgsThreadLocalStore::Get();
90   e->tvmFuncArgValues.push_back(value);
91   e->tvmFuncArgTypes.push_back(kDLFloat);
92 }
93 
Java_org_apache_tvm_LibInfo_tvmFuncPushArgString(JNIEnv * env,jobject obj,jstring arg)94 JNIEXPORT void JNICALL Java_org_apache_tvm_LibInfo_tvmFuncPushArgString(
95   JNIEnv *env, jobject obj, jstring arg) {
96   TVMValue value;
97   jstring garg = reinterpret_cast<jstring>(env->NewGlobalRef(arg));
98   value.v_str = env->GetStringUTFChars(garg, 0);
99   TVMFuncArgsThreadLocalEntry *e = TVMFuncArgsThreadLocalStore::Get();
100   e->tvmFuncArgValues.push_back(value);
101   e->tvmFuncArgTypes.push_back(kStr);
102   // release string args later
103   e->tvmFuncArgPushedStrs.push_back(std::make_pair(garg, value.v_str));
104 }
105 
Java_org_apache_tvm_LibInfo_tvmFuncPushArgHandle(JNIEnv * env,jobject obj,jlong arg,jint argType)106 JNIEXPORT void JNICALL Java_org_apache_tvm_LibInfo_tvmFuncPushArgHandle(
107   JNIEnv *env, jobject obj, jlong arg, jint argType) {
108   TVMValue value;
109   value.v_handle = reinterpret_cast<void *>(arg);
110   TVMFuncArgsThreadLocalEntry *e = TVMFuncArgsThreadLocalStore::Get();
111   e->tvmFuncArgValues.push_back(value);
112   e->tvmFuncArgTypes.push_back(static_cast<int>(argType));
113 }
114 
Java_org_apache_tvm_LibInfo_tvmFuncPushArgBytes(JNIEnv * env,jobject obj,jbyteArray arg)115 JNIEXPORT void JNICALL Java_org_apache_tvm_LibInfo_tvmFuncPushArgBytes(
116   JNIEnv *env, jobject obj, jbyteArray arg) {
117   jbyteArray garg = reinterpret_cast<jbyteArray>(env->NewGlobalRef(arg));
118   jbyte *data = env->GetByteArrayElements(garg, 0);
119 
120   TVMByteArray *byteArray = new TVMByteArray();
121   byteArray->size = static_cast<size_t>(env->GetArrayLength(garg));
122   byteArray->data = reinterpret_cast<const char *>(data);
123 
124   TVMValue value;
125   value.v_handle = reinterpret_cast<void *>(byteArray);
126 
127   TVMFuncArgsThreadLocalEntry *e = TVMFuncArgsThreadLocalStore::Get();
128   e->tvmFuncArgValues.push_back(value);
129   e->tvmFuncArgTypes.push_back(kBytes);
130 
131   e->tvmFuncArgPushedBytes.push_back(std::make_pair(garg, byteArray));
132   // release (garg, data), byteArray later
133 }
134 
Java_org_apache_tvm_LibInfo_tvmFuncListGlobalNames(JNIEnv * env,jobject obj,jobject jfuncNames)135 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmFuncListGlobalNames(
136   JNIEnv *env, jobject obj, jobject jfuncNames) {
137   int outSize;
138   const char **outArray;
139 
140   int ret = TVMFuncListGlobalNames(&outSize, &outArray);
141   if (ret) {
142     return ret;
143   }
144 
145   jclass arrayClass = env->FindClass("java/util/List");
146   jmethodID arrayAppend = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
147 
148   // fill names
149   for (int i = 0; i < outSize; ++i) {
150     jstring jname = env->NewStringUTF(outArray[i]);
151     env->CallBooleanMethod(jfuncNames, arrayAppend, jname);
152     env->DeleteLocalRef(jname);
153   }
154 
155   env->DeleteLocalRef(arrayClass);
156 
157   return ret;
158 }
159 
Java_org_apache_tvm_LibInfo_tvmFuncFree(JNIEnv * env,jobject obj,jlong jhandle)160 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmFuncFree(
161   JNIEnv *env, jobject obj, jlong jhandle) {
162   return TVMFuncFree(reinterpret_cast<TVMFunctionHandle>(jhandle));
163 }
164 
Java_org_apache_tvm_LibInfo_tvmFuncGetGlobal(JNIEnv * env,jobject obj,jstring jname,jobject jhandle)165 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmFuncGetGlobal(
166   JNIEnv *env, jobject obj, jstring jname, jobject jhandle) {
167   TVMFunctionHandle handle;
168   const char *name = env->GetStringUTFChars(jname, 0);
169   int ret = TVMFuncGetGlobal(name, &handle);
170   env->ReleaseStringUTFChars(jname, name);
171   setLongField(env, jhandle, reinterpret_cast<jlong>(handle));
172   return ret;
173 }
174 
Java_org_apache_tvm_LibInfo_tvmFuncCall(JNIEnv * env,jobject obj,jlong jhandle,jobject jretVal)175 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmFuncCall(
176   JNIEnv *env, jobject obj, jlong jhandle, jobject jretVal) {
177   TVMFuncArgsThreadLocalEntry *e = TVMFuncArgsThreadLocalStore::Get();
178   int numArgs = e->tvmFuncArgValues.size();
179 
180   TVMValue retVal;
181   int retTypeCode;
182 
183   // function can be invoked recursively,
184   // thus we copy the pushed arguments here.
185   auto argValues = e->tvmFuncArgValues;
186   auto argTypes = e->tvmFuncArgTypes;
187   auto pushedStrs = e->tvmFuncArgPushedStrs;
188   auto pushedBytes = e->tvmFuncArgPushedBytes;
189 
190   e->tvmFuncArgPushedStrs.clear();
191   e->tvmFuncArgPushedBytes.clear();
192   e->tvmFuncArgTypes.clear();
193   e->tvmFuncArgValues.clear();
194 
195   int ret = TVMFuncCall(reinterpret_cast<TVMFunctionHandle>(jhandle),
196     &argValues[0], &argTypes[0], numArgs, &retVal, &retTypeCode);
197 
198   if (ret != 0) {
199     return ret;
200   }
201 
202   for (auto iter = pushedStrs.cbegin(); iter != pushedStrs.cend(); iter++) {
203     env->ReleaseStringUTFChars(iter->first, iter->second);
204     env->DeleteGlobalRef(iter->first);
205   }
206   for (auto iter = pushedBytes.cbegin(); iter != pushedBytes.cend(); iter++) {
207     env->ReleaseByteArrayElements(iter->first,
208         reinterpret_cast<jbyte *>(const_cast<char *>(iter->second->data)), 0);
209     env->DeleteGlobalRef(iter->first);
210     delete iter->second;
211   }
212 
213   // return TVMValue object to Java
214   jclass refTVMValueCls = env->FindClass("org/apache/tvm/Base$RefTVMValue");
215   jfieldID refTVMValueFid
216     = env->GetFieldID(refTVMValueCls, "value", "Lorg/apache/tvm/TVMValue;");
217 
218   env->SetObjectField(jretVal, refTVMValueFid, tvmRetValueToJava(env, retVal, retTypeCode));
219 
220   env->DeleteLocalRef(refTVMValueCls);
221 
222   return ret;
223 }
224 
225 // Callback function
funcInvokeCallback(TVMValue * args,int * typeCodes,int numArgs,TVMRetValueHandle ret,void * resourceHandle)226 extern "C" int funcInvokeCallback(TVMValue *args,
227     int *typeCodes, int numArgs, TVMRetValueHandle ret, void *resourceHandle) {
228   JNIEnv *env;
229   int jniStatus = _jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
230   if (jniStatus == JNI_EDETACHED) {
231   #ifdef TVM4J_ANDROID
232     _jvm->AttachCurrentThread(&env, nullptr);
233   #else
234     _jvm->AttachCurrentThread(reinterpret_cast<void **>(&env), nullptr);
235   #endif
236   } else {
237     CHECK(jniStatus == JNI_OK);
238   }
239 
240   jclass tvmValueCls = env->FindClass("org/apache/tvm/TVMValue");
241   jobjectArray jargs = env->NewObjectArray(numArgs, tvmValueCls, 0);
242   for (int i = 0; i < numArgs; ++i) {
243     TVMValue arg = args[i];
244     int tcode = typeCodes[i];
245     if (tcode == kObjectHandle || tcode == kFuncHandle || tcode == kModuleHandle) {
246       TVMCbArgToReturn(&arg, tcode);
247     }
248     jobject jarg = tvmRetValueToJava(env, arg, tcode);
249     env->SetObjectArrayElement(jargs, i, jarg);
250   }
251 
252   jclass clsFunc = env->FindClass("org/apache/tvm/Function");
253   jmethodID invokeRegisteredCbFunc = env->GetStaticMethodID(clsFunc, "invokeRegisteredCbFunc",
254       "(Lorg/apache/tvm/Function$Callback;[Lorg/apache/tvm/TVMValue;)Ljava/lang/Object;");
255   jmethodID pushArgToStack = env->GetStaticMethodID(clsFunc, "pushArgToStack",
256       "(Ljava/lang/Object;)V");
257 
258   jobject jretValue = env->CallStaticObjectMethod(clsFunc, invokeRegisteredCbFunc,
259       reinterpret_cast<jobject>(resourceHandle), jargs);
260 
261   TVMFuncArgsThreadLocalEntry *e = TVMFuncArgsThreadLocalStore::Get();
262   const size_t prevNumStrArg = e->tvmFuncArgPushedStrs.size();
263   const size_t prevNumBytesArg = e->tvmFuncArgPushedBytes.size();
264 
265   // convert returned (java) TVMValue to (C) TVMValue
266   env->CallStaticVoidMethod(clsFunc, pushArgToStack, jretValue);
267 
268   TVMValue retValue = e->tvmFuncArgValues.back();
269   e->tvmFuncArgValues.pop_back();
270 
271   int retCode = e->tvmFuncArgTypes.back();
272   e->tvmFuncArgTypes.pop_back();
273 
274   // set back the return value
275   TVMCFuncSetReturn(ret, &retValue, &retCode, 1);
276 
277   // release allocated strings.
278   if (e->tvmFuncArgPushedStrs.size() > prevNumStrArg) {
279     const auto &pairArg = e->tvmFuncArgPushedStrs.back();
280     env->ReleaseStringUTFChars(pairArg.first, pairArg.second);
281     env->DeleteGlobalRef(pairArg.first);
282     e->tvmFuncArgPushedStrs.pop_back();
283   }
284   // release allocated bytes.
285   if (e->tvmFuncArgPushedBytes.size() > prevNumBytesArg) {
286     const auto &pairArg = e->tvmFuncArgPushedBytes.back();
287     env->ReleaseByteArrayElements(pairArg.first,
288         reinterpret_cast<jbyte *>(const_cast<char *>(pairArg.second->data)), 0);
289     env->DeleteGlobalRef(pairArg.first);
290     delete pairArg.second;
291     e->tvmFuncArgPushedBytes.pop_back();
292   }
293 
294   env->DeleteLocalRef(clsFunc);
295   env->DeleteLocalRef(tvmValueCls);
296 
297   return 0;
298 }
299 
300 // Free callback function
funcFreeCallback(void * resourceHandle)301 extern "C" void funcFreeCallback(void *resourceHandle) {
302   JNIEnv *env;
303   int jniStatus = _jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
304   if (jniStatus == JNI_EDETACHED) {
305   #ifdef TVM4J_ANDROID
306     _jvm->AttachCurrentThread(&env, nullptr);
307   #else
308     _jvm->AttachCurrentThread(reinterpret_cast<void **>(&env), nullptr);
309   #endif
310   } else {
311     CHECK(jniStatus == JNI_OK);
312   }
313   env->DeleteGlobalRef(reinterpret_cast<jobject>(resourceHandle));
314 }
315 
Java_org_apache_tvm_LibInfo_tvmFuncCreateFromCFunc(JNIEnv * env,jobject obj,jobject jfunction,jobject jretHandle)316 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmFuncCreateFromCFunc(
317   JNIEnv *env, jobject obj, jobject jfunction, jobject jretHandle) {
318   TVMFunctionHandle out;
319   int ret = TVMFuncCreateFromCFunc(reinterpret_cast<TVMPackedCFunc>(&funcInvokeCallback),
320                                    reinterpret_cast<void *>(env->NewGlobalRef(jfunction)),
321                                    reinterpret_cast<TVMPackedCFuncFinalizer>(&funcFreeCallback),
322                                    &out);
323   setLongField(env, jretHandle, reinterpret_cast<jlong>(out));
324   return ret;
325 }
326 
Java_org_apache_tvm_LibInfo_tvmFuncRegisterGlobal(JNIEnv * env,jobject obj,jstring jname,jlong jhandle,jint joverride)327 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmFuncRegisterGlobal(
328   JNIEnv *env, jobject obj, jstring jname, jlong jhandle, jint joverride) {
329   const char *name = env->GetStringUTFChars(jname, 0);
330   int ret = TVMFuncRegisterGlobal(
331       name, reinterpret_cast<TVMFunctionHandle>(jhandle), reinterpret_cast<int>(joverride));
332   env->ReleaseStringUTFChars(jname, name);
333   return ret;
334 }
335 
336 // Module
Java_org_apache_tvm_LibInfo_tvmModFree(JNIEnv * env,jobject obj,jlong jhandle)337 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmModFree(
338   JNIEnv *env, jobject obj, jlong jhandle) {
339   return TVMModFree(reinterpret_cast<TVMModuleHandle>(jhandle));
340 }
341 
Java_org_apache_tvm_LibInfo_tvmModImport(JNIEnv * env,jobject obj,jlong jmod,jlong jdep)342 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmModImport(
343   JNIEnv *env, jobject obj, jlong jmod, jlong jdep) {
344   return TVMModImport(reinterpret_cast<TVMModuleHandle>(jmod),
345                       reinterpret_cast<TVMModuleHandle>(jdep));
346 }
347 
Java_org_apache_tvm_LibInfo_tvmModGetFunction(JNIEnv * env,jobject obj,jlong jhandle,jstring jname,jint jimport,jobject jret)348 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmModGetFunction(
349   JNIEnv *env, jobject obj, jlong jhandle, jstring jname, jint jimport, jobject jret) {
350   TVMFunctionHandle retFunc;
351 
352   const char *name = env->GetStringUTFChars(jname, 0);
353   int ret = TVMModGetFunction(reinterpret_cast<TVMFunctionHandle>(jhandle),
354                               name,
355                               reinterpret_cast<int>(jimport),
356                               &retFunc);
357   env->ReleaseStringUTFChars(jname, name);
358 
359   setLongField(env, jret, reinterpret_cast<jlong>(retFunc));
360 
361   return ret;
362 }
363 
364 // NDArray
Java_org_apache_tvm_LibInfo_tvmArrayFree(JNIEnv * env,jobject obj,jlong jhandle)365 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmArrayFree(
366   JNIEnv *env, jobject obj, jlong jhandle) {
367   return TVMArrayFree(reinterpret_cast<TVMArrayHandle>(jhandle));
368 }
369 
Java_org_apache_tvm_LibInfo_tvmArrayAlloc(JNIEnv * env,jobject obj,jlongArray jshape,jint jdtypeCode,jint jdtypeBits,jint jdtypeLanes,jint jdeviceType,jint jdeviceId,jobject jret)370 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmArrayAlloc(
371   JNIEnv *env, jobject obj, jlongArray jshape, jint jdtypeCode,
372   jint jdtypeBits, jint jdtypeLanes, jint jdeviceType, jint jdeviceId, jobject jret) {
373   int ndim = static_cast<int>(env->GetArrayLength(jshape));
374 
375   TVMArrayHandle out;
376 
377   jlong *shapeArray = env->GetLongArrayElements(jshape, NULL);
378   int ret = TVMArrayAlloc(
379       reinterpret_cast<const tvm_index_t*>(shapeArray),
380       ndim,
381       static_cast<int>(jdtypeCode),
382       static_cast<int>(jdtypeBits),
383       static_cast<int>(jdtypeLanes),
384       static_cast<int>(jdeviceType),
385       static_cast<int>(jdeviceId),
386       &out);
387   env->ReleaseLongArrayElements(jshape, shapeArray, 0);
388 
389   setLongField(env, jret, reinterpret_cast<jlong>(out));
390 
391   return ret;
392 }
393 
Java_org_apache_tvm_LibInfo_tvmArrayGetShape(JNIEnv * env,jobject obj,jlong jhandle,jobject jshape)394 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmArrayGetShape(
395   JNIEnv *env, jobject obj, jlong jhandle, jobject jshape) {
396   TVMArray *array = reinterpret_cast<TVMArray *>(jhandle);
397   int64_t *shape = array->shape;
398   int ndim = array->ndim;
399 
400   // fill shape buffer
401   jclass longClass = env->FindClass("java/lang/Long");
402   jmethodID newLong = env->GetMethodID(longClass, "<init>", "(J)V");
403 
404   jclass arrayClass = env->FindClass("java/util/List");
405   jmethodID arrayAppend = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
406   for (int i = 0; i < ndim; ++i) {
407     jobject data = env->NewObject(longClass, newLong, static_cast<jlong>(shape[i]));
408     env->CallBooleanMethod(jshape, arrayAppend, data);
409     env->DeleteLocalRef(data);
410   }
411   env->DeleteLocalRef(longClass);
412   env->DeleteLocalRef(arrayClass);
413 
414   return 0;
415 }
416 
Java_org_apache_tvm_LibInfo_tvmArrayCopyFromTo(JNIEnv * env,jobject obj,jlong jfrom,jlong jto)417 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmArrayCopyFromTo(
418   JNIEnv *env, jobject obj, jlong jfrom, jlong jto) {
419   return TVMArrayCopyFromTo(reinterpret_cast<TVMArrayHandle>(jfrom),
420                             reinterpret_cast<TVMArrayHandle>(jto), NULL);
421 }
422 
Java_org_apache_tvm_LibInfo_tvmArrayCopyFromJArray(JNIEnv * env,jobject obj,jbyteArray jarr,jlong jfrom,jlong jto)423 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmArrayCopyFromJArray(
424   JNIEnv *env, jobject obj, jbyteArray jarr, jlong jfrom, jlong jto) {
425   jbyte *data = env->GetByteArrayElements(jarr, NULL);
426 
427   TVMArray *from = reinterpret_cast<TVMArray *>(jfrom);
428   from->data = static_cast<void *>(data);
429 
430   int ret = TVMArrayCopyFromTo(static_cast<TVMArrayHandle>(from),
431                                reinterpret_cast<TVMArrayHandle>(jto), NULL);
432 
433   from->data = NULL;
434   env->ReleaseByteArrayElements(jarr, data, 0);
435 
436   return ret;
437 }
438 
Java_org_apache_tvm_LibInfo_tvmArrayCopyToJArray(JNIEnv * env,jobject obj,jlong jfrom,jbyteArray jarr)439 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmArrayCopyToJArray(
440   JNIEnv *env, jobject obj, jlong jfrom, jbyteArray jarr) {
441   TVMArray *from = reinterpret_cast<TVMArray *>(jfrom);
442   int size = static_cast<int>(env->GetArrayLength(jarr));
443   jbyte *pdata = env->GetByteArrayElements(jarr, NULL);
444   int ret = 0;
445   if (memcpy(static_cast<void *>(pdata), from->data, size) == NULL) {
446     ret = 1;
447   }
448   env->ReleaseByteArrayElements(jarr, pdata, 0);  // copy back to java array automatically
449   return ret;
450 }
451 
452 // Context
Java_org_apache_tvm_LibInfo_tvmSynchronize(JNIEnv * env,jint deviceType,jint deviceId)453 JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmSynchronize(
454   JNIEnv *env, jint deviceType, jint deviceId) {
455   return TVMSynchronize(static_cast<int>(deviceType), static_cast<int>(deviceId), NULL);
456 }
457