2014-07-13 01:07:11 +04:00
|
|
|
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
'Use strict';
|
2014-07-13 01:07:11 +04:00
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
var Native = {};
|
2014-07-15 10:47:20 +04:00
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.invoke = function(caller, methodInfo, callback) {
|
2014-07-21 09:08:08 +04:00
|
|
|
if (!methodInfo.native) {
|
|
|
|
var key = methodInfo.classInfo.className + "." + methodInfo.name + "." + methodInfo.signature;
|
|
|
|
methodInfo.native = Native.fast[key];
|
2014-07-21 09:24:07 +04:00
|
|
|
if (!methodInfo.native)
|
|
|
|
return Native.slow[key](caller, callback);
|
2014-07-21 09:08:08 +04:00
|
|
|
}
|
|
|
|
|
2014-07-13 10:13:53 +04:00
|
|
|
function pushType(type, value) {
|
|
|
|
if (type === "long" || type === "double") {
|
|
|
|
caller.stack.push2(value);
|
|
|
|
return;
|
2014-07-13 01:07:11 +04:00
|
|
|
}
|
2014-07-13 10:13:53 +04:00
|
|
|
caller.stack.push(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
function popType(type) {
|
|
|
|
return (type === "long" || type === "double") ? caller.stack.pop2() : caller.stack.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
function popArgs(types) {
|
2014-07-13 11:12:33 +04:00
|
|
|
var argc = types.length;
|
|
|
|
if (!ACCESS_FLAGS.isStatic(methodInfo.access_flags))
|
|
|
|
++argc;
|
2014-07-15 10:47:20 +04:00
|
|
|
var args = Array(argc);
|
2014-07-13 11:12:33 +04:00
|
|
|
for (var i=types.length-1, j=args.length-1; i >= 0; --i, --j)
|
|
|
|
args[j] = popType(types[i].type);
|
|
|
|
if (j >= 0)
|
|
|
|
args[0] = caller.stack.pop();
|
2014-07-13 10:13:53 +04:00
|
|
|
return args;
|
|
|
|
}
|
|
|
|
|
2014-07-14 06:57:33 +04:00
|
|
|
var signature = Signature.parse(methodInfo.signature);
|
|
|
|
var args = popArgs(signature.IN);
|
2014-07-20 11:35:00 +04:00
|
|
|
var result = methodInfo.native.apply(caller, args);
|
2014-07-14 06:57:33 +04:00
|
|
|
if (signature.OUT.length)
|
2014-07-18 22:00:19 +04:00
|
|
|
pushType(signature.OUT[0].type, result);
|
2014-07-21 03:41:30 +04:00
|
|
|
return true;
|
2014-07-13 01:07:11 +04:00
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast = {};
|
2014-07-21 09:24:07 +04:00
|
|
|
Native.slow = {};
|
2014-07-21 08:32:47 +04:00
|
|
|
|
|
|
|
Native.fast["java/lang/System.arraycopy.(Ljava/lang/Object;ILjava/lang/Object;II)V"] = function(src, srcOffset, dst, dstOffset, length) {
|
2014-07-21 02:46:22 +04:00
|
|
|
var frame = this;
|
2014-07-13 11:15:00 +04:00
|
|
|
if (!src || !dst) {
|
2014-07-21 13:01:06 +04:00
|
|
|
throw this.newException("java/lang/NullPointerException", "Cannot copy to/from a null array.");
|
2014-07-13 11:15:00 +04:00
|
|
|
return;
|
|
|
|
}
|
2014-07-20 00:18:45 +04:00
|
|
|
var srcClass = src.class;
|
|
|
|
var dstClass = dst.class;
|
|
|
|
if (!srcClass.isArrayClass || !dstClass.isArrayClass) {
|
2014-07-21 13:01:06 +04:00
|
|
|
throw this.newException("java/lang/ArrayStoreException", "Can only copy to/from array types.");
|
2014-07-13 20:03:11 +04:00
|
|
|
return;
|
|
|
|
}
|
2014-07-20 00:18:45 +04:00
|
|
|
if (srcClass != dstClass && (!srcClass.elementClass || !dstClass.elementClass || !srcClass.elementClass.isAssignableTo(dstClass.elementClass))) {
|
2014-07-21 13:01:06 +04:00
|
|
|
throw this.newException("java/lang/ArrayStoreException", "Incompatible component types.");
|
2014-07-13 20:03:11 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (srcOffset < 0 || (srcOffset+length) > src.length || dstOffset < 0 || (dstOffset+length) > dst.length || length < 0) {
|
2014-07-21 13:01:06 +04:00
|
|
|
throw this.newException("java/lang/ArrayIndexOutOfBoundsException", "Invalid index.");
|
2014-07-13 20:03:11 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (dst !== src || dstOffset < srcOffset) {
|
|
|
|
for (var n = 0; n < length; ++n)
|
|
|
|
dst[dstOffset++] = src[srcOffset++];
|
|
|
|
} else {
|
|
|
|
dstOffset += length;
|
|
|
|
srcOffset += length;
|
|
|
|
for (var n = 0; n < length; ++n)
|
|
|
|
dst[--dstOffset] = src[--srcOffset];
|
2014-07-13 10:13:53 +04:00
|
|
|
}
|
|
|
|
}
|
2014-07-15 09:13:01 +04:00
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/System.getProperty0.(Ljava/lang/String;)Ljava/lang/String;"] = function(key) {
|
2014-07-18 09:00:32 +04:00
|
|
|
switch (util.fromJavaString(key)) {
|
2014-07-15 09:13:01 +04:00
|
|
|
case "microedition.encoding":
|
2014-07-21 12:50:36 +04:00
|
|
|
return this.newString("UTF-8");
|
2014-07-15 09:13:01 +04:00
|
|
|
}
|
2014-07-19 11:02:20 +04:00
|
|
|
console.log("UNKNOWN PROPERTY: " + util.fromJavaString(key));
|
|
|
|
return null;
|
2014-07-15 09:13:01 +04:00
|
|
|
}
|
2014-07-15 10:19:26 +04:00
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/System.currentTimeMillis.()J"] = function() {
|
2014-07-18 22:00:19 +04:00
|
|
|
return Long.fromNumber(Date.now());
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["com/sun/cldchi/jvm/JVM.unchecked_char_arraycopy.([CI[CII)V"] = function(src, srcOffset, dst, dstOffset, length) {
|
2014-07-15 10:19:26 +04:00
|
|
|
if (dst !== src || dstOffset < srcOffset) {
|
|
|
|
for (var n = 0; n < length; ++n)
|
|
|
|
dst[dstOffset++] = src[srcOffset++];
|
|
|
|
} else {
|
|
|
|
dstOffset += length;
|
|
|
|
srcOffset += length;
|
|
|
|
for (var n = 0; n < length; ++n)
|
|
|
|
dst[--dstOffset] = src[--srcOffset];
|
|
|
|
}
|
|
|
|
}
|
2014-07-15 10:37:33 +04:00
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Object.getClass.()Ljava/lang/Class;"] = function(obj) {
|
2014-07-18 10:02:28 +04:00
|
|
|
return obj.class.getClassObject();
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Class.getName.()Ljava/lang/String;"] = function(obj) {
|
2014-07-21 12:50:36 +04:00
|
|
|
var frame = this;
|
2014-07-18 10:02:28 +04:00
|
|
|
return util.cache(obj, "getName", function () {
|
2014-07-21 12:50:36 +04:00
|
|
|
return frame.newString(obj.vmClass.className.replace("/", ".", "g"));
|
2014-07-18 10:02:28 +04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Class.forName.(Ljava/lang/String;)Ljava/lang/Class;"] = function(name) {
|
2014-07-18 09:00:32 +04:00
|
|
|
var className = util.fromJavaString(name).replace(".", "/", "g");
|
2014-07-18 12:12:38 +04:00
|
|
|
var classInfo = (className[0] === "[") ? null : CLASSES.getClass(className);
|
2014-07-15 10:47:20 +04:00
|
|
|
if (!classInfo) {
|
2014-07-19 22:20:46 +04:00
|
|
|
throw new Native.VM.JavaException("java/lang/ClassNotFoundException", "'" + className + "' not found.");
|
2014-07-15 10:47:20 +04:00
|
|
|
}
|
2014-07-18 10:02:28 +04:00
|
|
|
return classInfo.getClassObject();
|
2014-07-15 10:47:20 +04:00
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Class.newInstance.()Ljava/lang/Object;"] = function(classObject) {
|
2014-07-17 12:37:35 +04:00
|
|
|
var classInfo = classObject.vmClass;
|
2014-07-21 13:04:14 +04:00
|
|
|
this.initClass(classInfo);
|
2014-07-21 12:50:36 +04:00
|
|
|
var obj = CLASSES.newObject(classInfo);
|
|
|
|
this.invokeConstructor(obj);
|
2014-07-19 08:56:30 +04:00
|
|
|
return obj;
|
2014-07-15 10:52:27 +04:00
|
|
|
};
|
2014-07-15 11:01:11 +04:00
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Class.isInterface.()Z"] = function(classObject) {
|
2014-07-19 04:55:09 +04:00
|
|
|
var classInfo = classObject.vmClass;
|
|
|
|
return ACCESS_FLAGS.isInterface(classInfo.access_flags) ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Class.isArray.()Z"] = function(classObject) {
|
2014-07-19 04:55:09 +04:00
|
|
|
var classInfo = classObject.vmClass;
|
|
|
|
return classInfo.isArrayClass ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Class.isAssignableFrom.(Ljava/lang/Class;)Z"] = function(classObject, fromClass) {
|
2014-07-19 04:55:09 +04:00
|
|
|
if (!fromClass) {
|
2014-07-21 13:01:06 +04:00
|
|
|
throw this.newException("java/lang/NullPointerException");
|
2014-07-19 04:55:09 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
return fromClass.vmClass.isAssignableTo(classObject.vmClass) ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Class.isInstance.(Ljava/lang/Object;)Z"] = function(classObject, obj) {
|
2014-07-19 04:55:09 +04:00
|
|
|
return obj && obj.class.isAssignableTo(classObject.vmClass) ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Float.floatToIntBits.(F)I"] = (function() {
|
2014-07-19 01:44:50 +04:00
|
|
|
var fa = Float32Array(1);
|
|
|
|
var ia = Int32Array(fa.buffer);
|
|
|
|
return function(f) {
|
|
|
|
fa[0] = f;
|
|
|
|
return ia[0];
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Double.doubleToLongBits.(D)J"] = (function() {
|
2014-07-19 01:44:50 +04:00
|
|
|
var da = Float64Array(1);
|
|
|
|
var ia = Int32Array(da.buffer);
|
|
|
|
return function(d) {
|
|
|
|
da[0] = d;
|
|
|
|
return Long.fromBits(ia[0], ia[1]);
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Float.intBitsToFloat.(I)F"] = (function() {
|
2014-07-19 05:09:55 +04:00
|
|
|
var fa = Float32Array(1);
|
|
|
|
var ia = Int32Array(fa.buffer);
|
|
|
|
return function(i) {
|
|
|
|
ia[0] = i;
|
|
|
|
return fa[0];
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Double.longBitsToDouble.(J)D"] = (function() {
|
2014-07-19 05:09:55 +04:00
|
|
|
var da = Float64Array(1);
|
|
|
|
var ia = Int32Array(da.buffer);
|
|
|
|
return function(l) {
|
2014-07-19 05:33:12 +04:00
|
|
|
ia[0] = l.low_;
|
|
|
|
ia[1] = l.high_;
|
2014-07-19 05:09:55 +04:00
|
|
|
return da[0];
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Throwable.fillInStackTrace.()V"] = (function() {
|
2014-07-18 10:02:28 +04:00
|
|
|
});
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Throwable.obtainBackTrace.()Ljava/lang/Object;"] = (function() {
|
2014-07-19 04:55:09 +04:00
|
|
|
return null;
|
|
|
|
});
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Runtime.freeMemory.()J"] = function() {
|
2014-07-19 20:23:14 +04:00
|
|
|
return Long.fromInt(0x800000);
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Runtime.totalMemory.()J"] = function() {
|
2014-07-19 20:23:14 +04:00
|
|
|
return Long.fromInt(0x1000000);
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Runtime.gc.()V"] = function() {
|
2014-07-19 20:23:14 +04:00
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Math.floor.(D)D"] = function(d) {
|
2014-07-19 22:53:27 +04:00
|
|
|
return Math.floor(d);
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Thread.currentThread.()Ljava/lang/Thread;"] = function() {
|
2014-07-20 11:35:00 +04:00
|
|
|
return this.getThread();
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Thread.setPriority0.(II)V"] = function(thread, oldPriority, newPriority) {
|
2014-07-20 11:35:00 +04:00
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["java/lang/Thread.start0.()V"] = function(thread) {
|
2014-07-21 03:28:26 +04:00
|
|
|
// The main thread starts during bootstrap and don't allow calling start()
|
|
|
|
// on already running threads.
|
2014-07-21 03:27:24 +04:00
|
|
|
if (thread === CLASSES.mainThread || thread.running)
|
2014-07-21 13:01:06 +04:00
|
|
|
throw this.newException("java/lang/IllegalThreadStateException");
|
2014-07-21 03:28:26 +04:00
|
|
|
thread.running = true;
|
2014-07-21 03:27:24 +04:00
|
|
|
var run = CLASSES.getMethod(thread.class, "run", "()V", false, true);
|
2014-07-21 11:30:37 +04:00
|
|
|
window.setZeroTimeout(VM.invoke.bind(VM, thread, run, [thread]));
|
2014-07-20 11:35:00 +04:00
|
|
|
}
|
|
|
|
|
2014-07-21 09:24:07 +04:00
|
|
|
Native.slow["java/lang/Thread.sleep.(J)V"] = function(caller, callback) {
|
|
|
|
var thread = caller.getThread();
|
|
|
|
var delay = caller.stack.pop2().toNumber();
|
|
|
|
if (thread.level > 1) {
|
|
|
|
console.log("WARNING: nested invocation, can't reschedule.");
|
|
|
|
return true;
|
|
|
|
}
|
2014-07-21 11:30:37 +04:00
|
|
|
window.setTimeout(VM.resume.bind(VM, caller, callback), delay);
|
2014-07-21 09:24:07 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["com/sun/cldchi/io/ConsoleOutputStream.write.(I)V"] = (function() {
|
2014-07-15 11:01:11 +04:00
|
|
|
var s = "";
|
2014-07-18 10:02:28 +04:00
|
|
|
return function(obj, ch) {
|
2014-07-15 11:01:11 +04:00
|
|
|
if (ch === 10) {
|
2014-07-17 12:41:50 +04:00
|
|
|
document.getElementById("output").textContent += s + "\n";
|
2014-07-15 11:01:11 +04:00
|
|
|
s = "";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s += String.fromCharCode(ch);
|
|
|
|
}
|
|
|
|
})();
|
2014-07-19 04:55:09 +04:00
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["com/sun/cldc/io/ResourceInputStream.open.(Ljava/lang/String;)Ljava/lang/Object;"] = function(name) {
|
2014-07-19 04:55:09 +04:00
|
|
|
var fileName = util.fromJavaString(name);
|
|
|
|
var data = CLASSES.loadFile(fileName);
|
|
|
|
if (!data)
|
|
|
|
return null;
|
2014-07-21 04:10:12 +04:00
|
|
|
var obj = CLASSES.newObject(CLASSES.java_lang_Object);
|
2014-07-19 04:55:09 +04:00
|
|
|
obj.data = Uint8Array(data);
|
|
|
|
obj.pos = 0;
|
|
|
|
return obj;
|
|
|
|
};
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["com/sun/cldc/io/ResourceInputStream.bytesRemain.(Ljava/lang/Object;)I"] = function(handle) {
|
2014-07-19 04:55:09 +04:00
|
|
|
return handle.data.length - handle.pos;
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["com/sun/cldc/io/ResourceInputStream.readByte.(Ljava/lang/Object;)I"] = function(handle) {
|
2014-07-19 04:55:09 +04:00
|
|
|
return handle.data[handle.pos++];
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["com/sun/cldc/io/ResourceInputStream.readBytes.(Ljava/lang/Object;[BII)I"] = function(handle, b, off, len) {
|
2014-07-19 04:55:09 +04:00
|
|
|
var data = handle.data;
|
|
|
|
var remaining = data.length - handle.pos;
|
|
|
|
if (remaining > len)
|
|
|
|
len = remaining;
|
|
|
|
for (var n = 0; n < len; ++n)
|
|
|
|
b[off+n] = data[n];
|
|
|
|
handle.pos += len;
|
|
|
|
return len;
|
|
|
|
}
|
2014-07-19 05:23:49 +04:00
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["com/sun/cldc/i18n/uclc/DefaultCaseConverter.toLowerCase.(C)C"] = function(c) {
|
2014-07-19 22:53:27 +04:00
|
|
|
return String.fromCharCode(c).toLowerCase().charCodeAt(0);
|
|
|
|
}
|
|
|
|
|
2014-07-21 08:32:47 +04:00
|
|
|
Native.fast["com/sun/cldc/i18n/uclc/DefaultCaseConverter.toUpperCase.(C)C"] = function(c) {
|
2014-07-19 22:53:27 +04:00
|
|
|
return String.fromCharCode(c).toUpperCase().charCodeAt(0);
|
2014-07-19 05:23:49 +04:00
|
|
|
}
|