com.alibaba.fastjson.asm.MethodWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fastjson-to-easyjson Show documentation
Show all versions of fastjson-to-easyjson Show documentation
Adapter alibaba fastjson to other json libraries. the fastjson version: 1.2.58
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.alibaba.fastjson.asm;
/**
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public class MethodWriter implements MethodVisitor {
/**
* Next method writer (see {@link ClassWriter#firstMethod firstMethod}).
*/
MethodWriter next;
/**
* The class writer to which this method must be added.
*/
final ClassWriter cw;
/**
* Access flags of this method.
*/
private int access;
/**
* The index of the constant pool item that contains the name of this method.
*/
private final int name;
/**
* The index of the constant pool item that contains the descriptor of this method.
*/
private final int desc;
/**
* Number of exceptions that can be thrown by this method.
*/
int exceptionCount;
/**
* The exceptions that can be thrown by this method. More precisely, this array contains the indexes of the constant
* pool items that contain the internal names of these exception classes.
*/
int[] exceptions;
/**
* The bytecode of this method.
*/
private ByteVector code = new ByteVector();
/**
* Maximum stack size of this method.
*/
private int maxStack;
/**
* Maximum number of local variables for this method.
*/
private int maxLocals;
// ------------------------------------------------------------------------
/*
* Fields for the control flow graph analysis algorithm (used to compute the maximum stack size). A control flow
* graph contains one node per "basic block", and one edge per "jump" from one basic block to another. Each node
* (i.e., each basic block) is represented by the Label object that corresponds to the first instruction of this
* basic block. Each node also stores the list of its successors in the graph, as a linked list of Edge objects.
*/
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
public MethodWriter(final ClassWriter cw, final int access, final String name, final String desc, final String signature, final String[] exceptions) {
if (cw.firstMethod == null) {
cw.firstMethod = this;
} else {
cw.lastMethod.next = this;
}
cw.lastMethod = this;
this.cw = cw;
this.access = access;
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
if (exceptions != null && exceptions.length > 0) {
exceptionCount = exceptions.length;
this.exceptions = new int[exceptionCount];
for (int i = 0; i < exceptionCount; ++i) {
this.exceptions[i] = cw.newClassItem(exceptions[i]).index;
}
}
}
// ------------------------------------------------------------------------
// Implementation of the MethodVisitor interface
// ------------------------------------------------------------------------
public void visitInsn(final int opcode) {
// adds the instruction to the bytecode of the method
code.putByte(opcode);
// update currentBlock
// Label currentBlock = this.currentBlock;
}
public void visitIntInsn(final int opcode, final int operand) {
// Label currentBlock = this.currentBlock;
// adds the instruction to the bytecode of the method
// if (opcode == Opcodes.SIPUSH) {
// code.put12(opcode, operand);
// } else { // BIPUSH or NEWARRAY
code.put11(opcode, operand);
// }
}
public void visitVarInsn(final int opcode, final int var) {
// Label currentBlock = this.currentBlock;
// adds the instruction to the bytecode of the method
if (var < 4 && opcode != Opcodes.RET) {
int opt;
if (opcode < Opcodes.ISTORE) {
/* ILOAD_0 */
opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
} else {
/* ISTORE_0 */
opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
}
code.putByte(opt);
} else if (var >= 256) {
code.putByte(196 /* WIDE */).put12(opcode, var);
} else {
code.put11(opcode, var);
}
}
public void visitTypeInsn(final int opcode, final String type) {
Item i = cw.newClassItem(type);
// Label currentBlock = this.currentBlock;
// adds the instruction to the bytecode of the method
code.put12(opcode, i.index);
}
public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
Item i = cw.newFieldItem(owner, name, desc);
// Label currentBlock = this.currentBlock;
// adds the instruction to the bytecode of the method
code.put12(opcode, i.index);
}
public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
Item i = cw.newMethodItem(owner, name, desc, itf);
int argSize = i.intVal;
// Label currentBlock = this.currentBlock;
// adds the instruction to the bytecode of the method
if (itf) {
if (argSize == 0) {
argSize = Type.getArgumentsAndReturnSizes(desc);
i.intVal = argSize;
}
code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
} else {
code.put12(opcode, i.index);
}
}
public void visitJumpInsn(final int opcode, final Label label) {
// Label currentBlock = this.currentBlock;
// adds the instruction to the bytecode of the method
if ((label.status & 2 /* Label.RESOLVED */) != 0 && label.position - code.length < Short.MIN_VALUE) {
throw new UnsupportedOperationException();
} else {
/*
* case of a backward jump with an offset >= -32768, or of a forward jump with, of course, an unknown
* offset. In these cases we store the offset in 2 bytes (which will be increased in resizeInstructions, if
* needed).
*/
code.putByte(opcode);
label.put(this, code, code.length - 1);
}
}
public void visitLabel(final Label label) {
// resolves previous forward references to label, if any
label.resolve(this, code.length, code.data);
}
public void visitLdcInsn(final Object cst) {
Item i = cw.newConstItem(cst);
// Label currentBlock = this.currentBlock;
// adds the instruction to the bytecode of the method
int index = i.index;
if (i.type == 5 /* ClassWriter.LONG */ || i.type == 6 /* ClassWriter.DOUBLE */) {
code.put12(20 /* LDC2_W */, index);
} else if (index >= 256) {
code.put12(19 /* LDC_W */, index);
} else {
code.put11(18 /*Opcodes.LDC*/, index);
}
}
public void visitIincInsn(final int var, final int increment) {
// adds the instruction to the bytecode of the method
// if ((var > 255) || (increment > 127) || (increment < -128)) {
// code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var).putShort(increment);
// } else {
code.putByte(132 /* Opcodes.IINC*/).put11(var, increment);
// }
}
public void visitMaxs(final int maxStack, final int maxLocals) {
this.maxStack = maxStack;
this.maxLocals = maxLocals;
}
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Utility methods: control flow analysis algorithm
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// Utility methods: stack map frames
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// Utility methods: dump bytecode array
// ------------------------------------------------------------------------
/**
* Returns the size of the bytecode of this method.
*
* @return the size of the bytecode of this method.
*/
final int getSize() {
int size = 8;
if (code.length > 0) {
cw.newUTF8("Code");
size += 18 + code.length + 8 * 0;
}
if (exceptionCount > 0) {
cw.newUTF8("Exceptions");
size += 8 + 2 * exceptionCount;
}
return size;
}
/**
* Puts the bytecode of this method in the given byte vector.
*
* @param out the byte vector into which the bytecode of this method must be copied.
*/
final void put(final ByteVector out) {
final int mask = 393216; //Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC));
out.putShort(access & ~mask).putShort(name).putShort(desc);
int attributeCount = 0;
if (code.length > 0) {
++attributeCount;
}
if (exceptionCount > 0) {
++attributeCount;
}
out.putShort(attributeCount);
if (code.length > 0) {
int size = 12 + code.length + 8 * 0; // handlerCount
out.putShort(cw.newUTF8("Code")).putInt(size);
out.putShort(maxStack).putShort(maxLocals);
out.putInt(code.length).putByteArray(code.data, 0, code.length);
out.putShort(0); // handlerCount
attributeCount = 0;
out.putShort(attributeCount);
}
if (exceptionCount > 0) {
out.putShort(cw.newUTF8("Exceptions")).putInt(2 * exceptionCount + 2);
out.putShort(exceptionCount);
for (int i = 0; i < exceptionCount; ++i) {
out.putShort(exceptions[i]);
}
}
}
}