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-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)
|
2014-07-14 05:47:31 +04:00
|
|
|
methodInfo.native = this.getNativeMethod(methodInfo);
|
2014-07-18 05:42:11 +04:00
|
|
|
var result = methodInfo.native.apply(caller, args);
|
2014-07-14 06:57:33 +04:00
|
|
|
if (signature.OUT.length)
|
|
|
|
pushType(signature.OUT[0], result);
|
2014-07-13 01:07:11 +04:00
|
|
|
}
|
|
|
|
|
2014-07-14 05:47:31 +04:00
|
|
|
Native.prototype.getNativeMethod = function (methodInfo) {
|
2014-07-13 11:00:11 +04:00
|
|
|
var classInfo = methodInfo.classInfo;
|
2014-07-13 20:28:19 +04:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
|
|
|
Native.prototype["java/lang/System.arraycopy.(Ljava/lang/Object;ILjava/lang/Object;II)V"] = function (src, srcOffset, dst, dstOffset, length) {
|
2014-07-13 11:15:00 +04:00
|
|
|
if (!src || !dst) {
|
|
|
|
this.raiseException("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) {
|
|
|
|
this.raiseException("java/lang/ArrayStoreException", "Can only copy to/from array types.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (proto !== Object.getPrototypeOf(dst)) {
|
|
|
|
this.raiseException("java/lang/ArrayStoreException", "Incompatible component types.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (srcOffset < 0 || (srcOffset+length) > src.length || dstOffset < 0 || (dstOffset+length) > dst.length || length < 0) {
|
|
|
|
this.raiseException("java/lang/ArrayIndexOutOfBoundsException", "Invalid index.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (proto === Array.prototype) {
|
|
|
|
// TODO: check casting
|
|
|
|
this.raiseException("java/lang/ArrayStoreException", "Invalid element type.");
|
|
|
|
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
|
|
|
|
|
|
|
Native.prototype["java/lang/System.getProperty0.(Ljava/lang/String;)Ljava/lang/String;"] = function (key) {
|
|
|
|
switch (util.chars2string(key.value)) {
|
|
|
|
case "microedition.encoding":
|
2014-07-18 01:34:22 +04:00
|
|
|
return CLASSES.newString("ISO-8859-1");
|
2014-07-15 09:13:01 +04:00
|
|
|
default:
|
|
|
|
console.log("KEY: " + util.chars2string(key.value));
|
|
|
|
}
|
|
|
|
}
|
2014-07-15 10:19:26 +04:00
|
|
|
|
|
|
|
Native.prototype["com/sun/cldchi/jvm/JVM.unchecked_char_arraycopy.([CI[CII)V"] = function (src, srcOffset, dst, dstOffset, length) {
|
|
|
|
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
|
|
|
|
|
|
|
Native.prototype["java/lang/Class.forName.(Ljava/lang/String;)Ljava/lang/Class;"] = function (name) {
|
|
|
|
var className = util.chars2string(name.value, name.offset, name.count).replace(".", "/", "g");
|
2014-07-18 01:34:22 +04:00
|
|
|
var classInfo = 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 01:34:22 +04:00
|
|
|
var classObject = CLASSES.newObject("java/lang/Class");
|
2014-07-15 10:47:20 +04:00
|
|
|
classObject.vmClass = classInfo;
|
|
|
|
return classObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
Native.prototype["java/lang/Class.newInstance.()Ljava/lang/Object;"] = function (classObject) {
|
2014-07-17 12:37:35 +04:00
|
|
|
var classInfo = classObject.vmClass;
|
2014-07-18 01:34:22 +04:00
|
|
|
CLASSES.initClass(classInfo);
|
2014-07-17 12:37:35 +04:00
|
|
|
return new (classInfo.constructor)();
|
2014-07-15 10:52:27 +04:00
|
|
|
};
|
2014-07-15 11:01:11 +04:00
|
|
|
|
|
|
|
Native.prototype["com/sun/cldchi/io/ConsoleOutputStream.write.(I)V"] = (function () {
|
|
|
|
var s = "";
|
|
|
|
return function (obj, ch) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
})();
|