Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 1 | /* |
Alexander Steffen | 55f3324 | 2017-06-30 09:22:17 +0200 | [diff] [blame] | 2 | * This file is part of the MicroPython project, http://micropython.org/ |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 3 | * |
| 4 | * The MIT License (MIT) |
| 5 | * |
| 6 | * Copyright (c) 2015 Paul Sokolovsky |
| 7 | * |
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 9 | * of this software and associated documentation files (the "Software"), to deal |
| 10 | * in the Software without restriction, including without limitation the rights |
| 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 12 | * copies of the Software, and to permit persons to whom the Software is |
| 13 | * furnished to do so, subject to the following conditions: |
| 14 | * |
| 15 | * The above copyright notice and this permission notice shall be included in |
| 16 | * all copies or substantial portions of the Software. |
| 17 | * |
| 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 24 | * THE SOFTWARE. |
| 25 | */ |
| 26 | |
| 27 | #include <assert.h> |
| 28 | #include <string.h> |
| 29 | #include <errno.h> |
| 30 | #include <dlfcn.h> |
Paul Sokolovsky | 0eba162 | 2015-09-30 00:54:20 -0700 | [diff] [blame] | 31 | #include <ctype.h> |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 32 | |
| 33 | #include "py/nlr.h" |
Paul Sokolovsky | f3ca862 | 2015-09-29 10:05:30 -0700 | [diff] [blame] | 34 | #include "py/runtime0.h" |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 35 | #include "py/runtime.h" |
| 36 | #include "py/binary.h" |
| 37 | |
| 38 | #include <jni.h> |
| 39 | |
| 40 | #define JJ(call, ...) (*env)->call(env, __VA_ARGS__) |
Paul Sokolovsky | 7a4b10c | 2015-09-14 00:12:27 +0300 | [diff] [blame] | 41 | #define JJ1(call) (*env)->call(env) |
Paul Sokolovsky | 02041bf | 2015-10-09 00:25:26 +0300 | [diff] [blame] | 42 | #define MATCH(s, static) (!strncmp(s, static, sizeof(static) - 1)) |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 43 | |
| 44 | static JavaVM *jvm; |
| 45 | static JNIEnv *env; |
Paul Sokolovsky | 1cb5de2 | 2015-09-17 13:31:16 +0300 | [diff] [blame] | 46 | static jclass Class_class; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 47 | static jclass String_class; |
Paul Sokolovsky | 3c7e1b8 | 2015-11-11 16:43:27 +0200 | [diff] [blame] | 48 | static jmethodID Class_getName_mid; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 49 | static jmethodID Class_getField_mid; |
| 50 | static jmethodID Class_getMethods_mid; |
| 51 | static jmethodID Class_getConstructors_mid; |
| 52 | static jmethodID Method_getName_mid; |
Paul Sokolovsky | f22be4e | 2015-10-03 08:43:41 -0700 | [diff] [blame] | 53 | static jmethodID Object_toString_mid; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 54 | |
Paul Sokolovsky | b2d880d | 2015-09-21 12:02:22 -0700 | [diff] [blame] | 55 | static jclass List_class; |
| 56 | static jmethodID List_get_mid; |
| 57 | static jmethodID List_set_mid; |
Paul Sokolovsky | f3ca862 | 2015-09-29 10:05:30 -0700 | [diff] [blame] | 58 | static jmethodID List_size_mid; |
Paul Sokolovsky | b2d880d | 2015-09-21 12:02:22 -0700 | [diff] [blame] | 59 | |
Paul Sokolovsky | 9e0a3d4 | 2015-10-02 00:21:07 -0700 | [diff] [blame] | 60 | static jclass IndexException_class; |
| 61 | |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 62 | STATIC const mp_obj_type_t jobject_type; |
| 63 | STATIC const mp_obj_type_t jmethod_type; |
| 64 | |
Paul Sokolovsky | 7a4b10c | 2015-09-14 00:12:27 +0300 | [diff] [blame] | 65 | STATIC mp_obj_t new_jobject(jobject jo); |
Paul Sokolovsky | 1cb5de2 | 2015-09-17 13:31:16 +0300 | [diff] [blame] | 66 | STATIC mp_obj_t new_jclass(jclass jc); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 67 | STATIC mp_obj_t call_method(jobject obj, const char *name, jarray methods, bool is_constr, mp_uint_t n_args, const mp_obj_t *args); |
Paul Sokolovsky | 3fea1f0 | 2016-09-16 00:59:48 +0300 | [diff] [blame] | 68 | STATIC bool py2jvalue(const char **jtypesig, mp_obj_t arg, jvalue *out); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 69 | |
| 70 | typedef struct _mp_obj_jclass_t { |
| 71 | mp_obj_base_t base; |
| 72 | jclass cls; |
| 73 | } mp_obj_jclass_t; |
| 74 | |
| 75 | typedef struct _mp_obj_jobject_t { |
| 76 | mp_obj_base_t base; |
| 77 | jobject obj; |
| 78 | } mp_obj_jobject_t; |
| 79 | |
| 80 | typedef struct _mp_obj_jmethod_t { |
| 81 | mp_obj_base_t base; |
| 82 | jobject obj; |
| 83 | jmethodID meth; |
| 84 | qstr name; |
Paul Sokolovsky | 7a4b10c | 2015-09-14 00:12:27 +0300 | [diff] [blame] | 85 | bool is_static; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 86 | } mp_obj_jmethod_t; |
| 87 | |
Paul Sokolovsky | e632b1f | 2015-09-23 07:10:55 -0700 | [diff] [blame] | 88 | // Utility functions |
| 89 | |
| 90 | STATIC bool is_object_type(const char *jtypesig) { |
| 91 | while (*jtypesig != ' ' && *jtypesig) { |
| 92 | if (*jtypesig == '.') { |
| 93 | return true; |
| 94 | } |
| 95 | jtypesig++; |
| 96 | } |
| 97 | return false; |
| 98 | } |
| 99 | |
Paul Sokolovsky | c4489a0 | 2015-10-01 01:19:33 -0700 | [diff] [blame] | 100 | STATIC void check_exception(void) { |
| 101 | jobject exc = JJ1(ExceptionOccurred); |
| 102 | if (exc) { |
| 103 | //JJ1(ExceptionDescribe); |
| 104 | mp_obj_t py_e = new_jobject(exc); |
| 105 | JJ1(ExceptionClear); |
Paul Sokolovsky | 9e0a3d4 | 2015-10-02 00:21:07 -0700 | [diff] [blame] | 106 | if (JJ(IsInstanceOf, exc, IndexException_class)) { |
| 107 | nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, py_e)); |
| 108 | } |
Paul Sokolovsky | c4489a0 | 2015-10-01 01:19:33 -0700 | [diff] [blame] | 109 | nlr_raise(mp_obj_new_exception_arg1(&mp_type_Exception, py_e)); |
| 110 | } |
| 111 | } |
| 112 | |
Paul Sokolovsky | 1ea4b77 | 2015-10-04 01:56:40 +0300 | [diff] [blame] | 113 | STATIC void print_jobject(const mp_print_t *print, jobject obj) { |
| 114 | jobject str_o = JJ(CallObjectMethod, obj, Object_toString_mid); |
| 115 | const char *str = JJ(GetStringUTFChars, str_o, NULL); |
| 116 | mp_printf(print, str); |
| 117 | JJ(ReleaseStringUTFChars, str_o, str); |
| 118 | } |
| 119 | |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 120 | // jclass |
| 121 | |
| 122 | STATIC void jclass_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 123 | mp_obj_jclass_t *self = self_in; |
Paul Sokolovsky | 1ea4b77 | 2015-10-04 01:56:40 +0300 | [diff] [blame] | 124 | if (kind == PRINT_REPR) { |
| 125 | mp_printf(print, "<jclass @%p \"", self->cls); |
| 126 | } |
| 127 | print_jobject(print, self->cls); |
| 128 | if (kind == PRINT_REPR) { |
| 129 | mp_printf(print, "\">"); |
| 130 | } |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 131 | } |
| 132 | |
| 133 | STATIC void jclass_attr(mp_obj_t self_in, qstr attr_in, mp_obj_t *dest) { |
| 134 | if (dest[0] == MP_OBJ_NULL) { |
| 135 | // load attribute |
| 136 | mp_obj_jclass_t *self = self_in; |
| 137 | const char *attr = qstr_str(attr_in); |
| 138 | |
| 139 | jstring field_name = JJ(NewStringUTF, attr); |
| 140 | jobject field = JJ(CallObjectMethod, self->cls, Class_getField_mid, field_name); |
Paul Sokolovsky | 7a4b10c | 2015-09-14 00:12:27 +0300 | [diff] [blame] | 141 | if (!JJ1(ExceptionCheck)) { |
| 142 | jfieldID field_id = JJ(FromReflectedField, field); |
| 143 | jobject obj = JJ(GetStaticObjectField, self->cls, field_id); |
| 144 | dest[0] = new_jobject(obj); |
| 145 | return; |
| 146 | } |
| 147 | //JJ1(ExceptionDescribe); |
| 148 | JJ1(ExceptionClear); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 149 | |
Paul Sokolovsky | 7a4b10c | 2015-09-14 00:12:27 +0300 | [diff] [blame] | 150 | mp_obj_jmethod_t *o = m_new_obj(mp_obj_jmethod_t); |
| 151 | o->base.type = &jmethod_type; |
| 152 | o->name = attr_in; |
| 153 | o->meth = NULL; |
| 154 | o->obj = self->cls; |
| 155 | o->is_static = true; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 156 | dest[0] = o; |
| 157 | } |
| 158 | } |
| 159 | |
Paul Sokolovsky | eac22e2 | 2017-01-04 16:10:42 +0300 | [diff] [blame] | 160 | STATIC mp_obj_t jclass_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 161 | if (n_kw != 0) { |
Damien George | 48d867b | 2017-06-15 11:54:41 +1000 | [diff] [blame] | 162 | mp_raise_TypeError("kwargs not supported"); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 163 | } |
| 164 | mp_obj_jclass_t *self = self_in; |
| 165 | |
| 166 | jarray methods = JJ(CallObjectMethod, self->cls, Class_getConstructors_mid); |
| 167 | |
| 168 | return call_method(self->cls, NULL, methods, true, n_args, args); |
| 169 | } |
| 170 | |
Paul Sokolovsky | e280122 | 2017-07-30 10:03:14 +0300 | [diff] [blame] | 171 | STATIC const mp_rom_map_elem_t jclass_locals_dict_table[] = { |
| 172 | // { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&ffivar_get_obj) }, |
| 173 | // { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&ffivar_set_obj) }, |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 174 | }; |
| 175 | |
| 176 | STATIC MP_DEFINE_CONST_DICT(jclass_locals_dict, jclass_locals_dict_table); |
| 177 | |
| 178 | STATIC const mp_obj_type_t jclass_type = { |
| 179 | { &mp_type_type }, |
| 180 | .name = MP_QSTR_jclass, |
| 181 | .print = jclass_print, |
| 182 | .attr = jclass_attr, |
| 183 | .call = jclass_call, |
Paul Sokolovsky | e280122 | 2017-07-30 10:03:14 +0300 | [diff] [blame] | 184 | .locals_dict = (mp_obj_dict_t*)&jclass_locals_dict, |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 185 | }; |
| 186 | |
Paul Sokolovsky | 1cb5de2 | 2015-09-17 13:31:16 +0300 | [diff] [blame] | 187 | STATIC mp_obj_t new_jclass(jclass jc) { |
| 188 | mp_obj_jclass_t *o = m_new_obj(mp_obj_jclass_t); |
| 189 | o->base.type = &jclass_type; |
| 190 | o->cls = jc; |
| 191 | return o; |
| 192 | } |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 193 | |
| 194 | // jobject |
| 195 | |
| 196 | STATIC void jobject_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 197 | mp_obj_jobject_t *self = self_in; |
Paul Sokolovsky | f22be4e | 2015-10-03 08:43:41 -0700 | [diff] [blame] | 198 | if (kind == PRINT_REPR) { |
| 199 | mp_printf(print, "<jobject @%p \"", self->obj); |
| 200 | } |
Paul Sokolovsky | 1ea4b77 | 2015-10-04 01:56:40 +0300 | [diff] [blame] | 201 | print_jobject(print, self->obj); |
Paul Sokolovsky | f22be4e | 2015-10-03 08:43:41 -0700 | [diff] [blame] | 202 | if (kind == PRINT_REPR) { |
| 203 | mp_printf(print, "\">"); |
| 204 | } |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 205 | } |
| 206 | |
| 207 | STATIC void jobject_attr(mp_obj_t self_in, qstr attr_in, mp_obj_t *dest) { |
| 208 | if (dest[0] == MP_OBJ_NULL) { |
| 209 | // load attribute |
| 210 | mp_obj_jobject_t *self = self_in; |
| 211 | |
Paul Sokolovsky | 216b6a4 | 2015-10-08 16:55:59 +0300 | [diff] [blame] | 212 | const char *attr = qstr_str(attr_in); |
| 213 | jclass obj_class = JJ(GetObjectClass, self->obj); |
| 214 | jstring field_name = JJ(NewStringUTF, attr); |
| 215 | jobject field = JJ(CallObjectMethod, obj_class, Class_getField_mid, field_name); |
| 216 | JJ(DeleteLocalRef, field_name); |
| 217 | JJ(DeleteLocalRef, obj_class); |
| 218 | if (!JJ1(ExceptionCheck)) { |
| 219 | jfieldID field_id = JJ(FromReflectedField, field); |
| 220 | JJ(DeleteLocalRef, field); |
| 221 | jobject obj = JJ(GetObjectField, self->obj, field_id); |
| 222 | dest[0] = new_jobject(obj); |
| 223 | return; |
| 224 | } |
| 225 | //JJ1(ExceptionDescribe); |
| 226 | JJ1(ExceptionClear); |
| 227 | |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 228 | mp_obj_jmethod_t *o = m_new_obj(mp_obj_jmethod_t); |
| 229 | o->base.type = &jmethod_type; |
| 230 | o->name = attr_in; |
| 231 | o->meth = NULL; |
| 232 | o->obj = self->obj; |
Paul Sokolovsky | 7a4b10c | 2015-09-14 00:12:27 +0300 | [diff] [blame] | 233 | o->is_static = false; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 234 | dest[0] = o; |
| 235 | } |
| 236 | } |
| 237 | |
Paul Sokolovsky | 3c7e1b8 | 2015-11-11 16:43:27 +0200 | [diff] [blame] | 238 | STATIC void get_jclass_name(jobject obj, char *buf) { |
| 239 | jclass obj_class = JJ(GetObjectClass, obj); |
| 240 | jstring name = JJ(CallObjectMethod, obj_class, Class_getName_mid); |
| 241 | jint len = JJ(GetStringLength, name); |
| 242 | JJ(GetStringUTFRegion, name, 0, len, buf); |
| 243 | check_exception(); |
| 244 | } |
| 245 | |
Paul Sokolovsky | b2d880d | 2015-09-21 12:02:22 -0700 | [diff] [blame] | 246 | STATIC mp_obj_t jobject_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { |
| 247 | mp_obj_jobject_t *self = self_in; |
Paul Sokolovsky | 3fea1f0 | 2016-09-16 00:59:48 +0300 | [diff] [blame] | 248 | mp_uint_t idx = mp_obj_get_int(index); |
| 249 | char class_name[64]; |
| 250 | get_jclass_name(self->obj, class_name); |
| 251 | //printf("class: %s\n", class_name); |
| 252 | |
| 253 | if (class_name[0] == '[') { |
| 254 | if (class_name[1] == 'L' || class_name[1] == '[') { |
| 255 | if (value == MP_OBJ_NULL) { |
| 256 | // delete |
| 257 | assert(0); |
| 258 | } else if (value == MP_OBJ_SENTINEL) { |
| 259 | // load |
| 260 | jobject el = JJ(GetObjectArrayElement, self->obj, idx); |
| 261 | return new_jobject(el); |
| 262 | } else { |
| 263 | // store |
| 264 | jvalue jval; |
| 265 | const char *t = class_name + 1; |
| 266 | py2jvalue(&t, value, &jval); |
| 267 | JJ(SetObjectArrayElement, self->obj, idx, jval.l); |
| 268 | return mp_const_none; |
| 269 | } |
| 270 | } |
Javier Candeira | 35a1fea | 2017-08-09 14:40:45 +1000 | [diff] [blame] | 271 | mp_raise_NotImplementedError(""); |
Paul Sokolovsky | 3fea1f0 | 2016-09-16 00:59:48 +0300 | [diff] [blame] | 272 | } |
| 273 | |
Paul Sokolovsky | b2d880d | 2015-09-21 12:02:22 -0700 | [diff] [blame] | 274 | if (!JJ(IsInstanceOf, self->obj, List_class)) { |
| 275 | return MP_OBJ_NULL; |
| 276 | } |
| 277 | |
Paul Sokolovsky | b2d880d | 2015-09-21 12:02:22 -0700 | [diff] [blame] | 278 | |
| 279 | if (value == MP_OBJ_NULL) { |
| 280 | // delete |
| 281 | assert(0); |
| 282 | } else if (value == MP_OBJ_SENTINEL) { |
| 283 | // load |
| 284 | jobject el = JJ(CallObjectMethod, self->obj, List_get_mid, idx); |
Paul Sokolovsky | fd38799 | 2015-10-07 07:39:41 +0300 | [diff] [blame] | 285 | check_exception(); |
Paul Sokolovsky | b2d880d | 2015-09-21 12:02:22 -0700 | [diff] [blame] | 286 | return new_jobject(el); |
| 287 | } else { |
| 288 | // store |
| 289 | assert(0); |
| 290 | } |
| 291 | |
| 292 | |
| 293 | return MP_OBJ_NULL; |
| 294 | } |
| 295 | |
Paul Sokolovsky | f3ca862 | 2015-09-29 10:05:30 -0700 | [diff] [blame] | 296 | STATIC mp_obj_t jobject_unary_op(mp_uint_t op, mp_obj_t self_in) { |
| 297 | mp_obj_jobject_t *self = self_in; |
| 298 | switch (op) { |
| 299 | case MP_UNARY_OP_BOOL: |
| 300 | case MP_UNARY_OP_LEN: { |
| 301 | jint len = JJ(CallIntMethod, self->obj, List_size_mid); |
| 302 | if (op == MP_UNARY_OP_BOOL) { |
Paul Sokolovsky | 1b586f3 | 2015-10-11 12:09:43 +0300 | [diff] [blame] | 303 | return mp_obj_new_bool(len != 0); |
Paul Sokolovsky | f3ca862 | 2015-09-29 10:05:30 -0700 | [diff] [blame] | 304 | } |
| 305 | return MP_OBJ_NEW_SMALL_INT(len); |
| 306 | } |
| 307 | default: |
| 308 | return MP_OBJ_NULL; // op not supported |
| 309 | } |
| 310 | } |
| 311 | |
Paul Sokolovsky | fe29cc1 | 2015-10-14 00:35:28 +0300 | [diff] [blame] | 312 | // TODO: subscr_load_adaptor & subscr_getiter convenience functions |
| 313 | // should be moved to common location for reuse. |
| 314 | STATIC mp_obj_t subscr_load_adaptor(mp_obj_t self_in, mp_obj_t index_in) { |
| 315 | return mp_obj_subscr(self_in, index_in, MP_OBJ_SENTINEL); |
| 316 | } |
| 317 | MP_DEFINE_CONST_FUN_OBJ_2(subscr_load_adaptor_obj, subscr_load_adaptor); |
| 318 | |
| 319 | // .getiter special method which returns iterator which works in terms |
| 320 | // of object subscription. |
| 321 | STATIC mp_obj_t subscr_getiter(mp_obj_t self_in) { |
| 322 | mp_obj_t dest[2] = {(mp_obj_t)&subscr_load_adaptor_obj, self_in}; |
| 323 | return mp_obj_new_getitem_iter(dest); |
| 324 | } |
| 325 | |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 326 | STATIC const mp_obj_type_t jobject_type = { |
| 327 | { &mp_type_type }, |
| 328 | .name = MP_QSTR_jobject, |
| 329 | .print = jobject_print, |
Paul Sokolovsky | f3ca862 | 2015-09-29 10:05:30 -0700 | [diff] [blame] | 330 | .unary_op = jobject_unary_op, |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 331 | .attr = jobject_attr, |
Paul Sokolovsky | b2d880d | 2015-09-21 12:02:22 -0700 | [diff] [blame] | 332 | .subscr = jobject_subscr, |
Paul Sokolovsky | fe29cc1 | 2015-10-14 00:35:28 +0300 | [diff] [blame] | 333 | .getiter = subscr_getiter, |
Paul Sokolovsky | e280122 | 2017-07-30 10:03:14 +0300 | [diff] [blame] | 334 | // .locals_dict = (mp_obj_dict_t*)&jobject_locals_dict, |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 335 | }; |
| 336 | |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 337 | STATIC mp_obj_t new_jobject(jobject jo) { |
Paul Sokolovsky | 7e18d3b | 2015-09-24 15:29:22 -0700 | [diff] [blame] | 338 | if (jo == NULL) { |
| 339 | return mp_const_none; |
| 340 | } else if (JJ(IsInstanceOf, jo, String_class)) { |
Paul Sokolovsky | ed22e9b | 2015-09-22 17:01:01 -0700 | [diff] [blame] | 341 | const char *s = JJ(GetStringUTFChars, jo, NULL); |
| 342 | mp_obj_t ret = mp_obj_new_str(s, strlen(s), false); |
| 343 | JJ(ReleaseStringUTFChars, jo, s); |
| 344 | return ret; |
| 345 | } else if (JJ(IsInstanceOf, jo, Class_class)) { |
| 346 | return new_jclass(jo); |
| 347 | } else { |
| 348 | mp_obj_jobject_t *o = m_new_obj(mp_obj_jobject_t); |
| 349 | o->base.type = &jobject_type; |
| 350 | o->obj = jo; |
| 351 | return o; |
| 352 | } |
| 353 | |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 354 | } |
| 355 | |
| 356 | |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 357 | // jmethod |
| 358 | |
| 359 | STATIC void jmethod_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { |
| 360 | (void)kind; |
| 361 | mp_obj_jmethod_t *self = self_in; |
| 362 | // Variable value printed as cast to int |
| 363 | mp_printf(print, "<jmethod '%s'>", qstr_str(self->name)); |
| 364 | } |
| 365 | |
Paul Sokolovsky | 4e7bde8 | 2015-09-12 00:19:18 +0300 | [diff] [blame] | 366 | #define IMATCH(s, static) ((!strncmp(s, static, sizeof(static) - 1)) && (s += sizeof(static) - 1)) |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 367 | |
| 368 | #define CHECK_TYPE(java_type_name) \ |
Paul Sokolovsky | 4e7bde8 | 2015-09-12 00:19:18 +0300 | [diff] [blame] | 369 | if (strncmp(arg_type, java_type_name, sizeof(java_type_name) - 1) != 0) { \ |
| 370 | return false; \ |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 371 | } \ |
Paul Sokolovsky | 4e7bde8 | 2015-09-12 00:19:18 +0300 | [diff] [blame] | 372 | arg_type += sizeof(java_type_name) - 1; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 373 | |
| 374 | STATIC const char *strprev(const char *s, char c) { |
| 375 | while (*s != c) { |
| 376 | s--; |
| 377 | } |
| 378 | return s; |
| 379 | } |
| 380 | |
Paul Sokolovsky | 4e7bde8 | 2015-09-12 00:19:18 +0300 | [diff] [blame] | 381 | STATIC bool py2jvalue(const char **jtypesig, mp_obj_t arg, jvalue *out) { |
| 382 | const char *arg_type = *jtypesig; |
| 383 | mp_obj_type_t *type = mp_obj_get_type(arg); |
| 384 | |
| 385 | if (type == &mp_type_str) { |
| 386 | if (IMATCH(arg_type, "java.lang.String") || IMATCH(arg_type, "java.lang.Object")) { |
| 387 | out->l = JJ(NewStringUTF, mp_obj_str_get_str(arg)); |
| 388 | } else { |
| 389 | return false; |
| 390 | } |
| 391 | } else if (type == &mp_type_int) { |
Paul Sokolovsky | 011c7f5 | 2015-09-18 13:19:50 +0300 | [diff] [blame] | 392 | if (IMATCH(arg_type, "int") || IMATCH(arg_type, "long")) { |
| 393 | // TODO: Java long is 64-bit actually |
| 394 | out->j = mp_obj_get_int(arg); |
| 395 | } else { |
| 396 | return false; |
| 397 | } |
Paul Sokolovsky | 1e9d8e1 | 2015-09-19 01:04:41 +0300 | [diff] [blame] | 398 | } else if (type == &jobject_type) { |
Paul Sokolovsky | 9ebd4da | 2015-10-22 01:34:03 +0300 | [diff] [blame] | 399 | bool is_object = false; |
Paul Sokolovsky | 91f2168 | 2015-10-23 00:33:03 +0300 | [diff] [blame] | 400 | const char *expected_type = arg_type; |
Paul Sokolovsky | 9ebd4da | 2015-10-22 01:34:03 +0300 | [diff] [blame] | 401 | while (1) { |
| 402 | if (isalpha(*arg_type)) { |
| 403 | } else if (*arg_type == '.') { |
| 404 | is_object = true; |
| 405 | } else { |
| 406 | break; |
| 407 | } |
Paul Sokolovsky | 0eba162 | 2015-09-30 00:54:20 -0700 | [diff] [blame] | 408 | arg_type++; |
| 409 | } |
Paul Sokolovsky | 9ebd4da | 2015-10-22 01:34:03 +0300 | [diff] [blame] | 410 | if (!is_object) { |
| 411 | return false; |
| 412 | } |
Paul Sokolovsky | 1e9d8e1 | 2015-09-19 01:04:41 +0300 | [diff] [blame] | 413 | mp_obj_jobject_t *jo = arg; |
Paul Sokolovsky | 91f2168 | 2015-10-23 00:33:03 +0300 | [diff] [blame] | 414 | if (!MATCH(expected_type, "java.lang.Object")) { |
| 415 | char class_name[64]; |
| 416 | get_jclass_name(jo->obj, class_name); |
| 417 | //printf("Arg class: %s\n", class_name); |
| 418 | if (strcmp(class_name, expected_type) != 0) { |
| 419 | return false; |
| 420 | } |
| 421 | } |
Paul Sokolovsky | 1e9d8e1 | 2015-09-19 01:04:41 +0300 | [diff] [blame] | 422 | out->l = jo->obj; |
Paul Sokolovsky | 7381b7a | 2015-10-10 01:19:28 +0300 | [diff] [blame] | 423 | } else if (type == &mp_type_bool) { |
| 424 | if (IMATCH(arg_type, "boolean")) { |
| 425 | out->z = arg == mp_const_true; |
| 426 | } else { |
| 427 | return false; |
| 428 | } |
| 429 | } else if (arg == mp_const_none) { |
| 430 | //printf("TODO: Check java arg type!!\n"); |
| 431 | while (isalpha(*arg_type) || *arg_type == '.') { |
| 432 | arg_type++; |
| 433 | } |
| 434 | out->l = NULL; |
Paul Sokolovsky | 4e7bde8 | 2015-09-12 00:19:18 +0300 | [diff] [blame] | 435 | } else { |
Damien George | 48d867b | 2017-06-15 11:54:41 +1000 | [diff] [blame] | 436 | mp_raise_TypeError("arg type not supported"); |
Paul Sokolovsky | 4e7bde8 | 2015-09-12 00:19:18 +0300 | [diff] [blame] | 437 | } |
| 438 | |
| 439 | *jtypesig = arg_type; |
| 440 | return true; |
| 441 | } |
| 442 | |
Paul Sokolovsky | 02041bf | 2015-10-09 00:25:26 +0300 | [diff] [blame] | 443 | #if 0 |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 444 | // jvalue is known to be union of jobject and friends. And yet from C's |
| 445 | // perspective, it's aggregate object which may require passing via stack |
| 446 | // instead of registers. Work that around by passing jobject and typecasting |
| 447 | // it. |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 448 | STATIC mp_obj_t jvalue2py(const char *jtypesig, jobject arg) { |
Paul Sokolovsky | 5167332 | 2015-09-14 00:15:08 +0300 | [diff] [blame] | 449 | if (arg == NULL || MATCH(jtypesig, "void")) { |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 450 | return mp_const_none; |
Paul Sokolovsky | 6196aa4 | 2015-09-20 00:36:26 +0300 | [diff] [blame] | 451 | } else if (MATCH(jtypesig, "boolean")) { |
| 452 | return mp_obj_new_bool((bool)arg); |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 453 | } else if (MATCH(jtypesig, "int")) { |
| 454 | return mp_obj_new_int((mp_int_t)arg); |
Paul Sokolovsky | e632b1f | 2015-09-23 07:10:55 -0700 | [diff] [blame] | 455 | } else if (is_object_type(jtypesig)) { |
| 456 | // Non-primitive, object type |
| 457 | return new_jobject(arg); |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 458 | } |
| 459 | |
Paul Sokolovsky | e632b1f | 2015-09-23 07:10:55 -0700 | [diff] [blame] | 460 | printf("Unknown return type: %s\n", jtypesig); |
Paul Sokolovsky | b230a86 | 2015-09-15 14:07:12 +0300 | [diff] [blame] | 461 | |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 462 | return MP_OBJ_NULL; |
| 463 | } |
Paul Sokolovsky | 02041bf | 2015-10-09 00:25:26 +0300 | [diff] [blame] | 464 | #endif |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 465 | |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 466 | STATIC mp_obj_t call_method(jobject obj, const char *name, jarray methods, bool is_constr, mp_uint_t n_args, const mp_obj_t *args) { |
| 467 | jvalue jargs[n_args]; |
| 468 | // printf("methods=%p\n", methods); |
| 469 | jsize num_methods = JJ(GetArrayLength, methods); |
| 470 | for (int i = 0; i < num_methods; i++) { |
| 471 | jobject meth = JJ(GetObjectArrayElement, methods, i); |
Paul Sokolovsky | f22be4e | 2015-10-03 08:43:41 -0700 | [diff] [blame] | 472 | jobject name_o = JJ(CallObjectMethod, meth, Object_toString_mid); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 473 | const char *decl = JJ(GetStringUTFChars, name_o, NULL); |
| 474 | const char *arg_types = strchr(decl, '(') + 1; |
| 475 | //const char *arg_types_end = strchr(arg_types, ')'); |
| 476 | // printf("method[%d]=%p %s\n", i, meth, decl); |
| 477 | |
| 478 | const char *meth_name = NULL; |
| 479 | const char *ret_type = NULL; |
| 480 | if (!is_constr) { |
| 481 | meth_name = strprev(arg_types, '.') + 1; |
| 482 | ret_type = strprev(meth_name, ' ') - 1; |
| 483 | ret_type = strprev(ret_type, ' ') + 1; |
| 484 | |
| 485 | int name_len = strlen(name); |
| 486 | if (strncmp(name, meth_name, name_len/*arg_types - meth_name - 1*/) || meth_name[name_len] != '('/*(*/) { |
Paul Sokolovsky | 81d64ab | 2015-09-26 08:50:37 -0700 | [diff] [blame] | 487 | goto next_method; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 488 | } |
| 489 | } |
| 490 | // printf("method[%d]=%p %s\n", i, meth, decl); |
| 491 | // printf("!!!%s\n", arg_types); |
| 492 | // printf("name=%p meth_name=%s\n", name, meth_name); |
| 493 | |
| 494 | bool found = true; |
Paul Sokolovsky | 0eba162 | 2015-09-30 00:54:20 -0700 | [diff] [blame] | 495 | for (int i = 0; i < n_args && *arg_types != ')'; i++) { |
Paul Sokolovsky | 4e7bde8 | 2015-09-12 00:19:18 +0300 | [diff] [blame] | 496 | if (!py2jvalue(&arg_types, args[i], &jargs[i])) { |
| 497 | goto next_method; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 498 | } |
| 499 | |
| 500 | if (*arg_types == ',') { |
| 501 | arg_types++; |
| 502 | } |
| 503 | } |
| 504 | |
Paul Sokolovsky | 0eba162 | 2015-09-30 00:54:20 -0700 | [diff] [blame] | 505 | if (*arg_types != ')') { |
| 506 | goto next_method; |
| 507 | } |
| 508 | |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 509 | if (found) { |
| 510 | // printf("found!\n"); |
| 511 | jmethodID method_id = JJ(FromReflectedMethod, meth); |
| 512 | jobject res; |
Paul Sokolovsky | 0d28a3e | 2015-09-27 02:30:28 -0700 | [diff] [blame] | 513 | mp_obj_t ret; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 514 | if (is_constr) { |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 515 | JJ(ReleaseStringUTFChars, name_o, decl); |
Paul Sokolovsky | 0d28a3e | 2015-09-27 02:30:28 -0700 | [diff] [blame] | 516 | res = JJ(NewObjectA, obj, method_id, jargs); |
Paul Sokolovsky | 26a9b4d | 2015-09-13 01:25:04 +0300 | [diff] [blame] | 517 | return new_jobject(res); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 518 | } else { |
Paul Sokolovsky | c0a79cc | 2015-09-25 17:11:24 -0700 | [diff] [blame] | 519 | if (MATCH(ret_type, "void")) { |
| 520 | JJ(CallVoidMethodA, obj, method_id, jargs); |
Paul Sokolovsky | 41eb705 | 2015-10-14 00:24:36 +0300 | [diff] [blame] | 521 | check_exception(); |
Paul Sokolovsky | 0d28a3e | 2015-09-27 02:30:28 -0700 | [diff] [blame] | 522 | ret = mp_const_none; |
Paul Sokolovsky | c0a79cc | 2015-09-25 17:11:24 -0700 | [diff] [blame] | 523 | } else if (MATCH(ret_type, "int")) { |
| 524 | jint res = JJ(CallIntMethodA, obj, method_id, jargs); |
Paul Sokolovsky | 41eb705 | 2015-10-14 00:24:36 +0300 | [diff] [blame] | 525 | check_exception(); |
Paul Sokolovsky | 0d28a3e | 2015-09-27 02:30:28 -0700 | [diff] [blame] | 526 | ret = mp_obj_new_int(res); |
Paul Sokolovsky | c0a79cc | 2015-09-25 17:11:24 -0700 | [diff] [blame] | 527 | } else if (MATCH(ret_type, "boolean")) { |
| 528 | jboolean res = JJ(CallBooleanMethodA, obj, method_id, jargs); |
Paul Sokolovsky | 41eb705 | 2015-10-14 00:24:36 +0300 | [diff] [blame] | 529 | check_exception(); |
Paul Sokolovsky | 0d28a3e | 2015-09-27 02:30:28 -0700 | [diff] [blame] | 530 | ret = mp_obj_new_bool(res); |
Paul Sokolovsky | c0a79cc | 2015-09-25 17:11:24 -0700 | [diff] [blame] | 531 | } else if (is_object_type(ret_type)) { |
| 532 | res = JJ(CallObjectMethodA, obj, method_id, jargs); |
Paul Sokolovsky | 41eb705 | 2015-10-14 00:24:36 +0300 | [diff] [blame] | 533 | check_exception(); |
Paul Sokolovsky | 0d28a3e | 2015-09-27 02:30:28 -0700 | [diff] [blame] | 534 | ret = new_jobject(res); |
| 535 | } else { |
Paul Sokolovsky | c0a79cc | 2015-09-25 17:11:24 -0700 | [diff] [blame] | 536 | JJ(ReleaseStringUTFChars, name_o, decl); |
Damien George | 48d867b | 2017-06-15 11:54:41 +1000 | [diff] [blame] | 537 | mp_raise_TypeError("cannot handle return type"); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 538 | } |
Paul Sokolovsky | 0d28a3e | 2015-09-27 02:30:28 -0700 | [diff] [blame] | 539 | |
| 540 | JJ(ReleaseStringUTFChars, name_o, decl); |
Paul Sokolovsky | 7702028 | 2015-09-28 08:36:43 -0700 | [diff] [blame] | 541 | JJ(DeleteLocalRef, name_o); |
| 542 | JJ(DeleteLocalRef, meth); |
Paul Sokolovsky | 0d28a3e | 2015-09-27 02:30:28 -0700 | [diff] [blame] | 543 | return ret; |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 544 | } |
| 545 | } |
| 546 | |
Paul Sokolovsky | 4e7bde8 | 2015-09-12 00:19:18 +0300 | [diff] [blame] | 547 | next_method: |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 548 | JJ(ReleaseStringUTFChars, name_o, decl); |
Paul Sokolovsky | 7702028 | 2015-09-28 08:36:43 -0700 | [diff] [blame] | 549 | JJ(DeleteLocalRef, name_o); |
| 550 | JJ(DeleteLocalRef, meth); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 551 | } |
| 552 | |
Damien George | 48d867b | 2017-06-15 11:54:41 +1000 | [diff] [blame] | 553 | mp_raise_TypeError("method not found"); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 554 | } |
| 555 | |
| 556 | |
Paul Sokolovsky | eac22e2 | 2017-01-04 16:10:42 +0300 | [diff] [blame] | 557 | STATIC mp_obj_t jmethod_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 558 | if (n_kw != 0) { |
Damien George | 48d867b | 2017-06-15 11:54:41 +1000 | [diff] [blame] | 559 | mp_raise_TypeError("kwargs not supported"); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 560 | } |
| 561 | mp_obj_jmethod_t *self = self_in; |
| 562 | |
| 563 | const char *name = qstr_str(self->name); |
| 564 | // jstring meth_name = JJ(NewStringUTF, name); |
| 565 | |
Paul Sokolovsky | 7a4b10c | 2015-09-14 00:12:27 +0300 | [diff] [blame] | 566 | jclass obj_class = self->obj; |
| 567 | if (!self->is_static) { |
| 568 | obj_class = JJ(GetObjectClass, self->obj); |
| 569 | } |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 570 | jarray methods = JJ(CallObjectMethod, obj_class, Class_getMethods_mid); |
| 571 | |
| 572 | return call_method(self->obj, name, methods, false, n_args, args); |
| 573 | } |
| 574 | |
| 575 | STATIC const mp_obj_type_t jmethod_type = { |
| 576 | { &mp_type_type }, |
| 577 | .name = MP_QSTR_jmethod, |
| 578 | .print = jmethod_print, |
| 579 | .call = jmethod_call, |
| 580 | // .attr = jobject_attr, |
Paul Sokolovsky | e280122 | 2017-07-30 10:03:14 +0300 | [diff] [blame] | 581 | // .locals_dict = (mp_obj_dict_t*)&jobject_locals_dict, |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 582 | }; |
| 583 | |
| 584 | #ifdef __ANDROID__ |
| 585 | #define LIBJVM_SO "libdvm.so" |
| 586 | #else |
| 587 | #define LIBJVM_SO "libjvm.so" |
| 588 | #endif |
| 589 | |
| 590 | STATIC void create_jvm() { |
| 591 | JavaVMInitArgs args; |
| 592 | JavaVMOption options; |
| 593 | options.optionString = "-Djava.class.path=."; |
| 594 | args.version = JNI_VERSION_1_6; |
| 595 | args.nOptions = 1; |
| 596 | args.options = &options; |
| 597 | args.ignoreUnrecognized = 0; |
| 598 | |
| 599 | if (env) { |
| 600 | return; |
| 601 | } |
| 602 | |
| 603 | void *libjvm = dlopen(LIBJVM_SO, RTLD_NOW | RTLD_GLOBAL); |
| 604 | if (!libjvm) { |
Damien George | 48d867b | 2017-06-15 11:54:41 +1000 | [diff] [blame] | 605 | mp_raise_msg(&mp_type_OSError, "unable to load libjvm.so, use LD_LIBRARY_PATH"); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 606 | } |
| 607 | int (*_JNI_CreateJavaVM)(void*, void**, void*) = dlsym(libjvm, "JNI_CreateJavaVM"); |
| 608 | |
| 609 | int st = _JNI_CreateJavaVM(&jvm, (void**)&env, &args); |
| 610 | if (st < 0 || !env) { |
Damien George | 48d867b | 2017-06-15 11:54:41 +1000 | [diff] [blame] | 611 | mp_raise_msg(&mp_type_OSError, "unable to create JVM"); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 612 | } |
| 613 | |
Paul Sokolovsky | 1cb5de2 | 2015-09-17 13:31:16 +0300 | [diff] [blame] | 614 | Class_class = JJ(FindClass, "java/lang/Class"); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 615 | jclass method_class = JJ(FindClass, "java/lang/reflect/Method"); |
| 616 | String_class = JJ(FindClass, "java/lang/String"); |
| 617 | |
Paul Sokolovsky | f22be4e | 2015-10-03 08:43:41 -0700 | [diff] [blame] | 618 | jclass Object_class = JJ(FindClass, "java/lang/Object"); |
| 619 | Object_toString_mid = JJ(GetMethodID, Object_class, "toString", |
| 620 | "()Ljava/lang/String;"); |
| 621 | |
Paul Sokolovsky | 3c7e1b8 | 2015-11-11 16:43:27 +0200 | [diff] [blame] | 622 | Class_getName_mid = (*env)->GetMethodID(env, Class_class, "getName", |
| 623 | "()Ljava/lang/String;"); |
Paul Sokolovsky | 1cb5de2 | 2015-09-17 13:31:16 +0300 | [diff] [blame] | 624 | Class_getField_mid = (*env)->GetMethodID(env, Class_class, "getField", |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 625 | "(Ljava/lang/String;)Ljava/lang/reflect/Field;"); |
Paul Sokolovsky | 1cb5de2 | 2015-09-17 13:31:16 +0300 | [diff] [blame] | 626 | Class_getMethods_mid = (*env)->GetMethodID(env, Class_class, "getMethods", |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 627 | "()[Ljava/lang/reflect/Method;"); |
Paul Sokolovsky | 1cb5de2 | 2015-09-17 13:31:16 +0300 | [diff] [blame] | 628 | Class_getConstructors_mid = (*env)->GetMethodID(env, Class_class, "getConstructors", |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 629 | "()[Ljava/lang/reflect/Constructor;"); |
| 630 | Method_getName_mid = (*env)->GetMethodID(env, method_class, "getName", |
| 631 | "()Ljava/lang/String;"); |
Paul Sokolovsky | b2d880d | 2015-09-21 12:02:22 -0700 | [diff] [blame] | 632 | |
| 633 | List_class = JJ(FindClass, "java/util/List"); |
| 634 | List_get_mid = JJ(GetMethodID, List_class, "get", |
| 635 | "(I)Ljava/lang/Object;"); |
| 636 | List_set_mid = JJ(GetMethodID, List_class, "set", |
| 637 | "(ILjava/lang/Object;)Ljava/lang/Object;"); |
Paul Sokolovsky | f3ca862 | 2015-09-29 10:05:30 -0700 | [diff] [blame] | 638 | List_size_mid = JJ(GetMethodID, List_class, "size", |
| 639 | "()I"); |
Paul Sokolovsky | 9e0a3d4 | 2015-10-02 00:21:07 -0700 | [diff] [blame] | 640 | IndexException_class = JJ(FindClass, "java/lang/IndexOutOfBoundsException"); |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 641 | } |
| 642 | |
| 643 | STATIC mp_obj_t mod_jni_cls(mp_obj_t cls_name_in) { |
| 644 | const char *cls_name = mp_obj_str_get_str(cls_name_in); |
| 645 | if (!env) { |
| 646 | create_jvm(); |
| 647 | } |
| 648 | jclass cls = JJ(FindClass, cls_name); |
| 649 | |
| 650 | mp_obj_jclass_t *o = m_new_obj(mp_obj_jclass_t); |
| 651 | o->base.type = &jclass_type; |
| 652 | o->cls = cls; |
| 653 | return o; |
| 654 | } |
| 655 | MP_DEFINE_CONST_FUN_OBJ_1(mod_jni_cls_obj, mod_jni_cls); |
| 656 | |
Paul Sokolovsky | ee324c5 | 2016-09-17 16:14:02 +0300 | [diff] [blame] | 657 | STATIC mp_obj_t mod_jni_array(mp_obj_t type_in, mp_obj_t size_in) { |
Paul Sokolovsky | ee324c5 | 2016-09-17 16:14:02 +0300 | [diff] [blame] | 658 | if (!env) { |
| 659 | create_jvm(); |
| 660 | } |
Paul Sokolovsky | 5bf1b4e | 2016-09-18 13:37:40 +0300 | [diff] [blame] | 661 | mp_int_t size = mp_obj_get_int(size_in); |
Paul Sokolovsky | ee324c5 | 2016-09-17 16:14:02 +0300 | [diff] [blame] | 662 | jobject res = NULL; |
Paul Sokolovsky | 5bf1b4e | 2016-09-18 13:37:40 +0300 | [diff] [blame] | 663 | |
| 664 | if (MP_OBJ_IS_TYPE(type_in, &jclass_type)) { |
| 665 | |
| 666 | mp_obj_jclass_t *jcls = type_in; |
| 667 | res = JJ(NewObjectArray, size, jcls->cls, NULL); |
| 668 | |
| 669 | } else if (MP_OBJ_IS_STR(type_in)) { |
| 670 | const char *type = mp_obj_str_get_str(type_in); |
| 671 | switch (*type) { |
| 672 | case 'Z': |
| 673 | res = JJ(NewBooleanArray, size); |
| 674 | break; |
| 675 | case 'B': |
| 676 | res = JJ(NewByteArray, size); |
| 677 | break; |
| 678 | case 'C': |
| 679 | res = JJ(NewCharArray, size); |
| 680 | break; |
| 681 | case 'S': |
| 682 | res = JJ(NewShortArray, size); |
| 683 | break; |
| 684 | case 'I': |
| 685 | res = JJ(NewIntArray, size); |
| 686 | break; |
| 687 | case 'J': |
| 688 | res = JJ(NewLongArray, size); |
| 689 | break; |
| 690 | case 'F': |
| 691 | res = JJ(NewFloatArray, size); |
| 692 | break; |
| 693 | case 'D': |
| 694 | res = JJ(NewDoubleArray, size); |
| 695 | break; |
| 696 | } |
| 697 | |
Paul Sokolovsky | ee324c5 | 2016-09-17 16:14:02 +0300 | [diff] [blame] | 698 | } |
| 699 | |
| 700 | return new_jobject(res); |
| 701 | } |
| 702 | MP_DEFINE_CONST_FUN_OBJ_2(mod_jni_array_obj, mod_jni_array); |
| 703 | |
| 704 | |
Paul Sokolovsky | cb6cf5e | 2015-09-16 01:09:39 +0300 | [diff] [blame] | 705 | STATIC mp_obj_t mod_jni_env() { |
| 706 | return mp_obj_new_int((mp_int_t)env); |
| 707 | } |
| 708 | MP_DEFINE_CONST_FUN_OBJ_0(mod_jni_env_obj, mod_jni_env); |
| 709 | |
Paul Sokolovsky | e280122 | 2017-07-30 10:03:14 +0300 | [diff] [blame] | 710 | STATIC const mp_rom_map_elem_t mp_module_jni_globals_table[] = { |
| 711 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_jni) }, |
| 712 | { MP_ROM_QSTR(MP_QSTR_cls), MP_ROM_PTR(&mod_jni_cls_obj) }, |
| 713 | { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mod_jni_array_obj) }, |
| 714 | { MP_ROM_QSTR(MP_QSTR_env), MP_ROM_PTR(&mod_jni_env_obj) }, |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 715 | }; |
| 716 | |
| 717 | STATIC MP_DEFINE_CONST_DICT(mp_module_jni_globals, mp_module_jni_globals_table); |
| 718 | |
| 719 | const mp_obj_module_t mp_module_jni = { |
| 720 | .base = { &mp_type_module }, |
Paul Sokolovsky | e79c6b6 | 2015-09-11 17:57:47 +0300 | [diff] [blame] | 721 | .globals = (mp_obj_dict_t*)&mp_module_jni_globals, |
| 722 | }; |