com.googlecode.d2j.dex.writer.CodeWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle Show documentation
Show all versions of gradle Show documentation
fakeradnroid gradle builder
/*
* dex2jar - Tools to work with android .dex and java .class files
* Copyright (c) 2009-2013 Panxiaobo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.googlecode.d2j.dex.writer;
import com.googlecode.d2j.DexLabel;
import com.googlecode.d2j.Field;
import com.googlecode.d2j.Method;
import com.googlecode.d2j.dex.writer.insn.*;
import com.googlecode.d2j.dex.writer.item.*;
import com.googlecode.d2j.reader.Op;
import com.googlecode.d2j.visitors.DexCodeVisitor;
import com.googlecode.d2j.visitors.DexDebugVisitor;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;
import static com.googlecode.d2j.reader.InstructionFormat.*;
import static com.googlecode.d2j.reader.Op.*;
@SuppressWarnings("incomplete-switch")
public class CodeWriter extends DexCodeVisitor {
final CodeItem codeItem;
final ConstPool cp;
ByteBuffer b = ByteBuffer.allocate(10).order(ByteOrder.LITTLE_ENDIAN);
int in_reg_size = 0;
int max_out_reg_size = 0;
List ops = new ArrayList<>();
List tailOps = new ArrayList<>();
int total_reg;
List tryItems = new ArrayList<>();
Method owner;
Map labelMap = new HashMap<>();
ClassDataItem.EncodedMethod encodedMethod;
public CodeWriter(ClassDataItem.EncodedMethod encodedMethod, CodeItem codeItem, Method owner, boolean isStatic, ConstPool cp) {
this.encodedMethod = encodedMethod;
this.codeItem = codeItem;
this.owner = owner;
int in_reg_size = 0;
if (!isStatic) {
in_reg_size++;
}
for (String s : owner.getParameterTypes()) {
switch (s.charAt(0)) {
case 'J':
case 'D':
in_reg_size += 2;
break;
default:
in_reg_size++;
break;
}
}
this.in_reg_size = in_reg_size;
this.cp = cp;
}
public static void checkContentByte(Op op, String cc, int v) {
if (v > Byte.MAX_VALUE || v < Byte.MIN_VALUE) {
throw new CantNotFixContentException(op, cc, v);
}
}
public static void checkContentS4bit(Op op, String name, int v) {
if (v > 7 || v < -8) { // TODO check
throw new CantNotFixContentException(op, name, v);
}
}
public static void checkContentShort(Op op, String cccc, int v) {
if (v > Short.MAX_VALUE || v < Short.MIN_VALUE) {
throw new CantNotFixContentException(op, cccc, v);
}
}
public static void checkContentU4bit(Op op, String name, int v) {
if (v > 15 || v < 0) {
throw new CantNotFixContentException(op, name, v);
}
}
public static void checkContentUByte(Op op, String cc, int v) {
if (v > 0xFF || v < 0) {
throw new CantNotFixContentException(op, cc, v);
}
}
public static void checkContentUShort(Op op, String cccc, int v) {
if (v > 0xFFFF || v < 0) {
throw new CantNotFixContentException(op, cccc, v);
}
}
public static void checkRegA(Op op, String s, int reg) {
if (reg > 0xF || reg < 0) {
throw new CantNotFixContentException(op, s, reg);
}
}
public static void checkRegAA(Op op, String s, int reg) {
if (reg > 0xFF || reg < 0) {
throw new CantNotFixContentException(op, s, reg);
}
}
static void checkRegAAAA(Op op, String s, int reg) {
if (reg > 0xFFFF || reg < 0) {
throw new CantNotFixContentException(op, s, reg);
}
}
static byte[] copy(ByteBuffer b) {
int size = b.position();
byte[] data = new byte[size];
System.arraycopy(b.array(), 0, data, 0, size);
return data;
}
public void add(Insn insn) {
ops.add(insn);
}
private byte[] build10x(Op op) {
b.position(0);
b.put((byte) op.opcode).put((byte) 0);
return copy(b);
}
// B|A|op
private byte[] build11n(Op op, int vA, int B) {
checkRegA(op, "vA", vA);
checkContentS4bit(op, "#+B", B);
b.position(0);
b.put((byte) op.opcode).put((byte) ((vA & 0xF) | (B << 4)));
return copy(b);
}
// AA|op
private byte[] build11x(Op op, int vAA) {
checkRegAA(op, "vAA", vAA);
b.position(0);
b.put((byte) op.opcode).put((byte) vAA);
return copy(b);
}
// B|A|op
private byte[] build12x(Op op, int vA, int vB) {
checkRegA(op, "vA", vA);
checkRegA(op, "vB", vB);
b.position(0);
b.put((byte) op.opcode).put((byte) ((vA & 0xF) | (vB << 4)));
return copy(b);
}
// AA|op BBBB
private byte[] build21h(Op op, int vAA, Number value) {
checkRegAA(op, "vAA", vAA);
int realV;
if (op == CONST_HIGH16) { // op vAA, #+BBBB0000
int v = ((Number) value).intValue();
if ((v & 0xFFFF) != 0) {
throw new CantNotFixContentException(op, "#+BBBB0000", v);
}
realV = v >> 16;
} else { // CONST_WIDE_HIGH16 //op vAA, #+BBBB000000000000
long v = ((Number) value).longValue();
if ((v & 0x0000FFFFffffFFFFL) != 0) {
throw new CantNotFixContentException(op, "#+BBBB000000000000", v);
}
realV = (int) (v >> 48);
}
b.position(0);
b.put((byte) op.opcode).put((byte) vAA).putShort((short) realV);
return copy(b);
}
// AA|op BBBB
private byte[] build21s(Op op, int vAA, Number value) {
checkRegAA(op, "vAA", vAA);
int realV;
if (op == CONST_16) {
realV = value.intValue();
checkContentShort(op, "#+BBBB", realV);
} else {// CONST_WIDE_16
long v = value.longValue();
if (v > Short.MAX_VALUE || v < Short.MIN_VALUE) {
throw new CantNotFixContentException(op, "#+BBBB", v);
}
realV = (int) v;
}
b.position(0);
b.put((byte) op.opcode).put((byte) vAA).putShort((short) realV);
return copy(b);
}
// AA|op CC|BB
private byte[] build22b(Op op, int vAA, int vBB, int cc) {
checkRegAA(op, "vAA", vAA);
checkRegAA(op, "vBB", vBB);
checkContentByte(op, "#+CC", cc);
b.position(0);
b.put((byte) op.opcode).put((byte) vAA).put((byte) vBB).put((byte) cc);
return copy(b);
}
// B|A|op CCCC
private byte[] build22s(Op op, int A, int B, int CCCC) {
checkRegA(op, "vA", A);
checkRegA(op, "vB", B);
checkContentShort(op, "+CCCC", CCCC);
b.position(0);
b.put((byte) op.opcode).put((byte) ((A & 0xF) | (B << 4))).putShort((short) CCCC);
return copy(b);
}
// AA|op BBBB
private byte[] build22x(Op op, int vAA, int vBBBB) {
checkRegAA(op, "vAA", vAA);
checkRegAAAA(op, "vBBBB", vBBBB);
b.position(0);
b.put((byte) op.opcode).put((byte) vAA).putShort((short) vBBBB);
return copy(b);
}
// AA|op CC|BB
private byte[] build23x(Op op, int vAA, int vBB, int vCC) {
checkRegAA(op, "vAA", vAA);
checkRegAA(op, "vBB", vBB);
checkRegAA(op, "vCC", vCC);
b.position(0);
b.put((byte) op.opcode).put((byte) vAA).put((byte) vBB).put((byte) vCC);
return copy(b);
}
// AA|op BBBBlo BBBBhi
private byte[] build31i(Op op, int vAA, Number value) {
checkRegAA(op, "vAA", vAA);
int realV;
if (op == CONST) {
realV = value.intValue();
} else if (op == CONST_WIDE_32) {
long v = value.longValue();
if (v > Integer.MAX_VALUE || v < Integer.MIN_VALUE) {
throw new CantNotFixContentException(op, "#+BBBBBBBB", v);
}
realV = (int) v;
} else {
throw new RuntimeException();
}
b.position(0);
b.put((byte) op.opcode).put((byte) vAA).putInt(realV);
return copy(b);
}
// ØØ|op AAAA BBBB
private byte[] build32x(Op op, int vAAAA, int vBBBB) {
checkRegAAAA(op, "vAAAA", vAAAA);
checkRegAAAA(op, "vBBBB", vBBBB);
b.position(0);
b.put((byte) op.opcode).put((byte) 0).putShort((short) vAAAA).putShort((short) vBBBB);
return copy(b);
}
// AA|op BBBBlo BBBB BBBB BBBBhi
private byte[] build51l(Op op, int vAA, Number value) {
checkRegAA(op, "vAA", vAA);
b.position(0);
b.put((byte) op.opcode).put((byte) vAA).putLong(value.longValue());
return copy(b);
}
Label getLabel(DexLabel label) {
Label mapped = labelMap.get(label);
if (mapped == null) {
mapped = new Label();
labelMap.put(label, mapped);
}
return mapped;
}
@Override
public void visitFillArrayDataStmt(Op op, int ra, Object value) {
ByteBuffer b;
if (value instanceof byte[]) {
byte[] data = (byte[]) value;
int size = data.length;
int element_width = 1;
b = ByteBuffer.allocate(((size * element_width + 1) / 2 + 4) * 2).order(ByteOrder.LITTLE_ENDIAN);
b.putShort((short) 0x0300);
b.putShort((short) element_width);
b.putInt(size);
b.put(data);
} else if (value instanceof short[]) {
short[] data = (short[]) value;
int size = data.length;
int element_width = 2;
b = ByteBuffer.allocate(((size * element_width + 1) / 2 + 4) * 2).order(ByteOrder.LITTLE_ENDIAN);
b.putShort((short) 0x0300);
b.putShort((short) element_width);
b.putInt(size);
for (short s : data) {
b.putShort(s);
}
} else if (value instanceof int[]) {
int[] data = (int[]) value;
int size = data.length;
int element_width = 4;
b = ByteBuffer.allocate(((size * element_width + 1) / 2 + 4) * 2).order(ByteOrder.LITTLE_ENDIAN);
b.putShort((short) 0x0300);
b.putShort((short) element_width);
b.putInt(size);
for (int s : data) {
b.putInt(s);
}
} else if (value instanceof float[]) {
float[] data = (float[]) value;
int size = data.length;
int element_width = 4;
b = ByteBuffer.allocate(((size * element_width + 1) / 2 + 4) * 2).order(ByteOrder.LITTLE_ENDIAN);
b.putShort((short) 0x0300);
b.putShort((short) element_width);
b.putInt(size);
for (float s : data) {
b.putInt(Float.floatToIntBits(s));
}
} else if (value instanceof long[]) {
long[] data = (long[]) value;
int size = data.length;
int element_width = 8;
b = ByteBuffer.allocate(((size * element_width + 1) / 2 + 4) * 2).order(ByteOrder.LITTLE_ENDIAN);
b.putShort((short) 0x0300);
b.putShort((short) element_width);
b.putInt(size);
for (long s : data) {
b.putLong(s);
}
} else if (value instanceof double[]) {
double[] data = (double[]) value;
int size = data.length;
int element_width = 8;
b = ByteBuffer.allocate(((size * element_width + 1) / 2 + 4) * 2).order(ByteOrder.LITTLE_ENDIAN);
b.putShort((short) 0x0300);
b.putShort((short) element_width);
b.putInt(size);
for (double s : data) {
b.putLong(Double.doubleToLongBits(s));
}
} else {
throw new RuntimeException();
}
Label d = new Label();
ops.add(new JumpOp(op, ra, 0, d));
tailOps.add(d);
tailOps.add(new PreBuildInsn(b.array()));
}
/**
* kFmt21c,kFmt31c,kFmt11n,kFmt21h,kFmt21s,kFmt31i,kFmt51l
*
* @param op
* @param ra
* @param value
*/
@Override
public void visitConstStmt(Op op, int ra, Object value) {
switch (op.format) {
case kFmt21c:// value is field,type,string
case kFmt31c:// value is string,
value = cp.wrapEncodedItem(value);
ops.add(new IndexedInsn(op, ra, 0, (BaseItem) value));
break;
case kFmt11n:
ops.add(new PreBuildInsn(build11n(op, ra, ((Number) value).intValue())));
break;
case kFmt21h:
ops.add(new PreBuildInsn(build21h(op, ra, ((Number) value))));
break;
case kFmt21s:
ops.add(new PreBuildInsn(build21s(op, ra, ((Number) value))));
break;
case kFmt31i:
ops.add(new PreBuildInsn(build31i(op, ra, ((Number) value))));
break;
case kFmt51l:
ops.add(new PreBuildInsn(build51l(op, ra, ((Number) value))));
break;
}
}
@Override
public void visitEnd() {
if (ops.size() == 0 && tailOps.size() == 0) {
encodedMethod.code = null;
return;
}
cp.addCodeItem(codeItem);
codeItem.registersSize = this.total_reg;
codeItem.outsSize = max_out_reg_size;
codeItem.insSize = in_reg_size;
codeItem.init(ops, tailOps, tryItems);
if (codeItem.debugInfo != null) {
cp.addDebugInfoItem(codeItem.debugInfo);
List debugNodes = codeItem.debugInfo.debugNodes;
Collections.sort(debugNodes, new Comparator() {
@Override
public int compare(DebugInfoItem.DNode o1, DebugInfoItem.DNode o2) {
int x = o1.label.offset - o2.label.offset;
// if (x == 0) {
// if (o1.op == o2.op) {
// x = o1.reg - o2.reg;
// if (x == 0) {
// x = o1.line - o2.line;
// }
// } else {
// //
// }
// }
return x;
}
});
}
ops = null;
tailOps = null;
tryItems = null;
}
@Override
public void visitFieldStmt(Op op, int a, int b, Field field) {
ops.add(new IndexedInsn(op, a, b, cp.uniqField(field)));
}
@Override
public void visitFilledNewArrayStmt(Op op, int[] args, String type) {
if (op.format == kFmt35c) {
ops.add(new OP35c(op, args, cp.uniqType(type)));
} else {
ops.add(new OP3rc(op, args, cp.uniqType(type)));
}
}
@Override
public void visitJumpStmt(Op op, int a, int b, DexLabel label) {
ops.add(new JumpOp(op, a, b, getLabel(label)));
}
@Override
public void visitLabel(DexLabel label) {
ops.add(getLabel(label));
}
@Override
public void visitMethodStmt(Op op, int[] args, Method method) {
if (op.format == kFmt3rc) {
ops.add(new OP3rc(op, args, cp.uniqMethod(method)));
} else if (op.format == kFmt35c) {
ops.add(new OP35c(op, args, cp.uniqMethod(method)));
}
if (args.length > max_out_reg_size) {
max_out_reg_size = args.length;
}
}
@Override
public void visitPackedSwitchStmt(Op op, int aA, final int first_case, final DexLabel[] labels) {
Label switch_data_location = new Label();
final JumpOp jumpOp = new JumpOp(op, aA, 0, switch_data_location);
ops.add(jumpOp);
tailOps.add(switch_data_location);
tailOps.add(new Insn() {
@Override
public int getCodeUnitSize() {
return (labels.length * 2) + 4;
}
@Override
public void write(ByteBuffer out) {
out.putShort((short) 0x0100).putShort((short) labels.length).putInt(first_case);
for (int i = 0; i < labels.length; i++) {
out.putInt(getLabel(labels[i]).offset - jumpOp.offset);
}
}
});
}
@Override
public void visitRegister(int total) {
this.total_reg = total;
}
@Override
public void visitSparseSwitchStmt(Op op, int ra, final int[] cases, final DexLabel[] labels) {
Label switch_data_location = new Label();
final JumpOp jumpOp = new JumpOp(op, ra, 0, switch_data_location);
ops.add(jumpOp);
tailOps.add(switch_data_location);
tailOps.add(new Insn() {
@Override
public int getCodeUnitSize() {
return (cases.length * 4) + 2;
}
@Override
public void write(ByteBuffer out) {
out.putShort((short) 0x0200).putShort((short) cases.length);
for (int i = 0; i < cases.length; i++) {
out.putInt(cases[i]);
}
for (int i = 0; i < cases.length; i++) {
out.putInt(getLabel(labels[i]).offset - jumpOp.offset);
}
}
});
}
@Override
public void visitStmt0R(Op op) {
if (op == BAD_OP) {
// TODO check
} else {
if (op.format == kFmt10x) {
ops.add(new PreBuildInsn(build10x(op)));
} else {
// FIXME error
}
}
}
/**
* kFmt11x
*
* @param op
* @param reg
*/
@Override
public void visitStmt1R(Op op, int reg) {
if (op.format == kFmt11x) {
ops.add(new PreBuildInsn(build11x(op, reg)));
} else {
}
}
/**
* kFmt12x,kFmt22x,kFmt32x
*
* @param op
* @param a
* @param b
*/
@Override
public void visitStmt2R(Op op, int a, int b) {
switch (op.format) {
case kFmt12x:
ops.add(new PreBuildInsn(build12x(op, a, b)));
break;
case kFmt22x:
ops.add(new PreBuildInsn(build22x(op, a, b)));
break;
case kFmt32x:
ops.add(new PreBuildInsn(build32x(op, a, b)));
break;
}
}
/**
* Only kFmt22s, kFmt22b
*
* @param op
* @param distReg
* @param srcReg
* @param content
*/
@Override
public void visitStmt2R1N(Op op, int distReg, int srcReg, int content) {
if (op.format == kFmt22s) {
ops.add(new PreBuildInsn(build22s(op, distReg, srcReg, content)));
} else if (op.format == kFmt22b) {
ops.add(new PreBuildInsn(build22b(op, distReg, srcReg, content)));
} else {
}
}
/**
* kFmt23x
*
* @param op
* @param a
* @param b
* @param c
*/
@Override
public void visitStmt3R(Op op, int a, int b, int c) {
if (op.format == kFmt23x) {
ops.add(new PreBuildInsn(build23x(op, a, b, c)));
} else {
}
}
@Override
public void visitTryCatch(DexLabel start, DexLabel end, DexLabel[] handlers, String[] types) {
CodeItem.TryItem tryItem = new CodeItem.TryItem();
tryItem.start = getLabel(start);
tryItem.end = getLabel(end);
CodeItem.EncodedCatchHandler ech = new CodeItem.EncodedCatchHandler();
tryItem.handler = ech;
tryItems.add(tryItem);
ech.addPairs = new ArrayList<>(types.length);
for (int i = 0; i < types.length; i++) {
String type = types[i];
Label label = getLabel(handlers[i]);
if (type == null) {
ech.catchAll = label;
} else {
ech.addPairs.add(new CodeItem.EncodedCatchHandler.AddrPair(cp.uniqType(type), label));
}
}
}
@Override
public void visitTypeStmt(Op op, int a, int b, String type) {
ops.add(new IndexedInsn(op, a, b, cp.uniqType(type)));
}
public static class IndexedInsn extends OpInsn {
final int a, b;
final BaseItem idxItem;
public IndexedInsn(Op op, int a, int b, BaseItem idxItem) {
super(op);
switch (op.format) {
case kFmt21c:
case kFmt31c:
checkRegAA(op, "vAA", a);
break;
case kFmt22c:
checkContentU4bit(op, "A", a);
checkContentU4bit(op, "B", b);
break;
}
this.a = a;
this.b = b;
this.idxItem = idxItem;
}
// 21c AA|op BBBB
// 31c AA|op BBBBlo BBBBhi
// 22c B|A|op CCCC
@Override
public void write(ByteBuffer out) {
out.put((byte) op.opcode);
switch (op.format) {
case kFmt21c:
checkContentUShort(op, "?@BBBB", idxItem.index);
out.put((byte) a).putShort((short) idxItem.index);
break;
case kFmt31c:
out.put((byte) a).putInt(idxItem.index);
break;
case kFmt22c: // B|A|op CCCC
checkContentUShort(op, "?@CCCC", idxItem.index);
out.put((byte) ((a & 0xF) | (b << 4))).putShort((short) idxItem.index);
break;
}
}
public void fit() {
if (op == CONST_STRING && (idxItem.index > 0xFFFF || idxItem.index < 0)) {
op = CONST_STRING_JUMBO;
}
}
}
public static class OP35c extends OpInsn {
final BaseItem item;
int A, C, D, E, F, G;
public OP35c(Op op, int[] args, BaseItem item) {
super(op);
int A = args.length;
if (A > 5) {
throw new CantNotFixContentException(op, "A", A);
}
this.A = A;
switch (A) { // [A=5] op {vC, vD, vE, vF, vG},
case 5:
G = args[4];
checkContentU4bit(op, "vG", G);
case 4:
F = args[3];
checkContentU4bit(op, "vF", F);
case 3:
E = args[2];
checkContentU4bit(op, "vE", E);
case 2:
D = args[1];
checkContentU4bit(op, "vD", D);
case 1:
C = args[0];
checkContentU4bit(op, "vC", C);
break;
}
this.item = item;
}
@Override
public void write(ByteBuffer out) { // A|G|op BBBB F|E|D|C
checkContentUShort(op, "@BBBB", item.index);
out.put((byte) op.opcode).put((byte) ((A << 4) | (G & 0xF))).putShort((short) item.index)
.put((byte) ((D << 4) | (C & 0xF))).put((byte) ((F << 4) | (E & 0xF)));
}
}
// AA|op BBBB CCCC
public static class OP3rc extends OpInsn {
final BaseItem item;
final int length;
final int start;
public OP3rc(Op op, int[] args, BaseItem item) {
super(op);
this.item = item;
length = args.length;
checkContentUByte(op, "AA", length);
if (length > 0) {
start = args[0];
checkContentUShort(op, "CCCC", start);
for (int i = 1; i < args.length; i++) {
if (start + i != args[i]) {
throw new CantNotFixContentException(op, "a", args[i]);
}
}
} else {
start = 0;
}
}
@Override
public void write(ByteBuffer out) {
checkContentUShort(op, "@BBBB", item.index);
out.put((byte) op.opcode).put((byte) length).putShort((short) item.index).putShort((short) start);
}
}
@Override
public DexDebugVisitor visitDebug() {
if (codeItem.debugInfo == null) {
codeItem.debugInfo = new DebugInfoItem();
codeItem.debugInfo.parameterNames=new StringIdItem[owner.getParameterTypes().length];
}
final DebugInfoItem debugInfoItem = codeItem.debugInfo;
return new DexDebugVisitor() {
@Override
public void visitParameterName(int parameterIndex, String name) {
if (name == null) {
return;
}
if (parameterIndex >= debugInfoItem.parameterNames.length) {
return;
}
debugInfoItem.parameterNames[parameterIndex] = cp.uniqString(name);
}
@Override
public void visitStartLocal(int reg, DexLabel label, String name, String type, String signature) {
if (signature == null) {
debugInfoItem.debugNodes.add(DebugInfoItem.DNode.startLocal(reg, getLabel(label),
cp.uniqString(name), cp.uniqType(type)));
} else {
debugInfoItem.debugNodes.add(DebugInfoItem.DNode.startLocalEx(reg, getLabel(label),
cp.uniqString(name), cp.uniqType(type), cp.uniqString(signature)));
}
}
int miniLine = 0;
@Override
public void visitLineNumber(int line, DexLabel label) {
if ((0x00000000FFFFffffL & line) < miniLine) {
miniLine = line;
}
debugInfoItem.debugNodes.add(DebugInfoItem.DNode.line(line, getLabel(label)));
}
@Override
public void visitPrologue(DexLabel dexLabel) {
debugInfoItem.debugNodes.add(DebugInfoItem.DNode.prologue( getLabel(dexLabel)));
}
@Override
public void visitEpiogue(DexLabel dexLabel) {
debugInfoItem.debugNodes.add(DebugInfoItem.DNode.epiogue( getLabel(dexLabel)));
}
@Override
public void visitEndLocal(int reg, DexLabel label) {
debugInfoItem.debugNodes.add(DebugInfoItem.DNode.endLocal(reg, getLabel(label)));
}
@Override
public void visitSetFile(String file) {
debugInfoItem.fileName = cp.uniqString(file);
}
@Override
public void visitRestartLocal(int reg, DexLabel label) {
debugInfoItem.debugNodes.add(DebugInfoItem.DNode.restartLocal(reg, getLabel(label)));
}
@Override
public void visitEnd() {
debugInfoItem.firstLine = miniLine;
}
};
}
}