зеркало из https://github.com/mozilla/pluotsorbet.git
A more compact encoding of unwind code.
This commit is contained in:
Родитель
a521034be2
Коммит
46b9fd2079
|
@ -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.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче