Skip to content

Commit

Permalink
Coarsen trycatch regions for contiguous blocks with same rescue.
Browse files Browse the repository at this point in the history
Fixes #3777.

Previously, every basic block with an associated rescue block
would get its own trycatch range emitted into JVM bytecode. This
may not be an issue on all JVMs, but some may have trouble
optimizing code across all those trycatch boundaries. Others may
do this coarsening for us, but we're still bloating up the size
of the emitted bytecode. Either way, this fix combines contiguous
blocks that have the same rescue into a single JVM trycatch.
headius committed Apr 5, 2016
1 parent e6a5867 commit ff882fc
Showing 1 changed file with 54 additions and 11 deletions.
65 changes: 54 additions & 11 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -166,23 +166,65 @@ public void emitScope(IRScope scope, String name, Signature signature, boolean s

int numberOfBasicBlocks = bbs.length;
int ipc = 0; // synthetic, used for debug traces that show which instr failed

Label currentRescue = null;
Label currentRegionStart = null;
Label currentBlockStart = null;
Map<Label, org.objectweb.asm.Label> rescueEndForStart = new HashMap<>();
Map<Label, org.objectweb.asm.Label> syntheticEndForStart = new HashMap<>();

for (int i = 0; i < numberOfBasicBlocks; i++) {
BasicBlock bb = bbs[i];
org.objectweb.asm.Label start = jvm.methodData().getLabel(bb.getLabel());
Label rescueLabel = exceptionTable.get(bb);
org.objectweb.asm.Label end = null;
currentBlockStart = bb.getLabel();

m.mark(start);
Label rescueLabel = exceptionTable.get(bb);

boolean newEnd = false;
if (rescueLabel != null) {
if (i+1 < numberOfBasicBlocks) {
end = jvm.methodData().getLabel(bbs[i+1].getLabel());
if (currentRescue != null) {
if (rescueLabel == currentRescue) {
// continue, inside active rescue region
continue;
} else {
// end of active region and start of new one
rescueEndForStart.put(currentRegionStart, jvm.methodData().getLabel(bb.getLabel()));
currentRescue = rescueLabel;
currentRegionStart = bb.getLabel();
}
} else {
newEnd = true;
end = new org.objectweb.asm.Label();
currentRescue = rescueLabel;
currentRegionStart = bb.getLabel();
}
} else {
if (currentRescue == null) {
// continue, no new or active region
continue;
} else {
// end of active region, no new region
rescueEndForStart.put(currentRegionStart, jvm.methodData().getLabel(bb.getLabel()));
currentRescue = null;
currentRegionStart = null;
}
}
}

// handle unclosed final region
if (currentRegionStart != null) {
org.objectweb.asm.Label syntheticEnd = new org.objectweb.asm.Label();
rescueEndForStart.put(currentRegionStart, syntheticEnd);
syntheticEndForStart.put(currentBlockStart, syntheticEnd);
}

for (int i = 0; i < numberOfBasicBlocks; i++) {
BasicBlock bb = bbs[i];
org.objectweb.asm.Label start = jvm.methodData().getLabel(bb.getLabel());
Label rescueLabel = exceptionTable.get(bb);

m.mark(start);

// if this is the start of a rescued region, emit trycatch
org.objectweb.asm.Label end;
if (rescueLabel != null && (end = rescueEndForStart.get(bb.getLabel())) != null) {
// first entry into a rescue region, do the try/catch
org.objectweb.asm.Label rescue = jvm.methodData().getLabel(rescueLabel);
jvmAdapter().trycatch(start, end, rescue, p(Throwable.class));
}
@@ -201,8 +243,9 @@ public void emitScope(IRScope scope, String name, Signature signature, boolean s
visit(instr);
}

if (newEnd) {
m.mark(end);
org.objectweb.asm.Label syntheticEnd = syntheticEndForStart.get(bb.getLabel());
if (syntheticEnd != null) {
m.mark(syntheticEnd);
}
}

0 comments on commit ff882fc

Please sign in to comment.