Skip to content

Commit

Permalink
Rework variable mapping logic
Browse files Browse the repository at this point in the history
Possibly fixes btraceio#333
Possibly fixes btraceio#367
  • Loading branch information
jbachorik committed Nov 11, 2018
1 parent 4c2a39f commit 587730f
Show file tree
Hide file tree
Showing 8 changed files with 641 additions and 199 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -321,16 +321,18 @@ private static final class SavedState {
static final int UNCONDITIONAL = 1;
static final int EXCEPTION = 2;

private final VariableMapper mapper;
private final LocalVarTypes lvTypes;
private final SimulatedStack sStack;
private final Collection<LocalVarSlot> newLocals;
private final int kind;

SavedState(LocalVarTypes lvTypes, SimulatedStack sStack, Collection<LocalVarSlot> newLocals) {
this(lvTypes, sStack, newLocals, CONDITIONAL);
SavedState(VariableMapper mapper, LocalVarTypes lvTypes, SimulatedStack sStack, Collection<LocalVarSlot> newLocals) {
this(mapper, lvTypes, sStack, newLocals, CONDITIONAL);
}

SavedState(LocalVarTypes lvTypes, SimulatedStack sStack, Collection<LocalVarSlot> newLocals, int kind) {
SavedState(VariableMapper mapper,LocalVarTypes lvTypes, SimulatedStack sStack, Collection<LocalVarSlot> newLocals, int kind) {
this.mapper = mapper.mirror();
this.lvTypes = new LocalVarTypes(lvTypes.toArray());
this.sStack = new SimulatedStack(sStack.toArray());
this.newLocals = new HashSet<>(newLocals);
Expand All @@ -339,9 +341,7 @@ private static final class SavedState {

}

private int nextMappedVar = 0;
private int[] mapping = new int[8];

private final VariableMapper variableMapper;
private final SimulatedStack stack = new SimulatedStack();
private final List<Object> locals = new ArrayList<>();
private final Set<LocalVarSlot> newLocals = new HashSet<>(3);
Expand All @@ -364,6 +364,7 @@ public InstrumentingMethodVisitor(int access, String owner, String name, String
this.desc = desc;

initLocals((access & ACC_STATIC) == 0);
this.variableMapper = new VariableMapper(argsSize);
}

@Override
Expand Down Expand Up @@ -542,7 +543,7 @@ public void visitJumpInsn(int opcode, Label label) {
}
}
jumpTargetStates.put(label, new SavedState(
localTypes, stack, newLocals,
variableMapper, localTypes, stack, newLocals,
opcode == Opcodes.GOTO || opcode == Opcodes.JSR ?
SavedState.UNCONDITIONAL : SavedState.CONDITIONAL
)
Expand Down Expand Up @@ -654,7 +655,7 @@ public void visitVarInsn(int opcode, int var) {
break;
}
}
var = remap(var, size);
var = variableMapper.remap(var, size);

boolean isPush = false;
Type opType = null;
Expand Down Expand Up @@ -1150,17 +1151,17 @@ public void visitInsn(int opcode) {

@Override
public void visitIincInsn(final int var, final int increment) {
super.visitIincInsn(remap(var, 1), increment);
super.visitIincInsn(variableMapper.remap(var, 1), increment);
pc++;
}

@Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
int newIndex = map(index);
if (newIndex != 0) {
super.visitLocalVariable(name, desc, signature, start, end, newIndex == Integer.MIN_VALUE ? 0 : Math.abs(newIndex));
int newIndex = variableMapper.map(index);
if (newIndex != 0xFFFFFFFF) {
super.visitLocalVariable(name, desc, signature, start, end, newIndex == Integer.MIN_VALUE ? 0 : newIndex);
}
}

Expand All @@ -1170,9 +1171,9 @@ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath type
int cnt = 0;
int[] newIndex = new int[index.length];
for (int i = 0; i < newIndex.length; ++i) {
int idx = map(index[i]);
if (idx != 0) {
newIndex[cnt++] = idx == Integer.MIN_VALUE ? 0 : Math.abs(idx);
int idx = variableMapper.map(index[i]);
if (idx != 0xFFFFFFFF) {
newIndex[cnt++] = idx;
}
}
return super.visitLocalVariableAnnotation(typeRef, typePath, start, end, Arrays.copyOf(newIndex, cnt), desc, visible);
Expand Down Expand Up @@ -1201,12 +1202,13 @@ public void visitLabel(Label label) {
lvs.expire();
}
}
newLocals.clear();
newLocals.addAll(ss.newLocals);
}
Label handler = tryCatchHandlerMap.get(label);
if (handler != null) {
if (!jumpTargetStates.containsKey(handler)) {
jumpTargetStates.put(handler, new SavedState(localTypes, stack, newLocals, SavedState.EXCEPTION));
jumpTargetStates.put(handler, new SavedState(variableMapper, localTypes, stack, newLocals, SavedState.EXCEPTION));
}
}
super.visitLabel(label);
Expand Down Expand Up @@ -1295,16 +1297,18 @@ public int storeAsNew() {

@Override
public final int newVar(Type t) {
int idx = newVarIdx(t.getSize());
int idx = variableMapper.newVarIdx(t.getSize());

newLocals.add(new LocalVarSlot(idx, toSlotType(t)));
int var = idx == Integer.MIN_VALUE ? 0 : Math.abs(idx);
int var = VariableMapper.unmask(idx == Integer.MIN_VALUE ? 0 : idx);
newLocals.add(new LocalVarSlot(var, toSlotType(t)));

localTypes.setType(var, t);

return idx;
}

private void initLocals(boolean isInstance) {
int nextMappedVar = 0;
if (isInstance) {
locals.add(owner);
nextMappedVar++;
Expand All @@ -1321,6 +1325,7 @@ private void initLocals(boolean isInstance) {

private Object[] computeFrameLocals() {
Object[] localsArr;
int nextMappedVar = variableMapper.getNextMappedVar();
if (nextMappedVar > argsSize) {
int arrSize = Math.max(locals.size(), nextMappedVar);
localsArr = new Object[arrSize];
Expand All @@ -1334,9 +1339,8 @@ private Object[] computeFrameLocals() {
localsArr[++idx] = TOP_EXT;
}
} else {
int var = mapping[idx - argsSize];
if (var < 0) {
var = var == Integer.MIN_VALUE ? 0 : -var;
int var = variableMapper.map(idx);
if (var != 0xFFFFFFFF) {
localsArr[var] = e;
if (e == LONG || e == DOUBLE) {
int off = var + 1;
Expand All @@ -1346,8 +1350,6 @@ private Object[] computeFrameLocals() {
localsArr[off] = TOP_EXT;
idx++;
}
} else {
System.err.println("***");
}
}
idx++;
Expand All @@ -1362,9 +1364,8 @@ private Object[] computeFrameLocals() {
} else {
localsArr = locals.toArray(new Object[0]);
}
for (int m : mapping) {
for (int m : variableMapper.mappings()) {
if (m != 0) {
m = m == Integer.MIN_VALUE ? 0 : Math.abs(m);
if (localsArr[m] == null) {
localsArr[m] = TOP;
}
Expand All @@ -1386,45 +1387,6 @@ private void reset() {
newLocals.clear();
}

private void setMapping(int from, int to, int padding) {
if (mapping.length <= from + padding) {
mapping = Arrays.copyOf(mapping, Math.max(mapping.length * 2, from + padding + 1));
}
mapping[from] = to;
if (padding > 0) {
mapping[from + padding] = Math.abs(to) + padding; // padding
}
}

private int remap(int var, int size) {
int mappedVar = map(var);
if (mappedVar >= 0) {
int offset = var - argsSize;
var = (mappedVar == 0) ? newVarIdx(size) : -mappedVar;
setMapping(offset, var, size - 1);
mappedVar = var;
}
var = mappedVar == Integer.MIN_VALUE ? 0 : Math.abs(mappedVar);
// adjust the mapping pointer if remapping with variable occupying 2 slots
nextMappedVar = Math.max(var + size, nextMappedVar);
return var;
}

private int map(int var) {
if (var < 0) {
return var;
}
int idx = (var - argsSize);
if (idx >= 0) {
if (mapping.length <= idx) {
mapping = Arrays.copyOf(mapping, mapping.length * 2);
return 0;
}
return mapping[idx];
}
return var == 0 ? Integer.MIN_VALUE : -var;
}

private Object peekFromStack() {
Object o = stack.peek();
if (o == null || o == TOP_EXT) {
Expand All @@ -1441,12 +1403,6 @@ private void pushToStack(Type t) {
stack.push(toSlotType(t));
}

private int newVarIdx(int size) {
int var = -nextMappedVar;
nextMappedVar += size;
return var == 0 ? Integer.MIN_VALUE : var;
}

private Type fromSlotType(Object slotType) {
if (slotType == INTEGER) {
return Type.INT_TYPE;
Expand Down
128 changes: 128 additions & 0 deletions src/share/classes/com/sun/btrace/runtime/VariableMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.sun.btrace.runtime;

import java.util.Arrays;

public class VariableMapper {
private static final int UNMASK = 0x1FFFFFFF;
private static final int DOUBLE_SLOT_FLAG = 0x20000000;
private static final int REMAP_FLAG = 0x40000000;

private int argsSize;

private int nextMappedVar = 0;
private int[] mapping = new int[8];

public VariableMapper(int argsSize) {
this.argsSize = argsSize;
this.nextMappedVar = argsSize;
}

private VariableMapper(int argsSize, int nextMappedVar, int[] mapping) {
this.argsSize = argsSize;
this.nextMappedVar = nextMappedVar;
this.mapping = Arrays.copyOf(mapping, mapping.length);
}

public void replaceWith(VariableMapper other) {
this.argsSize = other.argsSize;
this.nextMappedVar = other.nextMappedVar;
this.mapping = Arrays.copyOf(other.mapping, other.mapping.length);
}

public VariableMapper mirror() {
return new VariableMapper(argsSize, nextMappedVar, mapping);
}

public void setMapping(int from, int to, int size) {
int padding = size == 1 ? 0 : 1;
if (mapping.length <= from + padding) {
mapping = Arrays.copyOf(mapping, Math.max(mapping.length * 2, from + padding + 1));
}
mapping[from] = to;
if (padding > 0) {
mapping[from + padding] = Math.abs(to) + padding; // padding
}
}

public int remap(int var, int size) {
if ((var & REMAP_FLAG) != 0) {
return var & UNMASK;
}

int offset = var - argsSize;
if (offset < 0) {
// self projection for method arguments
return var;
}
if (offset >= mapping.length) {
mapping = Arrays.copyOf(mapping, mapping.length * 2);
}
int mappedVar = mapping[offset];

boolean isRemapped = ((mappedVar & REMAP_FLAG) != 0);
if (size == 2) {
if ((mappedVar & DOUBLE_SLOT_FLAG) == 0) {
// no double slot mapping; must re-map
isRemapped = false;
}
}
if (!isRemapped) {
mappedVar = remapVar(newVarIdxInternal(size), size);
setMapping(offset, mappedVar, size);
}
int unmasked = mappedVar & UNMASK;
// adjust the mapping pointer if remapping with variable occupying 2 slots
nextMappedVar = Math.max(unmasked + size, nextMappedVar);
return unmasked;
}

public int map(int var) {
if (((var & REMAP_FLAG) != 0)) {
return var & UNMASK;
}

int offset = (var - argsSize);
if (offset >= 0) {
if (mapping.length <= offset) {
return 0xFFFFFFFF;
}
return mapping[offset] & UNMASK;
}
return var;
}

public int[] mappings() {
int[] cleansed = new int[mapping.length];
for (int i = 0; i < mapping.length; i++) {
cleansed[i] = mapping[i] & UNMASK;
}
return cleansed;
}

private int newVarIdxInternal(int size) {
int var = nextMappedVar;
nextMappedVar += size;
return var == 0 ? Integer.MIN_VALUE : var;
}

private int remapVar(int var, int size) {
int mappedVar = var | REMAP_FLAG;
if (size == 2) {
mappedVar = mappedVar | DOUBLE_SLOT_FLAG;
}
return mappedVar;
}

public int newVarIdx(int size) {
int var = newVarIdxInternal(size);
return remapVar(var, size);
}

public int getNextMappedVar() {
return nextMappedVar;
}

public static int unmask(int var) {
return var & UNMASK;
}
}
2 changes: 1 addition & 1 deletion src/test/java/com/sun/btrace/runtime/BTRACE28Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void bytecodeValidation() throws Exception {
"ASTORE 6\n" +
"ASTORE 7\n" +
"ALOAD 7\n" +
"FRAME FULL [resources/issues/BTRACE28 java/lang/String java/lang/String java/lang/String java/lang/String [B [B java/lang/StringBuilder] [java/lang/Throwable]\n" +
"FRAME FULL [T java/lang/String java/lang/String java/lang/String java/lang/String [B [B java/lang/StringBuilder] [java/lang/Throwable]\n" +
"ASTORE 8\n" +
"ALOAD 8\n" +
"FRAME APPEND [T]\n" +
Expand Down
13 changes: 13 additions & 0 deletions src/test/java/com/sun/btrace/runtime/BTRACE333Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.sun.btrace.runtime;

import org.junit.Test;

public class BTRACE333Test extends InstrumentorTestBase {
@Test
public void stackmapErrorTest() throws Exception {
originalBC = loadTargetClass("classdata/BackpackExtensionTest");
transform("issues/BTRACE_333");
checkTransformation("");

}
}
Loading

0 comments on commit 587730f

Please sign in to comment.