Update some natives to the new mangling scheme.

This commit is contained in:
Michael Bebenita 2014-11-25 17:46:41 -08:00
Родитель ec70b204a3
Коммит d216ded20e
6 изменённых файлов: 94 добавлений и 56 удалений

Просмотреть файл

@ -263,16 +263,9 @@ module J2ME {
return this.superClass ? this.superClass.isAssignableTo(toClass) : false; return this.superClass ? this.superClass.isAssignableTo(toClass) : false;
} }
getClassObject(ctx: Context) { getClassObject(ctx: Context): java.lang.Class {
var className = this.className; // TODO: Check to make sure that it doesn't matter if this is done eagerly.
var classObjects = ctx.runtime.classObjects; return runtimeKlass(ctx.runtime, this.klass).classObject;
var classObject = classObjects[className];
if (!classObject) {
classObject = util.newObject(CLASSES.java_lang_Class);
classObject.vmClass = this;
classObjects[className] = classObject;
}
return classObject;
} }
getField(fieldKey: string) : FieldInfo { getField(fieldKey: string) : FieldInfo {

Просмотреть файл

@ -12,7 +12,7 @@ module J2ME {
frameSets: any []; frameSets: any [];
lockTimeout: number; lockTimeout: number;
lockLevel: number; lockLevel: number;
thread: any; thread: java.lang.Thread;
constructor(public runtime: Runtime) { constructor(public runtime: Runtime) {
this.frames = []; this.frames = [];
@ -248,7 +248,7 @@ module J2ME {
window.clearTimeout(this.lockTimeout); window.clearTimeout(this.lockTimeout);
this.lockTimeout = null; this.lockTimeout = null;
} }
if (obj.lock) { if (obj.__lock__) {
if (!obj.ready) if (!obj.ready)
obj.ready = []; obj.ready = [];
obj.ready.push(this); obj.ready.push(this);
@ -259,10 +259,10 @@ module J2ME {
} }
} }
monitorEnter(obj) { monitorEnter(obj: java.lang.Object) {
var lock = obj.lock; var lock = obj.__lock__;
if (!lock) { if (!lock) {
obj.lock = {thread: this.thread, level: 1}; obj.__lock__ = new Lock(this.thread, 1);
return; return;
} }
if (lock.thread === this.thread) { if (lock.thread === this.thread) {
@ -273,20 +273,20 @@ module J2ME {
} }
monitorExit(obj) { monitorExit(obj) {
var lock = obj.lock; var lock = obj.__lock__;
if (lock.thread !== this.thread) if (lock.thread !== this.thread)
this.raiseExceptionAndYield("java/lang/IllegalMonitorStateException"); this.raiseExceptionAndYield("java/lang/IllegalMonitorStateException");
if (--lock.level > 0) { if (--lock.level > 0) {
return; return;
} }
obj.lock = null; obj.__lock__ = null;
this.unblock(obj, "ready", false, function (ctx) { this.unblock(obj, "ready", false, function (ctx) {
ctx.wakeup(obj); ctx.wakeup(obj);
}); });
} }
wait(obj, timeout) { wait(obj, timeout) {
var lock = obj.lock; var lock = obj.__lock__;
if (timeout < 0) if (timeout < 0)
this.raiseExceptionAndYield("java/lang/IllegalArgumentException"); this.raiseExceptionAndYield("java/lang/IllegalArgumentException");
if (!lock || lock.thread !== this.thread) if (!lock || lock.thread !== this.thread)
@ -311,7 +311,7 @@ module J2ME {
} }
notify(obj, notifyAll) { notify(obj, notifyAll) {
if (!obj.lock || obj.lock.thread !== this.thread) if (!obj.__lock__ || obj.__lock__.thread !== this.thread)
this.raiseExceptionAndYield("java/lang/IllegalMonitorStateException"); this.raiseExceptionAndYield("java/lang/IllegalMonitorStateException");
this.unblock(obj, "waiting", notifyAll, function (ctx) { this.unblock(obj, "waiting", notifyAll, function (ctx) {
ctx.wakeup(obj); ctx.wakeup(obj);

Просмотреть файл

@ -607,7 +607,7 @@ module J2ME.C4.Backend {
var friendlyMangledNames = true; var friendlyMangledNames = true;
export function mangleString(s: string) { export function escapeString(s: string) {
var invalidChars = "[];/<>()"; var invalidChars = "[];/<>()";
var replaceChars = "abc_defg"; var replaceChars = "abc_defg";
var result = ""; var result = "";
@ -625,7 +625,7 @@ module J2ME.C4.Backend {
export function mangleClassAndMethod(methodInfo: MethodInfo) { export function mangleClassAndMethod(methodInfo: MethodInfo) {
var name = methodInfo.classInfo.className + methodInfo.name + methodInfo.signature; var name = methodInfo.classInfo.className + methodInfo.name + methodInfo.signature;
if (friendlyMangledNames) { if (friendlyMangledNames) {
return mangleString(name); return escapeString(name);
} }
var hash = hashString(name); var hash = hashString(name);
return StringUtilities.variableLengthEncodeInt32(hash); return StringUtilities.variableLengthEncodeInt32(hash);
@ -634,7 +634,7 @@ module J2ME.C4.Backend {
export function mangleMethod(methodInfo: MethodInfo) { export function mangleMethod(methodInfo: MethodInfo) {
var name = methodInfo.name + methodInfo.signature; var name = methodInfo.name + methodInfo.signature;
if (friendlyMangledNames) { if (friendlyMangledNames) {
return mangleString(name); return escapeString(name);
} }
var hash = hashString(name); var hash = hashString(name);
return StringUtilities.variableLengthEncodeInt32(hash); return StringUtilities.variableLengthEncodeInt32(hash);
@ -645,24 +645,15 @@ module J2ME.C4.Backend {
return "$AK(" + mangleClass(classInfo.elementClass) + ")"; return "$AK(" + mangleClass(classInfo.elementClass) + ")";
} else { } else {
if (friendlyMangledNames) { if (friendlyMangledNames) {
return mangleString(classInfo.className); return escapeString(classInfo.className);
} }
var hash = hashString(classInfo.className); var hash = hashString(classInfo.className);
return StringUtilities.variableLengthEncodeInt32(hash); return StringUtilities.variableLengthEncodeInt32(hash);
} }
} }
export function mangleClassAndField(fieldInfo: FieldInfo) {
var name = fieldInfo.classInfo.className + fieldInfo.name;
if (friendlyMangledNames) {
return mangleString(name);
}
var hash = hashString(name);
return StringUtilities.variableLengthEncodeInt32(hash);
}
export function mangleField(fieldInfo: FieldInfo) { export function mangleField(fieldInfo: FieldInfo) {
return mangleString(fieldInfo.name); return "$" + escapeString(fieldInfo.name);
} }
function getRuntimeClass(classInfo: ClassInfo) { function getRuntimeClass(classInfo: ClassInfo) {

Просмотреть файл

@ -229,7 +229,7 @@ Native.create("java/lang/Object.notifyAll.()V", function(ctx) {
}); });
Native.create("java/lang/Class.invoke_clinit.()V", function(ctx) { Native.create("java/lang/Class.invoke_clinit.()V", function(ctx) {
var classInfo = this.vmClass; var classInfo = this.runtimeKlass.classInfo;
var className = classInfo.className; var className = classInfo.className;
var runtime = ctx.runtime; var runtime = ctx.runtime;
if (runtime.initialized[className] || runtime.pending[className]) if (runtime.initialized[className] || runtime.pending[className])
@ -256,7 +256,7 @@ Native.create("java/lang/Class.invoke_clinit.()V", function(ctx) {
}); });
Native.create("java/lang/Class.init9.()V", function(ctx) { Native.create("java/lang/Class.init9.()V", function(ctx) {
var classInfo = this.vmClass; var classInfo = this.runtimeKlass.classInfo;
var className = classInfo.className; var className = classInfo.className;
var runtime = ctx.runtime; var runtime = ctx.runtime;
if (runtime.initialized[className]) if (runtime.initialized[className])
@ -266,7 +266,7 @@ Native.create("java/lang/Class.init9.()V", function(ctx) {
}); });
Native.create("java/lang/Class.getName.()Ljava/lang/String;", function() { Native.create("java/lang/Class.getName.()Ljava/lang/String;", function() {
return this.vmClass.className.replace(/\//g, "."); return this.runtimeKlass.classInfo.className.replace(/\//g, ".");
}); });
Native.create("java/lang/Class.forName.(Ljava/lang/String;)Ljava/lang/Class;", function(name, ctx) { Native.create("java/lang/Class.forName.(Ljava/lang/String;)Ljava/lang/Class;", function(name, ctx) {
@ -285,7 +285,7 @@ Native.create("java/lang/Class.forName.(Ljava/lang/String;)Ljava/lang/Class;", f
}); });
Native.create("java/lang/Class.newInstance.()Ljava/lang/Object;", function(ctx) { Native.create("java/lang/Class.newInstance.()Ljava/lang/Object;", function(ctx) {
var className = this.vmClass.className; var className = this.runtimeKlass.classInfo.className;
var syntheticMethod = new MethodInfo({ var syntheticMethod = new MethodInfo({
name: "ClassNewInstanceSynthetic", name: "ClassNewInstanceSynthetic",
signature: "()Ljava/lang/Object;", signature: "()Ljava/lang/Object;",
@ -315,21 +315,21 @@ Native.create("java/lang/Class.newInstance.()Ljava/lang/Object;", function(ctx)
}); });
Native.create("java/lang/Class.isInterface.()Z", function() { Native.create("java/lang/Class.isInterface.()Z", function() {
return ACCESS_FLAGS.isInterface(this.vmClass.access_flags); return ACCESS_FLAGS.isInterface(this.runtimeKlass.classInfo.access_flags);
}); });
Native.create("java/lang/Class.isArray.()Z", function() { Native.create("java/lang/Class.isArray.()Z", function() {
return !!this.vmClass.isArrayClass; return !!this.runtimeKlass.classInfo.isArrayClass;
}); });
Native.create("java/lang/Class.isAssignableFrom.(Ljava/lang/Class;)Z", function(fromClass) { Native.create("java/lang/Class.isAssignableFrom.(Ljava/lang/Class;)Z", function(fromClass) {
if (!fromClass) if (!fromClass)
throw new JavaException("java/lang/NullPointerException"); throw new JavaException("java/lang/NullPointerException");
return fromClass.vmClass.isAssignableTo(this.vmClass); return fromClass.runtimeKlass.classInfo.isAssignableTo(this.runtimeKlass.classInfo);
}); });
Native.create("java/lang/Class.isInstance.(Ljava/lang/Object;)Z", function(obj) { Native.create("java/lang/Class.isInstance.(Ljava/lang/Object;)Z", function(obj) {
return obj && obj.class.isAssignableTo(this.vmClass); return obj && obj.class.isAssignableTo(this.runtimeKlass.classInfo);
}); });
Native.create("java/lang/Float.floatToIntBits.(F)I", (function() { Native.create("java/lang/Float.floatToIntBits.(F)I", (function() {
@ -551,7 +551,7 @@ Native.create("com/sun/cldc/io/ResourceInputStream.open.(Ljava/lang/String;)Ljav
}); });
Override.create("com/sun/cldc/io/ResourceInputStream.available.()I", function() { Override.create("com/sun/cldc/io/ResourceInputStream.available.()I", function() {
var handle = this.class.getField("I.fileDecoder.Ljava/lang/Object;").get(this); var handle = this.$fileDecoder;
if (!handle) { if (!handle) {
throw new JavaException("java/io/IOException"); throw new JavaException("java/io/IOException");
@ -561,7 +561,7 @@ Override.create("com/sun/cldc/io/ResourceInputStream.available.()I", function()
}); });
Override.create("com/sun/cldc/io/ResourceInputStream.read.()I", function() { Override.create("com/sun/cldc/io/ResourceInputStream.read.()I", function() {
var handle = this.class.getField("I.fileDecoder.Ljava/lang/Object;").get(this); var handle = this.$fileDecoder;
if (!handle) { if (!handle) {
throw new JavaException("java/io/IOException"); throw new JavaException("java/io/IOException");
@ -674,8 +674,8 @@ Native.create("com/sun/midp/links/LinkPortal.getLinks0.([Lcom/sun/midp/links/Lin
var isolateId = ctx.runtime.isolate.id; var isolateId = ctx.runtime.isolate.id;
for (var i = 0; i < links[isolateId].length; i++) { for (var i = 0; i < links[isolateId].length; i++) {
var nativePointer = links[isolateId][i].class.getField("I.nativePointer.I").get(links[isolateId][i]); var nativePointer = links[isolateId][i].$nativePointer;
linkArray[i].class.getField("I.nativePointer.I").set(linkArray[i], nativePointer); linkArray[i].$nativePointer = nativePointer;
linkArray[i].sender = links[isolateId][i].sender; linkArray[i].sender = links[isolateId][i].sender;
linkArray[i].receiver = links[isolateId][i].receiver; linkArray[i].receiver = links[isolateId][i].receiver;
} }
@ -692,7 +692,7 @@ Native.create("com/sun/midp/links/LinkPortal.setLinks0.(I[Lcom/sun/midp/links/Li
Native.create("com/sun/midp/links/Link.init0.(II)V", function(sender, receiver) { Native.create("com/sun/midp/links/Link.init0.(II)V", function(sender, receiver) {
this.sender = sender; this.sender = sender;
this.receiver = receiver; this.receiver = receiver;
this.class.getField("I.nativePointer.I").set(this, util.id()); this.$nativePointer = util.id();
}); });
Native.create("com/sun/midp/links/Link.receive0.(Lcom/sun/midp/links/LinkMessage;Lcom/sun/midp/links/Link;)V", function(linkMessage, link) { Native.create("com/sun/midp/links/Link.receive0.(Lcom/sun/midp/links/LinkMessage;Lcom/sun/midp/links/Link;)V", function(linkMessage, link) {
@ -735,7 +735,7 @@ Native.create("java/io/DataInputStream.bytesToUTF.([B)Ljava/lang/String;", funct
Native.create("com/sun/cldc/i18n/j2me/UTF_8_Writer.encodeUTF8.([CII)[B", function(cbuf, off, len) { Native.create("com/sun/cldc/i18n/j2me/UTF_8_Writer.encodeUTF8.([CII)[B", function(cbuf, off, len) {
var outputArray = []; var outputArray = [];
var pendingSurrogate = this.class.getField("I.pendingSurrogate.I").get(this); var pendingSurrogate = this.$pendingSurrogate;
var inputChar = 0; var inputChar = 0;
var outputSize = 0; var outputSize = 0;
@ -792,7 +792,7 @@ Native.create("com/sun/cldc/i18n/j2me/UTF_8_Writer.encodeUTF8.([CII)[B", functio
count++; count++;
} }
this.class.getField("I.pendingSurrogate.I").set(this, pendingSurrogate); this.$pendingSurrogate = pendingSurrogate;
var totalSize = outputArray.reduce(function(total, cur) { var totalSize = outputArray.reduce(function(total, cur) {
return total + cur.length; return total + cur.length;
@ -812,7 +812,7 @@ Native.create("com/sun/cldc/i18n/j2me/UTF_8_Writer.sizeOf.([CII)I", function(cbu
var outputSize = 0; var outputSize = 0;
var outputCount = 0; var outputCount = 0;
var count = 0; var count = 0;
var localPendingSurrogate = this.class.getField("I.pendingSurrogate.I").get(this); var localPendingSurrogate = this.$pendingSurrogate;
while (count < length) { while (count < length) {
inputChar = 0xffff & cbuf[offset + count]; inputChar = 0xffff & cbuf[offset + count];
if (0 != localPendingSurrogate) { if (0 != localPendingSurrogate) {

Просмотреть файл

@ -151,7 +151,7 @@ module J2ME {
new (): java.lang.Object; new (): java.lang.Object;
/** /**
* Array klass of this klass constructed via \arrayKlass\. * Array klass of this klass, constructed via \arrayKlass\.
*/ */
arrayKlass: ArrayKlass; arrayKlass: ArrayKlass;
@ -186,12 +186,22 @@ module J2ME {
/** /**
* Java class object. This is only available on runtime klasses. * Java class object. This is only available on runtime klasses.
*/ */
class: java.lang.Class classObject: java.lang.Class;
/**
* Wether this class is a runtime class.
*/
isRuntimeKlass: boolean;
} }
export interface ArrayKlass extends Klass { export interface ArrayKlass extends Klass {
elementKlass: Klass; elementKlass: Klass;
}
export class Lock {
constructor(public thread: java.lang.Thread, public level: number) {
// ...
}
} }
export module java.lang { export module java.lang {
@ -206,6 +216,11 @@ module J2ME {
*/ */
__hashCode__: number; __hashCode__: number;
/**
* Some objects may have a lock.
*/
__lock__: Lock;
clone(): java.lang.Object; clone(): java.lang.Object;
equals(obj: java.lang.Object): boolean; equals(obj: java.lang.Object): boolean;
finalize(): void; finalize(): void;
@ -220,16 +235,27 @@ module J2ME {
} }
export interface Class extends java.lang.Object { export interface Class extends java.lang.Object {
runtimeKlass: Klass;
} }
export interface String extends java.lang.Object { export interface String extends java.lang.Object {
} }
export interface Thread extends java.lang.Object {
}
} }
declare var CLASSES; declare var CLASSES;
function initializeClassObject(klass: Klass) {
assert(klass.isRuntimeKlass, "Can only create class objects for runtime klasses.");
assert(!klass.classObject);
klass.classObject = <java.lang.Class>newObject(Klasses.java.lang.Class);
klass.classObject.runtimeKlass = klass;
}
/** /**
* Called by compiled code to initialize the klass. Klass initializers are reflected as * Called by compiled code to initialize the klass. Klass initializers are reflected as
* memoizing getters on the |RuntimeTemplate.prototype|. Once they are first accessed, * memoizing getters on the |RuntimeTemplate.prototype|. Once they are first accessed,
@ -241,9 +267,11 @@ module J2ME {
Object.defineProperty(RuntimeTemplate.prototype, mangledClassName, { Object.defineProperty(RuntimeTemplate.prototype, mangledClassName, {
configurable: true, configurable: true,
get: function () { get: function () {
assert(!klass.isRuntimeKlass);
var runtimeKlass = klass.bind(null); var runtimeKlass = klass.bind(null);
runtimeKlass.klass = klass; runtimeKlass.klass = klass;
runtimeKlass.class = new Class(runtimeKlass); runtimeKlass.isRuntimeKlass = true;
initializeClassObject(runtimeKlass);
var classInfo = CLASSES.getClass(className); var classInfo = CLASSES.getClass(className);
Object.defineProperty(this, mangledClassName, { Object.defineProperty(this, mangledClassName, {
configurable: false, configurable: false,
@ -261,6 +289,13 @@ module J2ME {
}); });
} }
export function runtimeKlass(runtime: Runtime, klass: Klass): Klass {
assert(!klass.isRuntimeKlass);
var runtimeKlass = runtime[klass.classInfo.mangledName];
assert(runtimeKlass.isRuntimeKlass);
return runtimeKlass;
}
export function createKlass(classInfo: ClassInfo): Klass { export function createKlass(classInfo: ClassInfo): Klass {
if (!classInfo) { if (!classInfo) {
return null; return null;
@ -390,11 +425,20 @@ module J2ME {
return arrayKlass; return arrayKlass;
} }
export function toDebugString(object: java.lang.Object): string { export function toDebugString(value: any): string {
if (!object) { if (typeof value !== "object") {
return String(value);
}
if (!value) {
return "null"; return "null";
} }
return "[" + object.klass.classInfo.className + " 0x" + object.__hashCode__.toString(16).toUpperCase() + "]"; if (!value.klass) {
return "no klass";
}
if (!value.klass.classInfo) {
return value.klass + " no classInfo"
}
return "[" + value.klass.classInfo.className + " 0x" + value.__hashCode__.toString(16).toUpperCase() + "]";
} }
} }

10
vm.js
Просмотреть файл

@ -18,6 +18,8 @@ VM.trace = function(type, pid, methodInfo, returnVal) {
(returnVal ? (" " + returnVal) : "") + "\n"; (returnVal ? (" " + returnVal) : "") + "\n";
} }
var traceWriter = new J2ME.IndentingWriter();
VM.execute = function(ctx) { VM.execute = function(ctx) {
var frame = ctx.current(); var frame = ctx.current();
@ -27,6 +29,13 @@ VM.execute = function(ctx) {
function pushFrame(methodInfo) { function pushFrame(methodInfo) {
var caller = frame; var caller = frame;
if (traceWriter) {
var args = stack.slice(stack.length - methodInfo.consumes).map(function (x) {
return J2ME.toDebugString(x);
}).join(", ")
traceWriter.enter(methodInfo.implKey + " " + args);
}
frame = ctx.pushFrame(methodInfo); frame = ctx.pushFrame(methodInfo);
stack = frame.stack; stack = frame.stack;
cp = frame.cp; cp = frame.cp;
@ -43,6 +52,7 @@ VM.execute = function(ctx) {
} }
function popFrame(consumes) { function popFrame(consumes) {
traceWriter && traceWriter.outdent();
if (frame.lockObject) if (frame.lockObject)
ctx.monitorExit(frame.lockObject); ctx.monitorExit(frame.lockObject);
var callee = frame; var callee = frame;