A more compact encoding of unwind code.

This commit is contained in:
Michael Bebenita 2015-03-06 01:45:06 -08:00
Родитель a521034be2
Коммит 46b9fd2079
4 изменённых файлов: 79 добавлений и 13 удалений

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

@ -744,7 +744,7 @@ module J2ME.Bytecode {
* Determines if a given opcode denotes an instruction that stores a value to a local variable
* after popping it from the operand stack.
*/
function isInvoke(opcode: Bytecodes): boolean {
export function isInvoke(opcode: Bytecodes): boolean {
return (flags[opcode & 0xff] & Flags.INVOKE) != 0;
}

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

@ -312,6 +312,8 @@ module J2ME {
*/
static stackNames = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "_O", "P", "Q", "R", "S", "T", "_U", "V", "W", "X", "Y", "Z"];
private hasUnwindThrow;
constructor(methodInfo: MethodInfo, target: CompilationTarget) {
this.methodInfo = methodInfo;
this.local = [];
@ -330,6 +332,7 @@ module J2ME {
this.bodyEmitter = new Emitter(target !== CompilationTarget.Runtime);
this.blockEmitter = new Emitter(target !== CompilationTarget.Runtime);
this.target = target;
this.hasUnwindThrow = false;
}
compile(): CompiledMethodInfo {
@ -388,11 +391,6 @@ module J2ME {
this.bodyEmitter.writeLn("J2ME.baselineMethodCounter.count(\"" + this.methodInfo.implKey + "\");");
}
needsWhile && this.bodyEmitter.enter("while (1) {");
needsTry && this.bodyEmitter.enter("try {");
this.bodyEmitter.writeLn("var label = 0;");
var blocks = blockMap.blocks;
for (var i = 0; i < blocks.length; i++) {
var block = blocks[i];
@ -407,12 +405,24 @@ module J2ME {
this.emitBlockBody(stream, block);
}
if (this.hasUnwindThrow) {
needsTry = true;
}
needsWhile && this.bodyEmitter.enter("while (1) {");
needsTry && this.bodyEmitter.enter("try {");
this.bodyEmitter.writeLn("var label = 0;");
this.bodyEmitter.writeLns(Relooper.render(this.entryBlock));
emitCompilerAssertions && this.bodyEmitter.writeLn("J2ME.Debug.assert(false, 'Invalid PC: ' + pc)");
if (needsTry) {
this.bodyEmitter.leaveAndEnter("} catch (ex) {");
if (this.hasUnwindThrow) {
var local = this.local.join(", ");
var stack = this.stack.join(", ");
this.bodyEmitter.writeLn("if (U) { $.T(ex, [" + local + "], [" + stack + "], " + this.lockObject + "); return; }");
}
this.bodyEmitter.writeLn(this.getStackName(0) + " = TE(ex);");
this.blockStack = [this.getStackName(0)];
this.sp = 1;
@ -970,10 +980,16 @@ module J2ME {
this.emitPush(Kind.Reference, "NM(" + classConstant(classInfo) + ", [" + dimensions.join(", ") + "])", Precedence.Call);
}
private emitUnwind(emitter: Emitter, pc: string, nextPC: string) {
var local = this.local.join(", ");
var stack = this.blockStack.slice(0, this.sp).join(", ");
emitter.writeLn("if (U) { $.B(" + pc + ", " + nextPC + ", [" + local + "], [" + stack + "], " + this.lockObject + "); return; }");
private emitUnwind(emitter: Emitter, pc: string, nextPC: string, forceInline: boolean = false) {
if (!forceInline && this.blockMap.invokeCount > 2) {
this.flushBlockStack();
emitter.writeLn("U && TU(" + UnwindThrowLocation.encode(pc, nextPC, this.sp) + ");");
this.hasUnwindThrow = true;
} else {
var local = this.local.join(", ");
var stack = this.blockStack.slice(0, this.sp).join(", ");
emitter.writeLn("if (U) { $.B(" + pc + ", " + nextPC + ", [" + local + "], [" + stack + "], " + this.lockObject + "); return; }");
}
baselineCounter && baselineCounter.count("emitUnwind");
}
@ -987,7 +1003,7 @@ module J2ME {
this.needsVariable("lk");
emitter.writeLn("lk = " + object + "._lock;");
emitter.enter("if (lk && lk.level === 0) { lk.thread = th; lk.level = 1; } else { ME(" + object + ");");
this.emitUnwind(emitter, String(this.pc), String(nextPC));
this.emitUnwind(emitter, String(this.pc), String(nextPC), true);
emitter.leave("}");
}

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

@ -87,6 +87,7 @@ module J2ME.Bytecode {
method: MethodInfo;
blocks: Block [];
hasBackwardBranches: boolean;
invokeCount: number;
private blockMap: Block [];
private startBlock: Block;
private canTrap: Uint32ArrayBitSet;
@ -96,6 +97,7 @@ module J2ME.Bytecode {
this.blocks = [];
this.method = method;
this.hasBackwardBranches = false;
this.invokeCount = 0;
this.blockMap = new Array<Block>(method.code.length);
this.canTrap = new Uint32ArrayBitSet(this.blockMap.length);
this.exceptionHandlers = this.method.exception_table;
@ -293,6 +295,9 @@ module J2ME.Bytecode {
if (this.canTrapAt(opcode, bci)) {
this.canTrap.set(bci);
}
if (Bytecode.isInvoke(opcode)) {
this.invokeCount ++;
}
}
}
bci += lengthAt(code, bci);

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

@ -737,10 +737,20 @@ module J2ME {
/**
* Bailout callback whenever a JIT frame is unwound.
*/
B(bci: number, nextBCI: number, local: any [], stack: any [], lockObject: java.lang.Object) {
B(pc: number, nextPC: number, local: any [], stack: any [], lockObject: java.lang.Object) {
var methodInfo = jitMethodInfos[(<any>arguments.callee.caller).name];
release || assert(methodInfo !== undefined);
$.ctx.bailout(methodInfo, bci, nextBCI, local, stack, lockObject);
$.ctx.bailout(methodInfo, pc, nextPC, local, stack, lockObject);
}
/**
* Bailout callback whenever a JIT frame is unwound that uses a slightly different calling
* convetion that makes it more convenient to emit in some cases.
*/
T(location: UnwindThrowLocation, local: any [], stack: any [], lockObject: java.lang.Object) {
var methodInfo = jitMethodInfos[(<any>arguments.callee.caller).name];
release || assert(methodInfo !== undefined);
$.ctx.bailout(methodInfo, location.getPC(), location.getNextPC(), local, stack.slice(0, location.getSP()), lockObject);
}
yield(reason: string) {
@ -1865,6 +1875,39 @@ module J2ME {
$.yield("preemption");
}
}
export class UnwindThrowLocation {
static instance: UnwindThrowLocation = new UnwindThrowLocation();
constructor() {
this.location = 0;
}
static encode(pc, nextPC, sp) {
var delta = nextPC - pc;
release || assert (delta >= 0 && delta < 8, delta);
return pc << 11 | delta << 8 | sp;
}
location: number;
set(location: number) {
this.location = location;
return this;
}
getPC() {
return (this.location >> 11) & 0xffff;
}
getNextPC() {
return this.getPC() + ((this.location >> 8) & 0x07);
}
getSP() {
return this.location & 0xff;
}
}
export function throwUnwind(location: number) {
if (location === 0) {
debugger;
}
throw UnwindThrowLocation.instance.set(location);
}
}
var Runtime = J2ME.Runtime;
@ -1878,6 +1921,8 @@ var AOTMD = J2ME.aotMetaData;
*/
var U: J2ME.VMState = J2ME.VMState.Running;
var TU = J2ME.throwUnwind;
/**
* OSR Frame.
*/