зеркало из https://github.com/mozilla/pluotsorbet.git
Moved most of the top level code generation in the compiler file, and lots of other smaller things.
This commit is contained in:
Родитель
5e2712ca22
Коммит
a6eeab5c39
|
@ -11,6 +11,7 @@ var FieldInfo = (function() {
|
|||
this.name = name;
|
||||
this.signature = signature;
|
||||
this.id = idgen++;
|
||||
this.isStatic = ACCESS_FLAGS.isStatic(access_flags);
|
||||
}
|
||||
})();
|
||||
|
||||
|
|
|
@ -85,7 +85,6 @@ try {
|
|||
start = dateNow();
|
||||
var runtime = jvm.startIsolate0(scriptArgs[0], urlParams.args);
|
||||
|
||||
J2ME.printResults();
|
||||
print("RUNNING TIME: " + (dateNow() - start));
|
||||
} catch (x) {
|
||||
print(x);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module J2ME {
|
||||
|
||||
var debug = false;
|
||||
var writer = new IndentingWriter(!debug);
|
||||
var writer = null; // new IndentingWriter(true);
|
||||
var consoleWriter = new IndentingWriter();
|
||||
|
||||
export var counter = new J2ME.Metrics.Counter(true);
|
||||
|
@ -81,6 +81,7 @@ module J2ME {
|
|||
classInfo: ClassInfo;
|
||||
access_flags: any;
|
||||
id: number;
|
||||
isStatic: boolean;
|
||||
}
|
||||
|
||||
export enum TAGS {
|
||||
|
@ -153,6 +154,12 @@ module J2ME {
|
|||
|
||||
declare var Frame;
|
||||
|
||||
export class CompiledMethodInfo {
|
||||
constructor(public args: string [], public body: string, public referencedClasses: ClassInfo []) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
function assertKind(kind: Kind, x: Node): Node {
|
||||
assert(stackKind(x.kind) === stackKind(kind), "Got " + kindCharacter(stackKind(x.kind)) + " expected " + kindCharacter(stackKind(kind)));
|
||||
return x;
|
||||
|
@ -464,7 +471,7 @@ module J2ME {
|
|||
return "\"" + s + "\"";
|
||||
}
|
||||
|
||||
export function compileMethodInfo(methodInfo: MethodInfo, ctx: Context, target: CompilationTarget) {
|
||||
export function compileMethodInfo(methodInfo: MethodInfo, ctx: Context, target: CompilationTarget): CompiledMethodInfo {
|
||||
if (!methodInfo.code) {
|
||||
counter.count("Cannot Compile: Method has no code.");
|
||||
return;
|
||||
|
@ -486,14 +493,15 @@ module J2ME {
|
|||
var parameter = builder.parameters[i];
|
||||
args.push(parameter.name);
|
||||
}
|
||||
var fnSource = compilation.body;
|
||||
var body = compilation.body;
|
||||
// consoleWriter.writeLn(fnSource);
|
||||
fn = new Function(args.join(","), fnSource);
|
||||
// var fn = new Function(args.join(","), body);
|
||||
// consoleWriter.writeLn(fn.toString());
|
||||
// debug && writer.writeLn(fn.toString());
|
||||
counter.count("Compiled");
|
||||
} catch (e) {
|
||||
counter.count("Failed to Compile " + e);
|
||||
// consoleWriter.writeLn(e);
|
||||
// consoleWriter.writeLns(e.stack);
|
||||
debug && Debug.warning("Failed to compile " + methodInfo.implKey + " " + e + " " + e.stack);
|
||||
if (e.message.indexOf("Not Implemented ") === -1) {
|
||||
|
@ -501,7 +509,7 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
return fn;
|
||||
return new CompiledMethodInfo(args, body, builder.referencedClasses);
|
||||
}
|
||||
|
||||
interface WorklistItem {
|
||||
|
@ -588,16 +596,17 @@ module J2ME {
|
|||
*/
|
||||
blockMap: BlockMap;
|
||||
|
||||
ctxValue: IR.Parameter;
|
||||
|
||||
parameters: IR.Parameter [];
|
||||
|
||||
referencedClasses: ClassInfo [];
|
||||
|
||||
constructor(public methodInfo: MethodInfo, public ctx: Context, public target: CompilationTarget) {
|
||||
// ...
|
||||
this.peepholeOptimizer = new PeepholeOptimizer();
|
||||
this.signatureDescriptor = SignatureDescriptor.makeSignatureDescriptor(methodInfo.signature);
|
||||
this.methodReturnInfos = [];
|
||||
this.parameters = [];
|
||||
this.referencedClasses = [];
|
||||
}
|
||||
|
||||
build(): C4.Backend.Compilation {
|
||||
|
@ -605,16 +614,18 @@ module J2ME {
|
|||
|
||||
var methodInfo = this.methodInfo;
|
||||
|
||||
writer.enter("Compiling Method: " + methodInfo.name + " " + methodInfo.signature + " {");
|
||||
writer.writeLn("Size: " + methodInfo.code.length);
|
||||
writer && writer.enter("Compiling Method: " + methodInfo.name + " " + methodInfo.signature + " {");
|
||||
writer && writer.writeLn("Size: " + methodInfo.code.length);
|
||||
var blockMap = this.blockMap = new BlockMap(methodInfo);
|
||||
blockMap.build();
|
||||
debug && blockMap.trace(writer, true);
|
||||
|
||||
// consoleWriter.writeLn("Compiling Method: " + methodInfo.name + " " + methodInfo.signature + " {");
|
||||
// blockMap.trace(consoleWriter, false);
|
||||
|
||||
var start = this.buildStart();
|
||||
var dfg = this.buildGraph(start, start.entryState.clone());
|
||||
|
||||
debug && dfg.trace(writer);
|
||||
writer && dfg.trace(writer);
|
||||
|
||||
enterTimeline("Build CFG");
|
||||
var cfg = dfg.buildCFG();
|
||||
|
@ -632,7 +643,7 @@ module J2ME {
|
|||
cfg.scheduleEarly();
|
||||
leaveTimeline();
|
||||
|
||||
debug && cfg.trace(writer);
|
||||
writer && cfg.trace(writer);
|
||||
|
||||
enterTimeline("Verify IR");
|
||||
cfg.verify();
|
||||
|
@ -649,7 +660,7 @@ module J2ME {
|
|||
Node.stopNumbering();
|
||||
leaveTimeline();
|
||||
|
||||
writer.leave("}");
|
||||
writer && writer.leave("}");
|
||||
IR.Node.stopNumbering();
|
||||
|
||||
return result;
|
||||
|
@ -668,15 +679,10 @@ module J2ME {
|
|||
state.store.kind = Kind.Store;
|
||||
|
||||
var signatureDescriptor = this.signatureDescriptor;
|
||||
writer.writeLn("SIG: " + signatureDescriptor);
|
||||
writer && writer.writeLn("SIG: " + signatureDescriptor);
|
||||
|
||||
var typeDescriptors = signatureDescriptor.typeDescriptors;
|
||||
|
||||
|
||||
assert (!this.ctxValue);
|
||||
this.ctxValue = new IR.Parameter(start, 0, "$");
|
||||
this.parameters.push(this.ctxValue);
|
||||
|
||||
var localIndex = 0;
|
||||
var parameterIndex = 1;
|
||||
if (!methodInfo.isStatic) {
|
||||
|
@ -721,7 +727,7 @@ module J2ME {
|
|||
}
|
||||
this.blockStopInfos.forEach(function (stop: StopInfo) {
|
||||
var target = stop.target;
|
||||
writer.writeLn(String(target));
|
||||
writer && writer.writeLn(String(target));
|
||||
var region = target.region;
|
||||
if (region) {
|
||||
writer && writer.enter("Merging into region: " + region + " @ " + target.startBci + ", block " + target.blockID + " {");
|
||||
|
@ -977,7 +983,7 @@ module J2ME {
|
|||
}
|
||||
|
||||
genNewInstance(cpi: number) {
|
||||
var classInfo = this.ctx.resolve(this.methodInfo.classInfo.constant_pool, cpi, false);
|
||||
var classInfo = this.lookupClass(cpi);
|
||||
var jvmNew = new IR.JVMNew(this.region, this.state.store, classInfo);
|
||||
this.recordStore(jvmNew);
|
||||
this.state.apush(jvmNew);
|
||||
|
@ -992,7 +998,7 @@ module J2ME {
|
|||
}
|
||||
|
||||
genNewObjectArray(cpi: number) {
|
||||
var classInfo = this.ctx.resolve(this.methodInfo.classInfo.constant_pool, cpi, false);
|
||||
var classInfo = this.lookupClass(cpi);
|
||||
var length = this.state.ipop();
|
||||
var result = new IR.JVMNewObjectArray(this.region, this.state.store, classInfo, length);
|
||||
this.recordStore(result);
|
||||
|
@ -1025,14 +1031,14 @@ module J2ME {
|
|||
}
|
||||
|
||||
genCheckCast(cpi: Bytecodes) {
|
||||
var classInfo = this.ctx.resolve(this.methodInfo.classInfo.constant_pool, cpi, false);
|
||||
var classInfo = this.lookupClass(cpi);
|
||||
var object = this.state.peek();
|
||||
var checkCast = new IR.JVMCheckCast(this.region, this.state.store, object, classInfo);
|
||||
this.recordStore(checkCast);
|
||||
}
|
||||
|
||||
genInstanceOf(cpi: Bytecodes) {
|
||||
var classInfo = this.ctx.resolve(this.methodInfo.classInfo.constant_pool, cpi, false);
|
||||
var classInfo = this.lookupClass(cpi);
|
||||
var object = this.state.apop();
|
||||
var instanceOf = new IR.JVMInstanceOf(this.region, this.state.store, object, classInfo);
|
||||
this.recordStore(instanceOf);
|
||||
|
@ -1119,12 +1125,22 @@ module J2ME {
|
|||
));
|
||||
}
|
||||
|
||||
lookupClass(cpi: number): ClassInfo {
|
||||
var classInfo = this.ctx.resolve(this.methodInfo.classInfo.constant_pool, cpi, false);
|
||||
ArrayUtilities.pushUnique(this.referencedClasses, classInfo);
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
lookupMethod(cpi: number, opcode: Bytecodes, isStatic: boolean): MethodInfo {
|
||||
return this.ctx.resolve(this.methodInfo.classInfo.constant_pool, cpi, isStatic);
|
||||
var methodInfo = this.ctx.resolve(this.methodInfo.classInfo.constant_pool, cpi, isStatic);
|
||||
ArrayUtilities.pushUnique(this.referencedClasses, methodInfo.classInfo);
|
||||
return methodInfo;
|
||||
}
|
||||
|
||||
lookupField(cpi: number, opcode: Bytecodes, isStatic: boolean): FieldInfo {
|
||||
return this.ctx.resolve(this.methodInfo.classInfo.constant_pool, cpi, isStatic);
|
||||
var fieldInfo = this.ctx.resolve(this.methodInfo.classInfo.constant_pool, cpi, isStatic);
|
||||
ArrayUtilities.pushUnique(this.referencedClasses, fieldInfo.classInfo);
|
||||
return fieldInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1154,7 +1170,6 @@ module J2ME {
|
|||
}
|
||||
|
||||
genThrow(bci: number) {
|
||||
// this.ctx.methodInfos[this.methodInfo.implKey] = this.methodInfo;
|
||||
var _throw = new IR.JVMThrow(this.region, this.state.store);
|
||||
this.recordStore(_throw);
|
||||
this.methodReturnInfos.push(new ReturnInfo(
|
||||
|
@ -1177,12 +1192,11 @@ module J2ME {
|
|||
for (var i = types.length - 1; i > 0; i--) {
|
||||
args.unshift(this.state.pop(types[i].kind));
|
||||
}
|
||||
args.unshift(this.ctxValue);
|
||||
var object = null;
|
||||
if (opcode !== Bytecodes.INVOKESTATIC) {
|
||||
object = this.state.pop(Kind.Reference);
|
||||
}
|
||||
var call = new IR.JVMInvoke(this.region, this.state.store, opcode, object, methodInfo, args);
|
||||
var call = new IR.JVMInvoke(this.region, this.state.store, this.state.clone(nextBCI), opcode, object, methodInfo, args);
|
||||
this.recordStore(call);
|
||||
if (types[0].kind !== Kind.Void) {
|
||||
this.state.push(types[0].kind, call);
|
||||
|
@ -1213,6 +1227,7 @@ module J2ME {
|
|||
}
|
||||
|
||||
genClass(classInfo: ClassInfo): Value {
|
||||
ArrayUtilities.pushUnique(this.referencedClasses, classInfo);
|
||||
return new IR.JVMClass(classInfo);
|
||||
}
|
||||
|
||||
|
@ -1235,7 +1250,7 @@ module J2ME {
|
|||
processBytecode(stream: BytecodeStream, state: State) {
|
||||
var cpi: number;
|
||||
var opcode: Bytecodes = stream.currentBC();
|
||||
writer.enter("State Before: " + Bytecodes[opcode].padRight(" ", 12) + " " + state.toString());
|
||||
writer && writer.enter("State Before: " + Bytecodes[opcode].padRight(" ", 12) + " " + state.toString());
|
||||
switch (opcode) {
|
||||
case Bytecodes.NOP : break;
|
||||
case Bytecodes.ACONST_NULL : state.apush(genConstant(null, Kind.Reference)); break;
|
||||
|
@ -1457,8 +1472,8 @@ module J2ME {
|
|||
default:
|
||||
throw new Error("Not Implemented " + Bytecodes[opcode]);
|
||||
}
|
||||
writer.leave("State After: " + Bytecodes[opcode].padRight(" ", 12) + " " + state.toString());
|
||||
writer.writeLn("");
|
||||
writer && writer.leave("State After: " + Bytecodes[opcode].padRight(" ", 12) + " " + state.toString());
|
||||
writer && writer.writeLn("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -276,6 +276,9 @@ module J2ME.C4.AST {
|
|||
if (value === null) {
|
||||
return 'null';
|
||||
}
|
||||
if (value === undefined) {
|
||||
return 'undefined';
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
return escapeString(value);
|
||||
}
|
||||
|
@ -343,7 +346,7 @@ module J2ME.C4.AST {
|
|||
super();
|
||||
}
|
||||
toSource(precedence: number) : string {
|
||||
return "{\n" + nodesToSource(this.body, precedence) + "}";
|
||||
return "{" + nodesToSource(this.body, precedence, "\n") + "}";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,12 +355,12 @@ module J2ME.C4.AST {
|
|||
super();
|
||||
}
|
||||
toSource(precedence: number) : string {
|
||||
return this.expression.toSource(Precedence.Sequence) + ";\n";
|
||||
return this.expression.toSource(Precedence.Sequence) + ";";
|
||||
}
|
||||
}
|
||||
|
||||
export class IfStatement extends Statement {
|
||||
constructor (public test: Expression, public consequent: Statement, public alternate: Statement) {
|
||||
constructor (public test: Expression, public consequent: Statement, public alternate?: Statement) {
|
||||
super();
|
||||
}
|
||||
toSource(precedence: number) : string {
|
||||
|
@ -421,11 +424,11 @@ module J2ME.C4.AST {
|
|||
super();
|
||||
}
|
||||
toSource(precedence: number) : string {
|
||||
var result = "return ";
|
||||
var result = "return";
|
||||
if (this.argument) {
|
||||
result += this.argument.toSource(Precedence.Sequence);
|
||||
result += " " + this.argument.toSource(Precedence.Sequence);
|
||||
}
|
||||
return result + ";\n";
|
||||
return result + ";";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -368,13 +368,18 @@ module J2ME.C4.Backend {
|
|||
this.useVariable(node.to);
|
||||
from = compileValue(node.from, this);
|
||||
} else {
|
||||
if (node.variable && !node.handlesAssignment) {
|
||||
to = id(node.variable.name);
|
||||
this.useVariable(node.variable);
|
||||
} else {
|
||||
to = null;
|
||||
}
|
||||
from = compileValue(node, this, true);
|
||||
if (from instanceof AST.Statement) {
|
||||
body.push(from);
|
||||
continue;
|
||||
} else {
|
||||
if (node.variable) {
|
||||
to = id(node.variable.name);
|
||||
this.useVariable(node.variable);
|
||||
} else {
|
||||
to = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (to) {
|
||||
statement = new ExpressionStatement(assignment(to, from));
|
||||
|
|
|
@ -265,7 +265,7 @@ module J2ME.C4.IR {
|
|||
Store.prototype.nodeName = "Store";
|
||||
|
||||
export class StoreDependent extends Value {
|
||||
loads: Node [];
|
||||
public loads: Node [];
|
||||
constructor(public control: Control, public store: Store) {
|
||||
super();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
module J2ME {
|
||||
|
||||
import mangleClass = J2ME.C4.Backend.mangleClass;
|
||||
import mangleField = J2ME.C4.Backend.mangleField;
|
||||
import mangleMethod = J2ME.C4.Backend.mangleMethod;
|
||||
import mangleClassAndMethod = J2ME.C4.Backend.mangleClassAndMethod;
|
||||
|
||||
declare var JVM, Runtime, CLASSES, Context, release;
|
||||
|
||||
var consoleWriter = new IndentingWriter();
|
||||
|
||||
export class Emitter {
|
||||
constructor(
|
||||
public writer: IndentingWriter,
|
||||
public closure: boolean,
|
||||
public debugInfo: boolean
|
||||
) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
function getClassInheritanceChain(classInfo: ClassInfo): ClassInfo [] {
|
||||
var list = [];
|
||||
var klass = classInfo;
|
||||
while (klass) {
|
||||
list.unshift(klass);
|
||||
klass = klass.superClass;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
function compileConstructor(emitter: Emitter, classInfo: ClassInfo) {
|
||||
var writer = emitter.writer;
|
||||
var mangledClassName = mangleClass(classInfo);
|
||||
if (emitter.closure) {
|
||||
writer.writeLn("/** @constructor */");
|
||||
}
|
||||
|
||||
writer.enter("function " + mangledClassName + "() {");
|
||||
getClassInheritanceChain(classInfo).forEach(function (klass) {
|
||||
for (var i = 0; i < klass.fields.length; i++) {
|
||||
var fieldInfo = klass.fields[i];
|
||||
if (fieldInfo.isStatic) {
|
||||
continue;
|
||||
}
|
||||
var signature = TypeDescriptor.makeTypeDescriptor(fieldInfo.signature);
|
||||
var kind = signature.kind;
|
||||
var defaultValue;
|
||||
switch (kind) {
|
||||
case Kind.Reference:
|
||||
defaultValue = "null";
|
||||
break;
|
||||
case Kind.Long:
|
||||
defaultValue = "Long.ZERO";
|
||||
break;
|
||||
default:
|
||||
defaultValue = "0";
|
||||
break;
|
||||
}
|
||||
if (emitter.closure) {
|
||||
writer.writeLn("this[" + quote(mangleField(fieldInfo)) + "] = " + defaultValue + ";");
|
||||
} else {
|
||||
writer.writeLn("this." + mangleField(fieldInfo) + " = " + defaultValue + ";");
|
||||
}
|
||||
}
|
||||
});
|
||||
writer.leave("}");
|
||||
|
||||
if (emitter.closure) {
|
||||
writer.writeLn("window[" + quote(mangledClassName) + "] = " + mangledClassName + ";");
|
||||
}
|
||||
|
||||
if (classInfo.superClass) {
|
||||
var mangledSuperClassName = mangleClass(classInfo.superClass);
|
||||
writer.writeLn(mangledClassName + ".prototype = Object.create(" + mangledSuperClassName + ".prototype);");
|
||||
}
|
||||
}
|
||||
|
||||
function compileClassInfo(emitter: Emitter, classInfo: ClassInfo, ctx: Context): CompiledMethodInfo [] {
|
||||
var writer = emitter.writer;
|
||||
var mangledClassName = mangleClass(classInfo);
|
||||
if (!J2ME.C4.Backend.isIdentifierName(mangledClassName)) {
|
||||
mangledClassName = quote(mangledClassName);
|
||||
}
|
||||
|
||||
compileConstructor(emitter, classInfo);
|
||||
|
||||
var methods = classInfo.methods;
|
||||
var compiledMethods: CompiledMethodInfo [] = [];
|
||||
for (var i = 0; i < methods.length; i++) {
|
||||
var method = methods[i];
|
||||
var mangledMethodName = mangleMethod(method);
|
||||
if (!J2ME.C4.Backend.isIdentifierName(mangledMethodName)) {
|
||||
mangledMethodName = quote(mangledMethodName);
|
||||
}
|
||||
try {
|
||||
if (emitter.debugInfo) {
|
||||
writer.writeLn("// " + classInfo.className + "/" + method.name);
|
||||
}
|
||||
var mangledClassAndMethodName = mangleClassAndMethod(method);
|
||||
var compiledMethod = compileMethodInfo(method, ctx, CompilationTarget.Static);
|
||||
if (compiledMethod && compiledMethod.body) {
|
||||
writer.enter("function " + mangledClassAndMethodName + "(" + compiledMethod.args.join(",") + ") {");
|
||||
writer.writeLns(compiledMethod.body);
|
||||
writer.leave("}");
|
||||
if (emitter.closure) {
|
||||
writer.writeLn(mangledClassName + ".prototype[" + quote(mangledMethodName) + "] = " + mangledClassAndMethodName + ";");
|
||||
} else {
|
||||
writer.writeLn(mangledClassName + ".prototype." + mangledMethodName + " = " + mangledClassAndMethodName + ";");
|
||||
}
|
||||
if (emitter.closure) {
|
||||
writer.writeLn("window[" + quote(mangledClassAndMethodName) + "] = " + mangledClassAndMethodName + ";");
|
||||
}
|
||||
compiledMethods.push(compiledMethod);
|
||||
}
|
||||
} catch (x) {
|
||||
consoleWriter.writeLn("XXXX: " + x);
|
||||
}
|
||||
}
|
||||
|
||||
return compiledMethods;
|
||||
}
|
||||
|
||||
export function compile(jvm: any, classFilter: string, debugInfo: boolean) {
|
||||
var runtime = new Runtime(jvm);
|
||||
var classFiles = CLASSES.classfiles;
|
||||
var ctx = new Context(runtime);
|
||||
|
||||
var code = "";
|
||||
var writer = new J2ME.IndentingWriter(false, function (s) {
|
||||
code += s + "\n";
|
||||
});
|
||||
|
||||
var emitter = new Emitter(writer, false, debugInfo);
|
||||
|
||||
var compiledMethods: CompiledMethodInfo [] = [];
|
||||
var classInfoList: ClassInfo [] = [];
|
||||
Object.keys(classFiles).every(function (path) {
|
||||
if (path.substr(-4) !== ".jar") {
|
||||
return true;
|
||||
}
|
||||
var zipFile = classFiles[path];
|
||||
Object.keys(zipFile.directory).every(function (fileName) {
|
||||
if (fileName.substr(-6) !== '.class') {
|
||||
return true;
|
||||
}
|
||||
var classInfo = CLASSES.loadClassFile(fileName);
|
||||
if (!classInfo.className.match(classFilter)) {
|
||||
return true;
|
||||
}
|
||||
classInfoList.push(classInfo);
|
||||
return true;
|
||||
}.bind(this));
|
||||
return true;
|
||||
}.bind(this));
|
||||
|
||||
var orderedClassInfoList: ClassInfo [] = [];
|
||||
|
||||
function indexOf(list, classInfo) {
|
||||
if (!classInfo) {
|
||||
return -1;
|
||||
}
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i].className === classInfo.className) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
while (classInfoList.length) {
|
||||
for (var i = 0; i < classInfoList.length; i++) {
|
||||
var classInfo = classInfoList[i];
|
||||
// writer.writeLn(nameOf(classInfo) + " " + nameOf(classInfo.superClass) + " " + classInfoList.indexOf(classInfo.superClass));
|
||||
if (indexOf(classInfoList, classInfo.superClass) < 0) {
|
||||
orderedClassInfoList.push(classInfo);
|
||||
classInfoList.splice(i--, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < orderedClassInfoList.length; i++) {
|
||||
var classInfo = orderedClassInfoList[i];
|
||||
if (emitter.debugInfo) {
|
||||
writer.writeLn("// " + classInfo.className + (classInfo.superClass ? " extends " + classInfo.superClass.className : ""));
|
||||
}
|
||||
ArrayUtilities.pushMany(compiledMethods, compileClassInfo(emitter, classInfo, ctx));
|
||||
}
|
||||
|
||||
/*
|
||||
writer.enter("referencedClasses: [");
|
||||
var referencedClasses = Object.create(null);
|
||||
compiledMethods.forEach(compiledMethod => {
|
||||
compiledMethod.referencedClasses.forEach(classInfo => {
|
||||
referencedClasses[classInfo.className] = true;
|
||||
});
|
||||
});
|
||||
var classNames = Object.keys(referencedClasses);
|
||||
for (var i = 0; i < classNames.length; i++) {
|
||||
writer.writeLn(quote(classNames[i]) + (i < classNames.length - 1 ? "," : ""));
|
||||
}
|
||||
writer.leave("]");
|
||||
*/
|
||||
consoleWriter.writeLn(code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -165,34 +165,8 @@ module J2ME.C4.IR {
|
|||
}
|
||||
}
|
||||
|
||||
export class JVMCallProperty extends StoreDependent {
|
||||
|
||||
constructor(control: Control, store: Store, public state: State, public object: Value, public name: Value, public args: Value [], public callerMethodInfoId: string, public objectCheck?: boolean) {
|
||||
super(control, store);
|
||||
this.handlesAssignment = true;
|
||||
}
|
||||
visitInputs(visitor: NodeVisitor) {
|
||||
this.control && visitor(this.control);
|
||||
this.store && visitor(this.store);
|
||||
this.loads && visitArrayInputs(this.loads, visitor);
|
||||
visitor(this.object);
|
||||
visitor(this.name);
|
||||
visitArrayInputs(this.args, visitor);
|
||||
visitStateInputs(this.state.local, visitor);
|
||||
visitStateInputs(this.state.stack, visitor);
|
||||
}
|
||||
replaceInput(oldInput: Node, newInput: Node) {
|
||||
var count = super.replaceInput(oldInput, newInput);
|
||||
count += (<any>this.state.local).replace(oldInput, newInput);
|
||||
count += (<any>this.state.stack).replace(oldInput, newInput);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
JVMCallProperty.prototype.nodeName = "JVMCallProperty";
|
||||
|
||||
export class JVMInvoke extends StoreDependent {
|
||||
constructor(control: Control, store: Store, public opcode: J2ME.Bytecode.Bytecodes, public object: Value, public methodInfo: MethodInfo, public args: Value []) {
|
||||
constructor(control: Control, store: Store, public state: State, public opcode: J2ME.Bytecode.Bytecodes, public object: Value, public methodInfo: MethodInfo, public args: Value []) {
|
||||
super(control, store);
|
||||
}
|
||||
visitInputs(visitor: NodeVisitor) {
|
||||
|
@ -201,6 +175,18 @@ module J2ME.C4.IR {
|
|||
this.loads && visitArrayInputs(this.loads, visitor);
|
||||
this.object && visitor(this.object);
|
||||
visitArrayInputs(this.args, visitor);
|
||||
if (this.state) {
|
||||
visitStateInputs(this.state.local, visitor);
|
||||
visitStateInputs(this.state.stack, visitor);
|
||||
}
|
||||
}
|
||||
replaceInput(oldInput: Node, newInput: Node) {
|
||||
var count = super.replaceInput(oldInput, newInput);
|
||||
if (this.state) {
|
||||
count += (<any>this.state.local).replace(oldInput, newInput);
|
||||
count += (<any>this.state.stack).replace(oldInput, newInput);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -505,6 +491,7 @@ module J2ME.C4.Backend {
|
|||
return compiledValues;
|
||||
}
|
||||
|
||||
/*
|
||||
IR.JVMCallProperty.prototype.compile = function (cx: Context): AST.Node {
|
||||
|
||||
var localValues = compileStateValues(cx, this.state.local);
|
||||
|
@ -566,6 +553,7 @@ module J2ME.C4.Backend {
|
|||
null
|
||||
);
|
||||
};
|
||||
*/
|
||||
|
||||
IR.JVMInvoke.prototype.compile = function (cx: Context): AST.Node {
|
||||
var object = this.object ? compileValue(this.object, cx) : null;
|
||||
|
@ -573,19 +561,32 @@ module J2ME.C4.Backend {
|
|||
return compileValue(arg, cx);
|
||||
});
|
||||
var callee = null;
|
||||
|
||||
var result = null;
|
||||
if (object) {
|
||||
if (this.opcode === J2ME.Bytecode.Bytecodes.INVOKESPECIAL) {
|
||||
var classPrototype = property(id(mangleClass(this.methodInfo.classInfo)), "prototype");
|
||||
var callee = property(classPrototype, mangleMethod(this.methodInfo));
|
||||
return callCall(callee, object, args);
|
||||
result = callCall(id(mangleClassAndMethod(this.methodInfo)), object, args);
|
||||
} else {
|
||||
callee = property(object, mangleMethod(this.methodInfo));
|
||||
result = call(callee, args);
|
||||
}
|
||||
callee = property(object, mangleMethod(this.methodInfo));
|
||||
} else {
|
||||
release || assert (this.opcode === J2ME.Bytecode.Bytecodes.INVOKESTATIC);
|
||||
callee = id(mangleMethod(this.methodInfo));
|
||||
result = call(callee, args);
|
||||
}
|
||||
return call(callee, args);
|
||||
if (false && this.state) {
|
||||
var block = new AST.BlockStatement([]);
|
||||
var to = id(this.variable.name);
|
||||
cx.useVariable(this.variable);
|
||||
block.body.push(new AST.ExpressionStatement(assignment(to, result)));
|
||||
var ifYield = new AST.IfStatement(id("$Y"), new AST.BlockStatement([
|
||||
new AST.ExpressionStatement(call(property(id("$"), "B"), [])),
|
||||
new AST.ReturnStatement(undefined)
|
||||
]));
|
||||
block.body.push(ifYield);
|
||||
return block;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
function hashString(s: string) {
|
||||
|
@ -613,11 +614,21 @@ module J2ME.C4.Backend {
|
|||
return result;
|
||||
}
|
||||
|
||||
export function mangleMethod(methodInfo: MethodInfo) {
|
||||
export function mangleClassAndMethod(methodInfo: MethodInfo) {
|
||||
var name = methodInfo.classInfo.className + methodInfo.name + methodInfo.signature;
|
||||
if (friendlyMangledNames) {
|
||||
return mangleString(methodInfo.name + methodInfo.signature);
|
||||
return mangleString(name);
|
||||
}
|
||||
var hash = hashString(methodInfo.name + methodInfo.signature);
|
||||
var hash = hashString(name);
|
||||
return StringUtilities.variableLengthEncodeInt32(hash);
|
||||
}
|
||||
|
||||
export function mangleMethod(methodInfo: MethodInfo) {
|
||||
var name = methodInfo.name + methodInfo.signature;
|
||||
if (friendlyMangledNames) {
|
||||
return mangleString(name);
|
||||
}
|
||||
var hash = hashString(name);
|
||||
return StringUtilities.variableLengthEncodeInt32(hash);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,4 +11,5 @@
|
|||
///<reference path='jvm.ir.ts' />
|
||||
///<reference path='types.ts' />
|
||||
///<reference path='blockMap.ts' />
|
||||
///<reference path='builder.ts' />
|
||||
///<reference path='builder.ts' />
|
||||
///<reference path='compiler.ts' />
|
118
opt/shell.ts
118
opt/shell.ts
|
@ -175,127 +175,11 @@ module J2ME {
|
|||
if (verboseOption.value) {
|
||||
writer.writeLn("Compiling Pattern: " + classFilterOption.value);
|
||||
}
|
||||
compile(jvm, classFilterOption.value);
|
||||
compile(jvm, classFilterOption.value, debuggerOption.value);
|
||||
}
|
||||
jvm.initializeBuiltinClasses();
|
||||
}
|
||||
|
||||
function getClassInheritanceChain(classInfo: ClassInfo): ClassInfo [] {
|
||||
var list = [];
|
||||
var klass = classInfo;
|
||||
while (klass) {
|
||||
list.unshift(klass);
|
||||
klass = klass.superClass;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
function compileClassInfo(codeWriter: IndentingWriter, classInfo: ClassInfo, ctx: Context) {
|
||||
var mangledClassName = J2ME.C4.Backend.mangleClass(classInfo);
|
||||
if (!J2ME.C4.Backend.isIdentifierName(mangledClassName)) {
|
||||
mangledClassName = quote(mangledClassName);
|
||||
}
|
||||
codeWriter.enter(mangledClassName + ": {");
|
||||
codeWriter.enter("initializer: function () {");
|
||||
getClassInheritanceChain(classInfo).forEach(function (klass) {
|
||||
if (debuggerOption.value) {
|
||||
codeWriter.writeLn("// " + klass.className);
|
||||
}
|
||||
for (var i = 0; i < klass.fields.length; i++) {
|
||||
var fieldInfo = klass.fields[i];
|
||||
var signature = TypeDescriptor.makeTypeDescriptor(fieldInfo.signature);
|
||||
var kind = signature.kind;
|
||||
var defaultValue;
|
||||
switch (kind) {
|
||||
case Kind.Reference:
|
||||
defaultValue = "null";
|
||||
break;
|
||||
case Kind.Long:
|
||||
defaultValue = "Long.ZERO";
|
||||
break;
|
||||
default:
|
||||
defaultValue = "0";
|
||||
break;
|
||||
}
|
||||
codeWriter.writeLn("this." + J2ME.C4.Backend.mangleField(fieldInfo) + " = " + defaultValue + ";");
|
||||
}
|
||||
});
|
||||
codeWriter.leave("},");
|
||||
codeWriter.enter("methods: {");
|
||||
var methods = classInfo.methods;
|
||||
for (var i = 0; i < methods.length; i++) {
|
||||
var method = methods[i];
|
||||
var mangledMethodName = J2ME.C4.Backend.mangleMethod(method);
|
||||
if (!J2ME.C4.Backend.isIdentifierName(mangledMethodName)) {
|
||||
mangledMethodName = quote(mangledMethodName);
|
||||
}
|
||||
try {
|
||||
var fn = compileMethodInfo(method, ctx, CompilationTarget.Static);
|
||||
if (fn) {
|
||||
if (debuggerOption.value) {
|
||||
codeWriter.writeLn("// " + method.name);
|
||||
}
|
||||
codeWriter.enter(mangledMethodName + ": ");
|
||||
codeWriter.write(fn);
|
||||
codeWriter.leave(",");
|
||||
if (verboseOption.value) {
|
||||
writer.write(fn);
|
||||
}
|
||||
}
|
||||
} catch (x) {
|
||||
|
||||
codeWriter.writeLn(mangledMethodName + ": undefined,");
|
||||
}
|
||||
}
|
||||
codeWriter.leave("}");
|
||||
codeWriter.leave("},");
|
||||
}
|
||||
|
||||
function compile(jvm: any, classFilter: string) {
|
||||
var runtime = new Runtime(jvm);
|
||||
var classFiles = CLASSES.classfiles;
|
||||
var ctx = new Context(runtime);
|
||||
|
||||
var code = "";
|
||||
var codeWriter = new J2ME.IndentingWriter(false, function (s) {
|
||||
code += s + "\n";
|
||||
});
|
||||
|
||||
codeWriter.enter("var CC = {");
|
||||
Object.keys(classFiles).every(function (name) {
|
||||
if (name.substr(-4) !== ".jar") {
|
||||
return true;
|
||||
}
|
||||
var zip = classFiles[name];
|
||||
// codeWriter.enter(J2ME.quote(name) + ": {");
|
||||
Object.keys(zip.directory).every(function (fileName) {
|
||||
if (fileName.substr(-6) !== '.class') {
|
||||
return true;
|
||||
}
|
||||
if (!fileName.match(classFilter)) {
|
||||
return true;
|
||||
}
|
||||
if (verboseOption.value) {
|
||||
writer.writeLn("Compiling Class: " + fileName);
|
||||
}
|
||||
if (debuggerOption.value) {
|
||||
codeWriter.writeLn("// " + fileName);
|
||||
}
|
||||
compileClassInfo(codeWriter, CLASSES.loadClassFile(fileName), ctx);
|
||||
// codeWriter.leave("},");
|
||||
return true;
|
||||
}.bind(this));
|
||||
|
||||
// codeWriter.leave("},");
|
||||
return true;
|
||||
}.bind(this));
|
||||
codeWriter.leave("}");
|
||||
writer.writeLn(code);
|
||||
if (verboseOption.value) {
|
||||
J2ME.printResults();
|
||||
}
|
||||
}
|
||||
|
||||
var commandLineArguments: string [];
|
||||
// Shell Entry Point
|
||||
if (typeof help === "function") {
|
||||
|
|
Загрузка…
Ссылка в новой задаче