pluotsorbet/native.js

260 строки
8.7 KiB
JavaScript
Исходник Обычный вид История

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: */
'use strict';
2014-07-16 06:21:40 +04:00
var Native = function() {
2014-07-15 10:47:20 +04:00
}
2014-07-16 06:21:40 +04:00
Native.prototype.JavaException = function(className, msg) {
this.className = className;
this.msg = msg;
2014-07-13 01:07:11 +04:00
}
2014-07-18 10:02:28 +04:00
Native.prototype.JavaException.prototype.toString = function() {
2014-07-18 09:00:32 +04:00
return "Uncaught Java Exception " + this.className + " " + this.msg;
}
2014-07-13 11:00:11 +04:00
Native.prototype.invokeNative = function(caller, methodInfo) {
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-13 11:00:11 +04:00
if (!methodInfo.native)
methodInfo.native = this.getNativeMethod(methodInfo);
var result = methodInfo.native.apply(caller, args);
2014-07-14 06:57:33 +04:00
if (signature.OUT.length)
pushType(signature.OUT[0].type, result);
2014-07-13 01:07:11 +04:00
}
2014-07-18 10:02:28 +04:00
Native.prototype.getNativeMethod = function(methodInfo) {
2014-07-13 11:00:11 +04:00
var classInfo = methodInfo.classInfo;
var className = classInfo.className;
2014-07-13 21:37:28 +04:00
var methodName = methodInfo.name;
var signature = methodInfo.signature;
2014-07-13 10:13:53 +04:00
return this[className + "." + methodName + "." + signature];
}
2014-07-18 10:02:28 +04:00
Native.prototype["java/lang/System.arraycopy.(Ljava/lang/Object;ILjava/lang/Object;II)V"] = function(src, srcOffset, dst, dstOffset, length) {
if (!src || !dst) {
throw new JavaException("java/lang/NullPointerException", "Cannot copy to/from a null array.");
return;
}
2014-07-13 20:03:11 +04:00
var proto = Object.getPrototypeOf(src);
if (proto !== Int8Array.prototype && proto !== Int16Array.prototype && proto !== Int32Array.prototype &&
proto !== Uint16Array.prototype && proto !== Float32Array.prototype && proto !== Float64Array.prototype &&
proto !== Array.prototype) {
throw new JavaException("java/lang/ArrayStoreException", "Can only copy to/from array types.");
2014-07-13 20:03:11 +04:00
return;
}
if (proto !== Object.getPrototypeOf(dst)) {
throw new JavaException("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) {
throw new JavaException("java/lang/ArrayIndexOutOfBoundsException", "Invalid index.");
2014-07-13 20:03:11 +04:00
return;
}
if (proto === Array.prototype) {
// TODO: check casting
throw new JavaException("java/lang/ArrayStoreException", "Invalid element type.");
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-18 10:02:28 +04:00
Native.prototype["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":
return CLASSES.newString("ISO-8859-1");
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
Native.prototype["java/lang/System.currentTimeMillis.()J"] = function() {
return Long.fromNumber(Date.now());
}
2014-07-18 10:02:28 +04:00
Native.prototype["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-18 10:02:28 +04:00
Native.prototype["java/lang/Object.getClass.()Ljava/lang/Class;"] = function(obj) {
return obj.class.getClassObject();
}
Native.prototype["java/lang/Class.getName.()Ljava/lang/String;"] = function(obj) {
return util.cache(obj, "getName", function () {
2014-07-19 04:55:09 +04:00
return CLASSES.newString(obj.vmClass.className.replace("/", ".", "g"));
2014-07-18 10:02:28 +04:00
});
}
Native.prototype["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-16 06:21:40 +04:00
throw new Native.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-18 10:02:28 +04:00
Native.prototype["java/lang/Class.newInstance.()Ljava/lang/Object;"] = function(classObject) {
2014-07-17 12:37:35 +04:00
var classInfo = classObject.vmClass;
CLASSES.initClass(classInfo);
2014-07-19 08:56:30 +04:00
var obj = new (classInfo.constructor)();
var ctor = CLASSES.getMethod(classInfo, "<init>", "()V", false, false);
VM.invoke(ctor, [obj]);
return obj;
};
2014-07-19 04:55:09 +04:00
Native.prototype["java/lang/Class.isInterface.()Z"] = function(classObject) {
var classInfo = classObject.vmClass;
return ACCESS_FLAGS.isInterface(classInfo.access_flags) ? 1 : 0;
}
Native.prototype["java/lang/Class.isArray.()Z"] = function(classObject) {
var classInfo = classObject.vmClass;
return classInfo.isArrayClass ? 1 : 0;
}
Native.prototype["java/lang/Class.isAssignableFrom.(Ljava/lang/Class;)Z"] = function(classObject, fromClass) {
if (!fromClass) {
throw new JavaException("java/lang/NullPointerException");
return;
}
return fromClass.vmClass.isAssignableTo(classObject.vmClass) ? 1 : 0;
}
Native.prototype["java/lang/Class.isInstance.(Ljava/lang/Object;)Z"] = function(classObject, obj) {
return obj && obj.class.isAssignableTo(classObject.vmClass) ? 1 : 0;
}
2014-07-19 01:44:50 +04:00
Native.prototype["java/lang/Float.floatToIntBits.(F)I"] = (function() {
var fa = Float32Array(1);
var ia = Int32Array(fa.buffer);
return function(f) {
fa[0] = f;
return ia[0];
}
})();
Native.prototype["java/lang/Double.doubleToLongBits.(D)J"] = (function() {
var da = Float64Array(1);
var ia = Int32Array(da.buffer);
return function(d) {
da[0] = d;
return Long.fromBits(ia[0], ia[1]);
}
})();
Native.prototype["java/lang/Float.intBitsToFloat.(I)F"] = (function() {
var fa = Float32Array(1);
var ia = Int32Array(fa.buffer);
return function(i) {
ia[0] = i;
return fa[0];
}
})();
Native.prototype["java/lang/Double.longBitsToDouble.(J)D"] = (function() {
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_;
return da[0];
}
})();
2014-07-18 10:02:28 +04:00
Native.prototype["java/lang/Throwable.fillInStackTrace.()V"] = (function() {
});
2014-07-19 04:55:09 +04:00
Native.prototype["java/lang/Throwable.obtainBackTrace.()Ljava/lang/Object;"] = (function() {
return null;
});
2014-07-18 10:02:28 +04:00
Native.prototype["com/sun/cldchi/io/ConsoleOutputStream.write.(I)V"] = (function() {
var s = "";
2014-07-18 10:02:28 +04:00
return function(obj, ch) {
if (ch === 10) {
2014-07-17 12:41:50 +04:00
document.getElementById("output").textContent += s + "\n";
s = "";
return;
}
s += String.fromCharCode(ch);
}
})();
2014-07-19 04:55:09 +04:00
Native.prototype["com/sun/cldc/io/ResourceInputStream.open.(Ljava/lang/String;)Ljava/lang/Object;"] = function(name) {
var fileName = util.fromJavaString(name);
var data = CLASSES.loadFile(fileName);
if (!data)
return null;
var obj = CLASSES.newObject("java/lang/Object");
obj.data = Uint8Array(data);
obj.pos = 0;
return obj;
};
Native.prototype["com/sun/cldc/io/ResourceInputStream.bytesRemain.(Ljava/lang/Object;)I"] = function(handle) {
return handle.data.length - handle.pos;
}
Native.prototype["com/sun/cldc/io/ResourceInputStream.readByte.(Ljava/lang/Object;)I"] = function(handle) {
return handle.data[handle.pos++];
}
Native.prototype["com/sun/cldc/io/ResourceInputStream.readBytes.(Ljava/lang/Object;[BII)I"] = function(handle, b, off, len) {
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
Native.prototype["java/lang/Math.floor.(D)D"] = function(d) {
return Math.floor(d);
}