1 ///////////////////////////////////////////////////////
3 // VTT Technical Research Centre of Finland LTD //
4 // For internal use only. Do not redistribute. //
7 // Antton Tapani ext-antton.tapani@vtt.fi //
9 // Last modified by Antton Tapani 9.2016 //
11 ///////////////////////////////////////////////////////
17 jint throwException( JNIEnv *env, char *className, const char *message )
19 jclass exClass = (*env)->FindClass( env, className);
20 if (exClass == NULL) {
24 return (*env)->ThrowNew( env, exClass, message );
27 jint throwPythonException( JNIEnv *env, const char *message ) {
28 return throwException( env, PYTHON_EXCEPTION, message );
31 jint throwIllegalArgumentException( JNIEnv *env, const char *message ) {
32 return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message );
35 // Returns a borrowed reference.
36 PyObject* getModule(jlong contextID) {
37 return PyState_FindModule((PyModuleDef*) contextID);
38 // return PyImport_AddModule("__main__");
43 PyThreadState *main_ts = 0;
45 static JNIEnv *currentEnv = NULL;
46 jobject sclWriter = NULL;
49 writeToSCL(PyObject *self, PyObject *args)
51 if (currentEnv != NULL && sclWriter != NULL) {
54 JNIEnv *env = currentEnv;
56 if (!PyArg_ParseTuple(args, "u#", &what, &length))
60 PyThreadState *my_ts = PyThreadState_Get();
61 if (my_ts == main_ts) {
62 jclass writerClass = (*env)->FindClass(env, WRITER_CLASS);
63 jmethodID writeMethod = (*env)->GetMethodID(env, writerClass, "write", "([CII)V");
64 jcharArray chars = (*env)->NewCharArray(env, (jsize)length);
66 (*env)->SetCharArrayRegion(env, chars, 0, length, what);
67 Py_BEGIN_ALLOW_THREADS
68 (*env)->CallVoidMethod(env, sclWriter, writeMethod, chars, 0, length);
80 flushSCL(PyObject *self, PyObject *args)
82 if (currentEnv != NULL && sclWriter != NULL) {
83 JNIEnv *env = currentEnv;
84 PyThreadState *my_ts = PyThreadState_Get();
85 if (my_ts != main_ts) {
86 // TODO: Process calls from other threads
91 jclass writerClass = (*env)->FindClass(env, WRITER_CLASS);
92 jmethodID flushMethod = (*env)->GetMethodID(env, writerClass, "flush", "()V");
94 Py_BEGIN_ALLOW_THREADS
95 (*env)->CallVoidMethod(env, sclWriter, flushMethod);
103 static PyMethodDef sclWriterMethods[] = {
104 {"write", writeToSCL, METH_VARARGS, "Write something."},
105 {"flush", flushSCL, METH_VARARGS, "Flush output."},
106 {NULL, NULL, 0, NULL}
109 JNIEXPORT void JNICALL
110 Java_org_simantics_pythonlink_PythonContext_initializePython(
111 JNIEnv *env, jobject thisObj, jobject writer) {
115 static struct PyModuleDef moduledef = {
116 PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods
118 PyObject *m = PyModule_Create(&moduledef);
120 sclWriter = (*env)->NewGlobalRef(env, writer);
123 throwException(env, PYTHON_EXCEPTION,
124 "Failed to create SCL writer module");
126 PySys_SetObject("stdout", m);
127 PySys_SetObject("stderr", m);
132 hasNumpy = _import_array();
133 hasNumpy = hasNumpy != -1;
135 main_ts = PyEval_SaveThread();
138 JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {
145 sprintf(name, "SCL_%d", ++moduleCount);
147 PyEval_RestoreThread(main_ts);
150 PyModuleDef *modDef = malloc(sizeof(PyModuleDef));
151 memset(modDef, 0, sizeof(PyModuleDef));
152 modDef->m_name = strdup(name);
153 modDef->m_doc = NULL;
156 module = PyModule_Create(modDef);
157 PyState_AddModule(module, modDef);
159 PyObject *builtin = PyImport_AddModule("builtins");
160 PyObject *dict = PyModule_GetDict(module);
162 PyDict_SetItemString(dict, "__builtin__", builtin);
163 PyDict_SetItemString(dict, "__builtins__", builtin);
166 return (jlong)modDef;
171 JNIEXPORT void JNICALL
172 Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(
173 JNIEnv *env, jobject thisObj, jlong contextID) {
174 PyModuleDef *modDef = (PyModuleDef*)contextID;
175 PyEval_RestoreThread(main_ts);
176 PyState_RemoveModule(modDef);
177 free((char*)modDef->m_name);
182 PyObject *getPythonBool(jboolean value) {
191 PyObject *getPythonString(JNIEnv *env, jstring string) {
192 jsize len = (*env)->GetStringLength(env, string);
193 const jchar *chars = (*env)->GetStringChars(env, string, NULL);
195 PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
197 (*env)->ReleaseStringChars(env, string, chars);
201 PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) {
202 jsize nitems = (*env)->GetArrayLength(env, value);
203 jint *values = (*env)->GetIntArrayElements(env, value, NULL);
204 jclass stringClass = (*env)->FindClass(env, STRING_CLASS);
207 PyObject *result = PyList_New(nitems);
208 for (i = 0; i < nitems; i++) {
209 jobject item = (*env)->GetObjectArrayElement(env, value, i);
210 if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) {
211 PyList_SetItem(result, i, getPythonString(env, (jstring)item));
215 PyList_SetItem(result, i, Py_None);
219 (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
223 PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) {
224 jsize nitems = (*env)->GetArrayLength(env, value);
225 jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL);
228 PyObject *result = PyList_New(nitems);
229 for (i = 0; i < nitems; i++) {
230 PyList_SetItem(result, i, getPythonBool(values[i]));
233 (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT);
237 PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) {
238 jint len = (*env)->GetArrayLength(env, value);
239 jbyte *values = (*env)->GetByteArrayElements(env, value, NULL);
241 PyObject *result = PyByteArray_FromStringAndSize(values, len);
243 (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT);
247 PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {
248 jsize nitems = (*env)->GetArrayLength(env, value);
249 jint *values = (*env)->GetIntArrayElements(env, value, NULL);
252 PyObject *result = PyList_New(nitems);
253 for (i = 0; i < nitems; i++) {
254 PyList_SetItem(result, i, PyLong_FromLong(values[i]));
257 (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
261 PyObject *getPythonLongList(JNIEnv *env, jlongArray value) {
262 jsize nitems = (*env)->GetArrayLength(env, value);
263 jlong *values = (*env)->GetLongArrayElements(env, value, NULL);
266 PyObject *result = PyList_New(nitems);
267 for (i = 0; i < nitems; i++) {
268 PyList_SetItem(result, i, PyLong_FromLongLong(values[i]));
271 (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT);
275 PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) {
276 jsize nitems = (*env)->GetArrayLength(env, value);
277 float *values = (*env)->GetFloatArrayElements(env, value, NULL);
280 PyObject *result = PyList_New(nitems);
281 for (i = 0; i < nitems; i++) {
282 PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i]));
285 (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT);
289 PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) {
290 jsize nitems = (*env)->GetArrayLength(env, value);
291 double *values = (*env)->GetDoubleArrayElements(env, value, NULL);
294 PyObject *result = PyList_New(nitems);
295 for (i = 0; i < nitems; i++) {
296 PyList_SetItem(result, i, PyFloat_FromDouble(values[i]));
299 (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT);
303 PyObject *getPythonNDArray(JNIEnv *env, jobject value) {
304 jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
305 jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I");
306 jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D");
308 jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod);
309 jsize ndims = (*env)->GetArrayLength(env, jdims);
310 jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL);
312 jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod);
313 jsize len = (*env)->GetArrayLength(env, jvalues);
314 jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL);
316 npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp));
318 jint i, nelem = ndims > 0 ? 1 : 0;
319 for (i = 0; i < ndims; i++) {
324 len = min(len, nelem);
327 PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0);
328 double *data = (double *)PyArray_DATA((PyArrayObject*)array);
330 memcpy(data, values, len * sizeof(double));
334 (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT);
335 (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT);
341 PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) {
342 jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
343 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z");
345 jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object);
346 return getPythonBool(bvalue);
349 PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) {
350 jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS);
351 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B");
353 jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object);
354 return PyLong_FromLong(v);
357 PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) {
358 jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS);
359 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I");
361 jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object);
362 return PyLong_FromLong(v);
365 PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) {
366 jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS);
367 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J");
369 jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object);
370 return PyLong_FromLongLong(v);
373 PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) {
374 jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS);
375 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F");
377 jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object);
378 return PyFloat_FromDouble(v);
381 PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) {
382 jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
383 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D");
385 jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object);
386 return PyFloat_FromDouble(v);
389 PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) {
390 jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS);
391 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";");
393 jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
394 jsize len = (*env)->GetStringLength(env, string);
395 const jchar *chars = (*env)->GetStringChars(env, string, NULL);
397 PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
399 (*env)->ReleaseStringChars(env, string, chars);
403 PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) {
404 jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS);
405 jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
406 jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
407 jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
409 jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS);
410 jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";");
411 jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I");
413 jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
414 jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
416 jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
417 jint n = (*env)->CallIntMethod(env, type, getComponentCount);
420 PyObject *result = PyDict_New();
421 for (i = 0; i < n; i++) {
422 jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i);
423 jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField);
424 jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);
425 jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);
428 *key = getPythonString(env, fieldName),
429 *item = getPythonObject(env, componentObject, componentBinding);
430 PyDict_SetItem(result, key, item);
438 PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) {
439 jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS);
440 jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
441 jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
442 jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
444 jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
446 jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
448 PyObject *result = PyList_New(size);
451 for (i = 0; i < size; i++) {
452 jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);
454 PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));
457 PyList_SetItem(result, i, Py_None);
464 PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) {
465 jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS);
466 jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS);
467 jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";");
468 jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";");
469 jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
470 jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V");
472 jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod);
473 jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod);
475 jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
476 jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL);
477 jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL);
479 PyObject *result = PyDict_New();
482 (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values);
484 for (i = 0; i < size; i++) {
485 jobject key = (*env)->GetObjectArrayElement(env, keys, i);
486 jobject item = (*env)->GetObjectArrayElement(env, values, i);
488 *pkey = getPythonObject(env, key, keyBinding),
489 *pitem = getPythonObject(env, item, valueBinding);
490 PyDict_SetItem(result, pkey, pitem);
495 (*env)->DeleteLocalRef(env, keys);
496 (*env)->DeleteLocalRef(env, values);
501 PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) {
502 jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
503 jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z");
505 jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object);
508 jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
509 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
511 jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
512 jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
514 return getPythonObject(env, value, componentBinding);
521 PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) {
522 jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS);
523 jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
524 jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I");
525 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
526 jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
528 jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS);
529 jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";");
531 jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
532 jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
534 jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object);
535 jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
537 jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
538 jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag);
539 jstring compName = (*env)->GetObjectField(env, typeComponent, nameField);
541 jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag);
543 PyObject *result = PyTuple_New(2);
544 PyTuple_SetItem(result, 0, getPythonString(env, compName));
545 PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding));
550 PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) {
551 jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS);
552 jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
553 jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";");
555 jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object);
556 jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object);
558 return getPythonObject(env, content, contentBinding);
561 PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) {
562 jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
563 jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS);
564 jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS);
565 jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS);
566 jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS);
567 jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
568 jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS);
569 jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS);
570 jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS);
571 jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS);
572 jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
573 jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS);
574 jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS);
579 if ((*env)->IsInstanceOf(env, binding, booleanBinding)) {
580 return getPythonBooleanObject(env, value, binding);
582 else if ((*env)->IsInstanceOf(env, binding, byteBinding)) {
583 return getPythonByteObject(env, value, binding);
585 else if ((*env)->IsInstanceOf(env, binding, integerBinding)) {
586 return getPythonIntegerObject(env, value, binding);
588 else if ((*env)->IsInstanceOf(env, binding, longBinding)) {
589 return getPythonLongObject(env, value, binding);
591 else if ((*env)->IsInstanceOf(env, binding, floatBinding)) {
592 return getPythonFloatObject(env, value, binding);
594 else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) {
595 return getPythonDoubleObject(env, value, binding);
597 else if ((*env)->IsInstanceOf(env, binding, stringBinding)) {
598 return getPythonStringObject(env, value, binding);
600 else if ((*env)->IsInstanceOf(env, binding, recordBinding)) {
601 return getPythonRecordObject(env, value, binding);
603 else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) {
604 return getPythonArrayObject(env, value, binding);
606 else if ((*env)->IsInstanceOf(env, binding, mapBinding)) {
607 return getPythonMapObject(env, value, binding);
609 else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) {
610 return getPythonOptionalObject(env, value, binding);
612 else if ((*env)->IsInstanceOf(env, binding, untionBinding)) {
613 return getPythonUnionObject(env, value, binding);
615 else if ((*env)->IsInstanceOf(env, binding, variantBinding)) {
616 return getPythonVariantObject(env, value, binding);
623 // Steals refs to name & value.
624 void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {
626 PyDict_SetItem(PyModule_GetDict(module), name, value);
633 static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {
639 npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);
640 ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;
645 static void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {
647 (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);
652 for (i = 0; i < dims[d]; i++) {
653 copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);
658 jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) {
659 jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean");
660 jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");
662 return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True));
665 jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) {
666 jclass longClass = (*env)->FindClass(env, "java/lang/Long");
667 jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;");
669 return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value));
672 jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) {
673 jclass doubleClass = (*env)->FindClass(env, "java/lang/Double");
674 jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;");
676 return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value));
679 jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) {
680 Py_ssize_t size = PyByteArray_Size(value);
681 jbyteArray result = (*env)->NewByteArray(env, (jsize)size);
682 char *bytes = PyByteArray_AsString(value);
684 (*env)->SetByteArrayRegion(env, result, 0, size, bytes);
689 jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {
690 PyObject *utf16Value = PyUnicode_AsUTF16String(string);
691 Py_ssize_t len = PyBytes_Size(utf16Value) / 2;
692 char *bytes = PyBytes_AsString(utf16Value);
694 // Create Java string, skipping the byte order mark in the beginning
695 jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1);
697 Py_XDECREF(utf16Value);
702 jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) {
703 Py_ssize_t len = PySequence_Size(seq);
704 jsize jlen = (jsize)min(len, JAVA_MAXINT);
705 jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL);
709 for (i = 0; i < jlen; i++) {
710 PyObject *item = PySequence_GetItem(seq, i);
711 if (PyUnicode_Check(item)) {
712 jstring value = pythonStringAsJavaString(env, item);
714 (*env)->SetObjectArrayElement(env, array, i, value);
718 throwPythonException(env, "List item not a string");
726 jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) {
727 Py_ssize_t len = PySequence_Size(seq);
728 jsize jlen = (jsize)min(len, JAVA_MAXINT);
729 jdoubleArray array = (*env)->NewDoubleArray(env, jlen);
733 for (i = 0; i < jlen; i++) {
734 PyObject *item = PySequence_GetItem(seq, i);
735 if (PyFloat_Check(item)) {
736 jdouble value = PyFloat_AsDouble(item);
738 (*env)->SetDoubleArrayRegion(env, array, i, 1, &value);
742 throwPythonException(env, "List item not a floating point value");
750 jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) {
751 if (PyBool_Check(value))
752 return pythonBoolAsBooleanObject(env, value);
753 else if (PyLong_Check(value))
754 return pythonLongAsLongObject(env, value);
755 else if (PyFloat_Check(value))
756 return pythonFloatAsDoubleObject(env, value);
757 else if (PyUnicode_Check(value))
758 return pythonStringAsJavaString(env, value);
759 else if (PyByteArray_Check(value))
760 return pythonByteArrayAsByteArray(env, value);
761 else if (PyDict_Check(value))
762 return pythonDictionaryAsMap(env, value);
763 else if (hasNumpy && PyArray_Check(value))
764 return pythonArrayAsNDArray(env, (PyArrayObject *)value);
765 else if (PySequence_Check(value))
766 return pythonSequenceAsObjectArray(env, value);
771 jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) {
772 Py_ssize_t len = PySequence_Size(seq);
773 jsize jlen = (jsize)min(len, JAVA_MAXINT);
774 jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL);
778 for (i = 0; i < jlen; i++) {
779 PyObject *item = PySequence_GetItem(seq, i);
780 jobject object = pythonObjectAsObject(env, item);
782 (*env)->SetObjectArrayElement(env, array, i, object);
788 jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) {
789 Py_ssize_t len = PySequence_Size(seq);
790 jsize jlen = (jsize)min(len, JAVA_MAXINT);
791 jbooleanArray array = (*env)->NewBooleanArray(env, jlen);
795 for (i = 0; i < jlen; i++) {
796 PyObject *item = PySequence_GetItem(seq, i);
797 if (PyBool_Check(item)) {
798 jboolean value = item == Py_True;
800 (*env)->SetBooleanArrayRegion(env, array, i, 1, &value);
804 throwPythonException(env, "List item not a boolean");
812 jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) {
813 Py_ssize_t len = PySequence_Size(seq);
814 jsize jlen = (jsize)min(len, JAVA_MAXINT);
815 jintArray array = (*env)->NewIntArray(env, jlen);
819 for (i = 0; i < jlen; i++) {
820 PyObject *item = PySequence_GetItem(seq, i);
821 if (PyLong_Check(item)) {
822 jint value = PyLong_AsLong(item);
824 (*env)->SetIntArrayRegion(env, array, i, 1, &value);
828 throwPythonException(env, "List item not an integer");
836 jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) {
837 Py_ssize_t len = PySequence_Size(seq);
838 jsize jlen = (jsize)min(len, JAVA_MAXINT);
839 jlongArray array = (*env)->NewLongArray(env, jlen);
843 for (i = 0; i < jlen; i++) {
844 PyObject *item = PySequence_GetItem(seq, i);
845 if (PyLong_Check(item)) {
846 jlong value = PyLong_AsLongLong(item);
848 (*env)->SetLongArrayRegion(env, array, i, 1, &value);
852 throwPythonException(env, "List item not an integer");
860 jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {
861 jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
862 jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "<init>", "([I[D)V");
864 int ndims = PyArray_NDIM(array);
865 npy_intp *dims = PyArray_DIMS(array);
867 npy_intp len = PyArray_Size((PyObject*)array);
868 double *values = (double*)PyArray_DATA(array);
870 jboolean isFortran = PyArray_ISFORTRAN(array) != 0;
874 if (len > JAVA_MAXINT) {
875 throwPythonException(env, "Array too large");
880 jintArray jdims = (*env)->NewIntArray(env, ndims);
881 jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len);
883 for (i = 0; i < ndims; i++) {
884 jint dim = (jint)dims[i];
885 (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim);
888 if (PyArray_IS_C_CONTIGUOUS(array)) {
889 (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values);
893 npy_intp *strides = PyArray_STRIDES(array);
894 npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp));
895 nContiguous(0, ndims, strides, dims, ncont);
896 copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont);
900 return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran);
904 jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) {
905 jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap");
906 jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "<init>", "(I)V");
907 jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
909 Py_ssize_t size = PyDict_Size(dict);
910 jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size);
912 PyObject *key, *value;
915 while (PyDict_Next(dict, &pos, &key, &value)) {
916 jobject keyObject = pythonObjectAsObject(env, key);
917 jobject valueObject = pythonObjectAsObject(env, value);
918 (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject);
924 #define DEF_SETTER(typename, jtype, j2py) \
925 JNIEXPORT void JNICALL \
926 Java_org_simantics_pythonlink_PythonContext_setPython##typename \
928 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, \
932 PyEval_RestoreThread(main_ts); \
933 module = getModule(contextID); \
934 setPythonVariable(module, getPythonString(env, variableName), \
936 PyEval_SaveThread(); \
939 #define getPythonBoolean(env, value) getPythonBool(value)
940 #define getPythonLong(env, value) PyLong_FromLongLong(value)
941 #define getPythonDouble(env, value) PyFloat_FromDouble(value)
943 DEF_SETTER(Boolean, jboolean, getPythonBoolean)
944 DEF_SETTER(BooleanArray, jbooleanArray, getPythonBooleanList)
945 DEF_SETTER(Long, jlong, getPythonLong)
946 DEF_SETTER(IntegerArray, jintArray, getPythonIntegerList)
947 DEF_SETTER(LongArray, jlongArray, getPythonLongList)
948 DEF_SETTER(Double, jdouble, getPythonDouble)
949 DEF_SETTER(FloatArray, jfloatArray, getPythonFloatList)
950 DEF_SETTER(DoubleArray, jdoubleArray, getPythonDoubleList)
951 DEF_SETTER(String, jstring, getPythonString)
952 DEF_SETTER(StringArray, jobjectArray, getPythonStringList)
954 JNIEXPORT void JNICALL
955 Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(
956 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
959 throwPythonException(env, "Importing numpy failed");
963 PyEval_RestoreThread(main_ts);
965 PyObject *module = getModule(contextID);
966 PyObject *pythonName = getPythonString(env, variableName);
967 PyObject *val = getPythonNDArray(env, value);
969 setPythonVariable(module, pythonName, val);
974 JNIEXPORT void JNICALL
975 Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(
976 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
977 jobject value, jobject binding) {
980 PyEval_RestoreThread(main_ts);
981 module = getModule(contextID);
982 setPythonVariable(module, getPythonString(env, variableName),
983 getPythonObject(env, value, binding));
987 static PyObject *getExceptionMessage(PyObject *exceptionType, PyObject *exception, PyObject *traceback) {
988 PyObject *formatExc = NULL, *args = NULL;
989 PyObject *tracebackModule = PyImport_ImportModule("traceback");
990 if (!tracebackModule) {
994 if (exception && traceback) {
995 formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");
996 args = PyTuple_Pack(3, exceptionType, exception, traceback);
998 else if (exception) {
999 formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception_only");
1000 args = PyTuple_Pack(2, exceptionType, exception);
1003 Py_DECREF(tracebackModule);
1005 if (formatExc != NULL && args != NULL) {
1006 PyObject *result = PyObject_CallObject(formatExc, args);
1008 Py_XDECREF(formatExc);
1013 Py_XDECREF(formatExc);
1018 JNIEXPORT jint JNICALL
1019 Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
1020 JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {
1021 const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL);
1023 PyEval_RestoreThread(main_ts);
1026 PyObject *module = getModule(contextID);
1030 globals = PyModule_GetDict(module);
1035 PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);
1036 PyObject *exceptionType = PyErr_Occurred();
1038 if (exceptionType != NULL) {
1039 PyObject *exception, *traceback, *message;
1040 PyErr_Fetch(&exceptionType, &exception, &traceback);
1042 message = getExceptionMessage(exceptionType, exception, traceback);
1043 if (message != NULL) {
1044 PyObject *emptyStr = PyUnicode_FromString("");
1045 PyObject *joined = PyUnicode_Join(emptyStr, message);
1046 char *messageStr = PyUnicode_AsUTF8(joined);
1047 throwPythonException(env, messageStr);
1049 Py_DECREF(emptyStr);
1054 *ty = (PyTypeObject *)exceptionType;
1055 throwPythonException(
1056 env, ty ? ty->tp_name
1057 : "Internal error, null exception type");
1060 Py_XDECREF(exceptionType);
1061 Py_XDECREF(exception);
1062 Py_XDECREF(traceback);
1065 PyEval_SaveThread();
1066 (*env)->ReleaseStringUTFChars(env, statement, utfchars);
1070 return result != NULL ? 0 : 1;
1075 // Returns a borrowed reference.
1076 static PyObject *getPythonValue(
1077 JNIEnv *env, jlong contextID, jstring variableName) {
1078 PyObject *module = getModule(contextID);
1079 PyObject *pythonName = getPythonString(env, variableName);
1080 PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);
1082 Py_DECREF(pythonName);
1083 if (value == NULL) {
1084 throwPythonException(env, "Python variable not found");
1089 #define DEF_GETTER(typename, jtype, check, desc, py2j) \
1090 JNIEXPORT jtype JNICALL \
1091 Java_org_simantics_pythonlink_PythonContext_getPython##typename \
1093 JNIEnv *env, jobject thisObj, jlong contextID, \
1094 jstring variableName) { \
1096 PyEval_RestoreThread(main_ts); \
1098 PyObject *value = getPythonValue(env, contextID, variableName); \
1099 if (value == 0) break; \
1100 if (check(value)) { \
1101 result = py2j(env, value); \
1103 throwPythonException(env, "Python variable not " desc); \
1106 PyEval_SaveThread(); \
1110 #define pythonBoolAsJboolean(env, value) ((value) == Py_True)
1111 #define pythonLongAsJlong(env, value) PyLong_AsLongLong(value)
1112 #define pythonFloatAsJdouble(env, value) PyFloat_AsDouble(value)
1114 DEF_GETTER(String, jstring, PyUnicode_Check, "a string",
1115 pythonStringAsJavaString)
1116 DEF_GETTER(StringArray, jobjectArray, PySequence_Check, "a sequence",
1117 pythonSequenceAsStringArray)
1118 DEF_GETTER(Boolean, jboolean, PyBool_Check, "a Boolean", pythonBoolAsJboolean)
1119 DEF_GETTER(BooleanArray, jbooleanArray, PySequence_Check, "a sequence",
1120 pythonSequenceAsBooleanArray)
1121 DEF_GETTER(Long, jlong, PyLong_Check, "an integer", pythonLongAsJlong)
1122 DEF_GETTER(IntegerArray, jintArray, PySequence_Check, "a sequence",
1123 pythonSequenceAsIntegerArray)
1124 DEF_GETTER(LongArray, jlongArray, PySequence_Check, "a sequence",
1125 pythonSequenceAsLongArray)
1126 DEF_GETTER(Double, jdouble, PyFloat_Check, "a float", pythonFloatAsJdouble)
1127 DEF_GETTER(DoubleArray, jdoubleArray, PySequence_Check, "a sequence",
1128 pythonSequenceAsDoubleArray)
1130 JNIEXPORT jobject JNICALL
1131 Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(
1132 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
1133 jobject result = NULL;
1136 throwPythonException(env, "Importing numpy failed");
1140 PyEval_RestoreThread(main_ts);
1142 PyObject *value = getPythonValue(env, contextID, variableName);
1143 if (value == NULL) break;
1144 if (!PyArray_Check(value)) {
1145 throwPythonException(env, "Python variable not an ndarray");
1146 } else if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) {
1147 throwPythonException(
1148 env, "Only ndarrays of type double are supported");
1150 result = pythonArrayAsNDArray(env, (PyArrayObject *)value);
1153 PyEval_SaveThread();
1157 #define python_anything_goes(value) 1
1159 DEF_GETTER(Variant, jobject, python_anything_goes, "frabjous",
1160 pythonObjectAsObject)
1162 JNIEXPORT jint JNICALL
1163 Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(
1164 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
1166 PyEval_RestoreThread(main_ts);
1168 PyObject *value = getPythonValue(env, contextID, variableName);
1169 if (PyBool_Check(value))
1171 else if (PyLong_Check(value))
1173 else if (PyFloat_Check(value))
1175 else if (PyUnicode_Check(value))
1177 else if (PyByteArray_Check(value))
1179 else if (PyDict_Check(value))
1181 else if (hasNumpy && PyArray_Check(value))
1183 else if (PySequence_Check(value))
1188 PyEval_SaveThread();
1192 JNIEXPORT jobjectArray JNICALL
1193 Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(
1194 JNIEnv *env, jobject thisObj, jlong contextID) {
1195 jobjectArray result = NULL;
1196 PyEval_RestoreThread(main_ts);
1198 PyObject *module = getModule(contextID);
1199 PyObject *dict = PyModule_GetDict(module);
1201 PyObject *keys = PyDict_Keys(dict);
1202 Py_ssize_t size = PyList_Size(keys);
1205 result = (*env)->NewObjectArray(
1206 env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL);
1208 for (i = 0; i < size; i++) {
1209 jstring javaName = pythonStringAsJavaString(
1210 env, PyList_GetItem(keys, i));
1211 (*env)->SetObjectArrayElement(env, result, (jint)i, javaName);
1216 PyEval_SaveThread();
1220 BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1221 //extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1225 case DLL_PROCESS_ATTACH:
1226 // attach to process
1227 // return FALSE to fail DLL load
1230 case DLL_PROCESS_DETACH:
1231 // detach from process
1234 case DLL_THREAD_ATTACH:
1238 case DLL_THREAD_DETACH:
1239 // detach from thread
1242 return TRUE; // succesful