aboutsummaryrefslogtreecommitdiff
path: root/third_party/jni/emjvm.js
blob: 6a8da080fb0b4bf9511c2c58db176642e7f2a397 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
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 buffer = _malloc(obj.value.length+1);
    writeStringToMemory(obj.value, buffer);
    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, Pointer_stringify(name), Pointer_stringify(sig)]);
      console.log('EMJVM_GetMethodID: ' + [EmJVM.objects[jclass].name]);
    }
    // assumes class <--> object, just called on singletons
    name = Pointer_stringify(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 = Pointer_stringify(name);
    if (EmJVM.debug) {
      console.log('emjvm_findClass: ' + [name]);
    }
    var obj = EmJVM.classNames[name];
    assert(obj);
    return obj.id;
  },
});