ASM 4.0 소스 코드 통독 의 3 readCode 방법 분석 방법 코드
private void readCode(final MethodVisitor mv, final Context context, int u) {
// reads the header
byte[] b = this.b;
char[] c = context.buffer;// buffer maxStringLength
int maxStack = readUnsignedShort(u);//maxStack
int maxLocals = readUnsignedShort(u + 2);//max locals
int codeLength = readInt(u + 4);//
u += 8;
// reads the bytecode to find the labels
int codeStart = u;
int codeEnd = u + codeLength;
Label[] labels = context.labels = new Label[codeLength + 2];// +2?
readLabel(codeLength + 1, labels);
while (u < codeEnd) {
int offset = u - codeStart;
int opcode = b[u] & 0xFF;
switch (ClassWriter.TYPE[opcode]) {
case ClassWriter.NOARG_INSN:
case ClassWriter.IMPLVAR_INSN:
u += 1;
break;
case ClassWriter.LABEL_INSN:
readLabel(offset + readShort(u + 1), labels);
u += 3;
break;
case ClassWriter.LABELW_INSN:
readLabel(offset + readInt(u + 1), labels);
u += 5;
break;
case ClassWriter.WIDE_INSN:
opcode = b[u + 1] & 0xFF;
if (opcode == Opcodes.IINC) {
u += 6;
} else {
u += 4;
}
break;
case ClassWriter.TABL_INSN:
// skips 0 to 3 padding bytes
u = u + 4 - (offset & 3);
// reads instruction
readLabel(offset + readInt(u), labels);
for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) {
readLabel(offset + readInt(u + 12), labels);
u += 4;
}
u += 12;
break;
case ClassWriter.LOOK_INSN:
// skips 0 to 3 padding bytes
u = u + 4 - (offset & 3);
// reads instruction
readLabel(offset + readInt(u), labels);
for (int i = readInt(u + 4); i > 0; --i) {
readLabel(offset + readInt(u + 12), labels);
u += 8;
}
u += 8;
break;
case ClassWriter.VAR_INSN:
case ClassWriter.SBYTE_INSN:
case ClassWriter.LDC_INSN:
u += 2;
break;
case ClassWriter.SHORT_INSN:
case ClassWriter.LDCW_INSN:
case ClassWriter.FIELDORMETH_INSN:
case ClassWriter.TYPE_INSN:
case ClassWriter.IINC_INSN:
u += 3;
break;
case ClassWriter.ITFMETH_INSN:
case ClassWriter.INDYMETH_INSN:
u += 5;
break;
// case MANA_INSN:
default:
u += 4;
break;
}
}
// reads the try catch entries to find the labels, and also visits them
for (int i = readUnsignedShort(u); i > 0; --i) {
Label start = readLabel(readUnsignedShort(u + 2), labels);
Label end = readLabel(readUnsignedShort(u + 4), labels);
Label handler = readLabel(readUnsignedShort(u + 6), labels);
String type = readUTF8(items[readUnsignedShort(u + 8)], c);
mv.visitTryCatchBlock(start, end, handler, type);
u += 8;
}
u += 2;
// reads the code attributes
int[] tanns = null; // start index of each visible type annotation
int[] itanns = null; // start index of each invisible type annotation
int tann = 0; // current index in tanns array
int itann = 0; // current index in itanns array
int ntoff = -1; // next visible type annotation code offset
int nitoff = -1; // next invisible type annotation code offset
int varTable = 0;
int varTypeTable = 0;
boolean zip = true;
boolean unzip = (context.flags & EXPAND_FRAMES) != 0;
int stackMap = 0;
int stackMapSize = 0;
int frameCount = 0;
Context frame = null;
Attribute attributes = null;
for (int i = readUnsignedShort(u); i > 0; --i) {
String attrName = readUTF8(u + 2, c);
if ("LocalVariableTable".equals(attrName)) {
if ((context.flags & SKIP_DEBUG) == 0) {
varTable = u + 8;
for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
int label = readUnsignedShort(v + 10);
if (labels[label] == null) {
readLabel(label, labels).status |= Label.DEBUG;
}
label += readUnsignedShort(v + 12);
if (labels[label] == null) {
readLabel(label, labels).status |= Label.DEBUG;
}
v += 10;
}
}
} else if ("LocalVariableTypeTable".equals(attrName)) {
varTypeTable = u + 8;
} else if ("LineNumberTable".equals(attrName)) {
if ((context.flags & SKIP_DEBUG) == 0) {
for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
int label = readUnsignedShort(v + 10);
if (labels[label] == null) {
readLabel(label, labels).status |= Label.DEBUG;
}
labels[label].line = readUnsignedShort(v + 12);
v += 4;
}
}
} else if (ANNOTATIONS
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = readTypeAnnotations(mv, context, u + 8, true);
ntoff = tann >= tanns.length
|| readUnsignedShort(tanns[tann]) < 0x86 ? -1
: readUnsignedShort(tanns[tann] + 2);
} else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = readTypeAnnotations(mv, context, u + 8, false);
nitoff = itann >= itanns.length
|| readUnsignedShort(itanns[itann]) < 0x86 ? -1
: readUnsignedShort(itanns[itann] + 2);
} else if (FRAMES && "StackMapTable".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) {
stackMap = u + 10;//stackMap stack_map_frame entries,10 = attribute_count(u2)、attribute_name_index(u2)、attribute_length(u4)、number_of_entries(u2)
stackMapSize = readInt(u + 4);//stackMapSize attribute_length
frameCount = readUnsignedShort(u + 8);//
}
/*
* here we do not extract the labels corresponding to the
* attribute content. This would require a full parsing of the
* attribute, which would need to be repeated in the second
* phase (see below). Instead the content of the attribute is
* read one frame at a time (i.e. after a frame has been
* visited, the next frame is read), and the labels it contains
* are also extracted one frame at a time. Thanks to the
* ordering of frames, having only a "one frame lookahead" is
* not a problem, i.e. it is not possible to see an offset
* smaller than the offset of the current insn and for which no
* Label exist.
*/
/*
* This is not true for UNINITIALIZED type offsets. We solve
* this by parsing the stack map table without a full decoding
* (see below).
*/
} else if (FRAMES && "StackMap".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) {
zip = false;
stackMap = u + 10;
stackMapSize = readInt(u + 4);
frameCount = readUnsignedShort(u + 8);
}
/*
* IMPORTANT! here we assume that the frames are ordered, as in
* the StackMapTable attribute, although this is not guaranteed
* by the attribute format.
*/
} else {
for (int j = 0; j < context.attrs.length; ++j) {
if (context.attrs[j].type.equals(attrName)) {
Attribute attr = context.attrs[j].read(this, u + 8,
readInt(u + 4), c, codeStart - 8, labels);
if (attr != null) {
attr.next = attributes;
attributes = attr;
}
}
}
}
u += 6 + readInt(u + 4);
}
u += 2;
// generates the first (implicit) stack map frame
if (FRAMES && (stackMap != 0 || unzip)) {
/*
* for the first explicit frame the offset is not offset_delta + 1
* but only offset_delta; setting the implicit frame offset to -1
* allow the use of the "offset_delta + 1" rule in all cases
*/
frame = context;
frame.offset = -1;
frame.mode = 0;
frame.localCount = 0;
frame.localDiff = 0;
frame.stackCount = 0;
frame.local = new Object[maxLocals];
frame.stack = new Object[maxStack];
if (unzip) {
getImplicitFrame(context);
}
}
if (FRAMES && stackMap != 0) {
/*
* Finds labels for UNINITIALIZED frame types. Instead of decoding
* each element of the stack map table, we look for 3 consecutive
* bytes that "look like" an UNINITIALIZED type (tag 8, offset
* within code bounds, NEW instruction at this offset). We may find
* false positives (i.e. not real UNINITIALIZED types), but this
* should be rare, and the only consequence will be the creation of
* an unneeded label. This is better than creating a label for each
* NEW instruction, and faster than fully decoding the whole stack
* map table.
*/
for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) {
if (b[i] == 8) { // UNINITIALIZED FRAME TYPE
int v = readUnsignedShort(i + 1);
if (v >= 0 && v < codeLength) {
if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) {
readLabel(v, labels);
}
}
}
}
}
// visits the instructions
u = codeStart;
while (u < codeEnd) {
int offset = u - codeStart;
// visits the label and line number for this offset, if any
Label l = labels[offset];
if (l != null) {
mv.visitLabel(l);
if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) {
mv.visitLineNumber(l.line, l);
}
}
// visits the frame(s) for this offset, if any
while (FRAMES && frame != null
&& (frame.offset == offset || frame.offset == -1)) {
// if there is a frame for this offset, makes the visitor visit
// it, and reads the next frame if there is one.
if (!zip || unzip) {
mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local,
frame.stackCount, frame.stack);
} else if (frame.offset != -1) {
mv.visitFrame(frame.mode, frame.localDiff, frame.local,
frame.stackCount, frame.stack);
}
if (frameCount > 0) {
stackMap = readFrame(stackMap, zip, unzip, frame);
--frameCount;
} else {
frame = null;
}
}
// visits the instruction at this offset
int opcode = b[u] & 0xFF;
switch (ClassWriter.TYPE[opcode]) {
case ClassWriter.NOARG_INSN:
mv.visitInsn(opcode);
u += 1;
break;
case ClassWriter.IMPLVAR_INSN:
if (opcode > Opcodes.ISTORE) {
opcode -= 59; // ISTORE_0
mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2),
opcode & 0x3);
} else {
opcode -= 26; // ILOAD_0
mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
}
u += 1;
break;
case ClassWriter.LABEL_INSN:
mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]);
u += 3;
break;
case ClassWriter.LABELW_INSN:
mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]);
u += 5;
break;
case ClassWriter.WIDE_INSN:
opcode = b[u + 1] & 0xFF;
if (opcode == Opcodes.IINC) {
mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4));
u += 6;
} else {
mv.visitVarInsn(opcode, readUnsignedShort(u + 2));
u += 4;
}
break;
case ClassWriter.TABL_INSN: {
// skips 0 to 3 padding bytes
u = u + 4 - (offset & 3);
// reads instruction
int label = offset + readInt(u);
int min = readInt(u + 4);
int max = readInt(u + 8);
Label[] table = new Label[max - min + 1];
u += 12;
for (int i = 0; i < table.length; ++i) {
table[i] = labels[offset + readInt(u)];
u += 4;
}
mv.visitTableSwitchInsn(min, max, labels[label], table);
break;
}
case ClassWriter.LOOK_INSN: {
// skips 0 to 3 padding bytes
u = u + 4 - (offset & 3);
// reads instruction
int label = offset + readInt(u);
int len = readInt(u + 4);
int[] keys = new int[len];
Label[] values = new Label[len];
u += 8;
for (int i = 0; i < len; ++i) {
keys[i] = readInt(u);
values[i] = labels[offset + readInt(u + 4)];
u += 8;
}
mv.visitLookupSwitchInsn(labels[label], keys, values);
break;
}
case ClassWriter.VAR_INSN:
mv.visitVarInsn(opcode, b[u + 1] & 0xFF);
u += 2;
break;
case ClassWriter.SBYTE_INSN:
mv.visitIntInsn(opcode, b[u + 1]);
u += 2;
break;
case ClassWriter.SHORT_INSN:
mv.visitIntInsn(opcode, readShort(u + 1));
u += 3;
break;
case ClassWriter.LDC_INSN:
mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c));
u += 2;
break;
case ClassWriter.LDCW_INSN:
mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c));
u += 3;
break;
case ClassWriter.FIELDORMETH_INSN:
case ClassWriter.ITFMETH_INSN: {
int cpIndex = items[readUnsignedShort(u + 1)];
String iowner = readClass(cpIndex, c);
cpIndex = items[readUnsignedShort(cpIndex + 2)];
String iname = readUTF8(cpIndex, c);
String idesc = readUTF8(cpIndex + 2, c);
if (opcode < Opcodes.INVOKEVIRTUAL) {
mv.visitFieldInsn(opcode, iowner, iname, idesc);
} else {
mv.visitMethodInsn(opcode, iowner, iname, idesc);
}
if (opcode == Opcodes.INVOKEINTERFACE) {
u += 5;
} else {
u += 3;
}
break;
}
case ClassWriter.INDYMETH_INSN: {
int cpIndex = items[readUnsignedShort(u + 1)];
int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)];
Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c);
int bsmArgCount = readUnsignedShort(bsmIndex + 2);
Object[] bsmArgs = new Object[bsmArgCount];
bsmIndex += 4;
for (int i = 0; i < bsmArgCount; i++) {
bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c);
bsmIndex += 2;
}
cpIndex = items[readUnsignedShort(cpIndex + 2)];
String iname = readUTF8(cpIndex, c);
String idesc = readUTF8(cpIndex + 2, c);
mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs);
u += 5;
break;
}
case ClassWriter.TYPE_INSN:
mv.visitTypeInsn(opcode, readClass(u + 1, c));
u += 3;
break;
case ClassWriter.IINC_INSN:
mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]);
u += 3;
break;
// case MANA_INSN:
default:
mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF);
u += 4;
break;
}
// visit the instruction annotations, if any
while (tanns != null && tann < tanns.length && ntoff <= offset) {
if (ntoff == offset) {
int v = readAnnotationTarget(context, tanns[tann]);
readAnnotationValues(v + 2, c, true,
mv.visitInsnAnnotation(context.target,
context.path, readUTF8(v, c), true));
}
ntoff = ++tann >= tanns.length
|| readUnsignedShort(tanns[tann]) < 0x86 ? -1
: readUnsignedShort(tanns[tann] + 2);
}
while (itanns != null && itann < itanns.length && nitoff <= offset) {
if (nitoff == offset) {
int v = readAnnotationTarget(context, itanns[itann]);
readAnnotationValues(v + 2, c, true,
mv.visitInsnAnnotation(context.target,
context.path, readUTF8(v, c), false));
}
nitoff = ++itann >= itanns.length
|| readUnsignedShort(itanns[itann]) < 0x86 ? -1
: readUnsignedShort(itanns[itann] + 2);
}
}
if (labels[codeLength] != null) {
mv.visitLabel(labels[codeLength]);
}
// visits the local variable tables
if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) {
int[] typeTable = null;
if (varTypeTable != 0) {
u = varTypeTable + 2;
typeTable = new int[readUnsignedShort(varTypeTable) * 3];
for (int i = typeTable.length; i > 0;) {
typeTable[--i] = u + 6; // signature
typeTable[--i] = readUnsignedShort(u + 8); // index
typeTable[--i] = readUnsignedShort(u); // start
u += 10;
}
}
u = varTable + 2;
for (int i = readUnsignedShort(varTable); i > 0; --i) {
int start = readUnsignedShort(u);
int length = readUnsignedShort(u + 2);
int index = readUnsignedShort(u + 8);
String vsignature = null;
if (typeTable != null) {
for (int j = 0; j < typeTable.length; j += 3) {
if (typeTable[j] == start && typeTable[j + 1] == index) {
vsignature = readUTF8(typeTable[j + 2], c);
break;
}
}
}
mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c),
vsignature, labels[start], labels[start + length],
index);
u += 10;
}
}
// visits the local variables type annotations
if (tanns != null) {
for (int i = 0; i < tanns.length; ++i) {
if ((readUnsignedShort(tanns[i]) & 0xFC) == 0x80) {
int v = readAnnotationTarget(context, tanns[i]);
v = readAnnotationValues(v + 2, c, true,
mv.visitLocalVariableAnnotation(context.target,
context.path, context.start, context.end,
context.index, readUTF8(v, c), true));
}
}
}
if (itanns != null) {
for (int i = 0; i < itanns.length; ++i) {
if ((readUnsignedShort(itanns[i]) & 0xFC) == 0x80) {
int v = readAnnotationTarget(context, itanns[i]);
v = readAnnotationValues(v + 2, c, true,
mv.visitLocalVariableAnnotation(context.target,
context.path, context.start, context.end,
context.index, readUTF8(v, c), false));
}
}
}
// visits the code attributes
while (attributes != null) {
Attribute attr = attributes.next;
attributes.next = null;
mv.visitAttribute(attributes);
attributes = attr;
}
// visits the max stack and max locals values
mv.visitMaxs(maxStack, maxLocals);
}
ASM 4.0 readCode 에 부분 변수 Label [] labels 가 있 고 org. object web. asm. context. labels 도 가리 키 고 있 습 니 다.org. objectweb. asm. ClassReader. readLabel (int, Label []) 을 호출 하여 작 동 합 니 다.
ASM 2.2.3 안에 access 방법 안에 Label [] labels 부분 변 수 를 조작 하여 access 에서 직접 읽 고 쓴 것 입 니 다.
4.0 의 labels 배열 은 특정한 명령 에 접근 할 때 label 을 구성 합 니 다.
1. 코드 명령 종류:
if 、goto、jsr ;
goto_w、jsr_w ;
tableswitch、lookupswitch 、 ;
2. 이상 표 류
start_pc、end_pc、handler_pc
3. code 속성의 속성
LocalVariableTable, start_pc start_pc + length
LineNumberTable, 、
StackMapTable, 、 , (2 )
RuntimeVisibleTypeAnnotations
RuntimeInvisibleTypeAnnotations
다음은 asm 가 상수 탱크 정 보 를 어떻게 읽 는 지 살 펴 보 겠 습 니 다. asm 는 상수 탱크 항목 에 대응 하 는 상수 탱크 색인 에 따라 상수 탱크 색인 에 따라 class 파일 type 배열 의 오프셋 을 얻 은 다음 에 class 파일 의 byte 배열 에서 해당 하 는 길이 의 값 을 읽 습 니 다. 특히 float 와 double 값 의 저장 은 iee 의 형식 에 따라 저 장 됩 니 다.그래서 여기 서 해석 할 때 한 번 전환 을 합 니 다.
/**
* Reads a numeric or string constant pool item in {@link #b b}. <i>This
* method is intended for {@link Attribute} sub classes, and is normally not
* needed by class generators or adapters.</i>
*
* @param item
* the index of a constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double},
* {@link String}, {@link Type} or {@link Handle} corresponding to
* the given constant pool item.
*/
public Object readConst(final int item, final char[] buf) {
int index = items[item];
switch (b[index - 1]) {
case ClassWriter.INT://
return new Integer(readInt(index));
case ClassWriter.FLOAT:
return new Float(Float.intBitsToFloat(readInt(index)));
case ClassWriter.LONG:
return new Long(readLong(index));
case ClassWriter.DOUBLE:
return new Double(Double.longBitsToDouble(readLong(index)));
case ClassWriter.CLASS://class Type
return Type.getObjectType(readUTF8(index, buf));
case ClassWriter.STR:
return readUTF8(index, buf);
case ClassWriter.MTYPE:
return Type.getMethodType(readUTF8(index, buf));
default: // case ClassWriter.HANDLE_BASE + [1..9]:
int tag = readByte(index);
int[] items = this.items;
int cpIndex = items[readUnsignedShort(index + 1)];
String owner = readClass(cpIndex, buf);
cpIndex = items[readUnsignedShort(cpIndex + 2)];
String name = readUTF8(cpIndex, buf);
String desc = readUTF8(cpIndex + 2, buf);
return new Handle(tag, owner, name, desc);
}
}
MethodNode 에서 상수 값 은 LdcInsnNode 노드 로 변환 되 고 노드 의 cst 값 은 상수 값 입 니 다.
《 미 완 대 속 》.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Vue에서 Select 선택기를 사용하여 label을 결합하는 작업나는 쓸데없는 말을 더 이상 하지 않겠다. 모두들 코드를 직접 보는 것이 좋겠다. 일반적인 사용 방법: :label=“item.label” 여러 필드 결합: :label="${item.Name}/${item.Bran...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.