| mergeInto(LibraryManager.library, { |
| $EmJVM: { |
| debug: false, |
| |
| nextId: 0, |
| objects: {}, |
| classNames: {}, // class name => singleton object |
| |
| addObject: function(o) { |
| var ret = EmJVM.nextId++; |
| EmJVM.objects[ret] = o; |
| o.id = ret; |
| o.refs = 1; |
| o.nextMethodId = 0; |
| // XXX Module.print('add object ' + JSON.stringify(o).substr(0, 80) + (ret > 5285 ? new Error().stack : '')); |
| return ret; |
| }, |
| |
| addSingletonObject: function(o) { |
| EmJVM.classNames[o.name] = o; |
| return EmJVM.addObject(o); |
| }, |
| |
| createString: function(data) { |
| return EmJVM.addObject({ name: 'string', value: data }); |
| }, |
| |
| createByteArray: function(data) { |
| return EmJVM.addObject({ name: 'byteArray', value: data }); |
| }, |
| |
| // utils |
| |
| widecharToString: function(ptr, len) { |
| var nullTerminated = typeof(len) == "undefined"; |
| var ret = ""; |
| var i = 0; |
| var t; |
| while (1) { |
| t = getValue(ptr + 2 * i, 'i16'); |
| if (nullTerminated && t == 0) break; |
| if (t != 0) { |
| ret += String.fromCharCode(t); |
| } |
| ++i; |
| if (!nullTerminated && i == len) break; |
| }; |
| return ret; |
| }, |
| }, |
| |
| emjvm_newString__deps: ['$EmJVM'], |
| emjvm_newString: function(chars, len) { |
| return EmJVM.createString(EmJVM.widecharToString(chars, len)); |
| }, |
| |
| emjvm_getStringUTFChars: function(jniEnv, string, isCopy) { |
| var obj = EmJVM.objects[string]; |
| assert(obj.name == 'string'); |
| if (isCopy) setValue(isCopy, 'i8', 1); |
| var len = lengthBytesUTF8(obj.value) + 1; |
| var buffer = _malloc(len); |
| stringToUTF8(obj.value, buffer, len); |
| return buffer; |
| }, |
| |
| emjvm_getStringUTFLength: function(jniEnv, string) { |
| var obj = EmJVM.objects[string]; |
| if (obj.value) { |
| return obj.value.length; |
| } |
| return 0; |
| }, |
| |
| emjvm_releaseStringUTFChars: function(jniEnv, string, utf) { |
| }, |
| |
| emjvm_getObjectClass__deps: ['$EmJVM'], |
| emjvm_getObjectClass: function(env, jobject) { |
| if (EmJVM.debug) { |
| console.log('EMJVM_GetObjectClass+AddLocalRef: ' + [jobject]); |
| } |
| var obj = EmJVM.objects[jobject]; |
| obj.refs++; |
| return jobject; |
| }, |
| |
| emjvm_getMethodID: function(jclass, name, sig) { |
| if (EmJVM.debug) { |
| console.log('EMJVM_GetMethodID: ' + [jclass, UTF8ToString(name), UTF8ToString(sig)]); |
| console.log('EMJVM_GetMethodID: ' + [EmJVM.objects[jclass].name]); |
| } |
| // assumes class <--> object, just called on singletons |
| name = UTF8ToString(name); |
| var obj = EmJVM.objects[jclass]; |
| if (!obj[name]) { |
| throw 'missing implementation for ' + obj.name + '::' + name + ' : ' + new Error().stack; |
| } |
| if (!obj[name + '__methodId']) { |
| var methodId = obj.nextMethodId++; |
| obj[name + '__methodId'] = methodId; |
| obj['method__' + methodId] = obj[name]; |
| obj['methodName__' + methodId] = name; |
| } |
| return obj[name + '__methodId']; |
| }, |
| |
| emjvm_getStaticMethodID: function(jniEnv, jclass, name, sig) { |
| // Pretend this to be the same as looking up a non-static method |
| return _emjvm_getMethodID(jclass, name, sig); |
| }, |
| |
| emjvm_callObjectMethod: function(jniEnv, jobject, methodId, varargs) { |
| if (EmJVM.debug) { |
| console.log('EMJVM_CallObjectMethod: ' + [jobject, EmJVM.objects[jobject].name, methodId, EmJVM.objects[jobject]['methodName__' + methodId]]); |
| } |
| return EmJVM.objects[jobject]['method__' + methodId](varargs); |
| }, |
| |
| emjvm_callStaticObjectMethod: function(jniEnv, jclass, methodId, varargs) { |
| // Pretend this to be the same as calling a non-static method |
| return _emjvm_callObjectMethod(jniEnv, jclass, methodId, varargs); |
| }, |
| |
| emjvm_callStaticBooleanMethod: function(jniEnv, jclass, methodId, varargs) { |
| // Only differs in return type |
| return _emjvm_callStaticObjectMethod(jniEnv, jclass, methodId, varargs); |
| }, |
| |
| emjvm_callBooleanMethod: function(jniEnv, jobject, methodId, varargs) { |
| // Pretend this to be the same as calling a non-static method |
| return _emjvm_callStaticBooleanMethod(jniEnv, jobject, methodId, varargs); |
| }, |
| |
| emjvm_callVoidMethod: function(jniEnv, jobject, methodId, varargs) { |
| _emjvm_callObjectMethod(jniEnv, jobject, methodId, varargs); |
| }, |
| |
| emjvm_callIntMethod: function(jniEnv, jobject, methodId, varargs) { |
| return _emjvm_callObjectMethod(jniEnv, jobject, methodId, varargs); |
| }, |
| |
| emjvm_deleteLocalRef: function(jniEnv, jobject) { |
| if (EmJVM.debug) { |
| console.log('EMJVM_DeleteLocalRef: ' + [jobject]); |
| } |
| var obj = EmJVM.objects[jobject]; |
| obj.refs--; |
| if (obj.refs == 0) { |
| if (EmJVM.debug) { |
| console.log('EMJVM_DeleteLocalRef: remove ' + obj.name); |
| } |
| delete EmJVM.objects[jobject]; |
| } |
| }, |
| |
| emjvm_getArrayLength: function(jniEnv, jobject) { |
| var obj = EmJVM.objects[jobject]; |
| assert(obj.name == 'byteArray'); |
| return obj.value.length; |
| }, |
| |
| emjvm_getByteArrayRegion: function(jniEnv, jobject, start, len, buf) { |
| var obj = EmJVM.objects[jobject]; |
| assert(obj.name == 'byteArray'); |
| assert(obj.value); // we set this to null below and assume we are never called again |
| if (EmJVM.debug) { |
| console.log('emjvm_getByteArrayRegion: ' + [jobject, obj.value.length, start, len, buf]); |
| } |
| assert(start + len <= obj.value.length); |
| assert(len == obj.value.length); // we assume users read it all, and we can now copy it all with set() and then free it |
| HEAPU8.set(obj.value, buf); |
| obj.value = null; // XXX assume byte arrays are one-shot |
| }, |
| |
| emjvm_findClass: function(env, name) { |
| name = UTF8ToString(name); |
| if (EmJVM.debug) { |
| console.log('emjvm_findClass: ' + [name]); |
| } |
| var obj = EmJVM.classNames[name]; |
| assert(obj); |
| return obj.id; |
| }, |
| }); |
| |