下面列出了org.objectweb.asm.Type#FLOAT 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private void emitPrimitiveCompare(CodeEmitter code, TypeWidget type) {
switch (type.getJVMType().getSort()) {
case Type.BYTE:
case Type.BOOLEAN:
case Type.SHORT:
case Type.INT:
case Type.CHAR:
code.getMethodVisitor().visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Integer.class), "compare", Type.getMethodDescriptor(Type.INT_TYPE, Type.INT_TYPE, Type.INT_TYPE), false);
break;
case Type.FLOAT:
code.getMethodVisitor().visitInsn(Opcodes.FCMPG);
break;
case Type.LONG:
code.getMethodVisitor().visitInsn(Opcodes.LCMP);
break;
case Type.DOUBLE:
code.getMethodVisitor().visitInsn(Opcodes.DCMPG);
break;
default:
throw new UnsupportedOperationException("Unexpected primitive type: " + leftExpr.getType().getJVMType().getDescriptor());
}
}
public static Type getBoxedType(Type type) {
switch (type.getSort()) {
case Type.CHAR:
return Constants.TYPE_CHARACTER;
case Type.BOOLEAN:
return Constants.TYPE_BOOLEAN;
case Type.DOUBLE:
return Constants.TYPE_DOUBLE;
case Type.FLOAT:
return Constants.TYPE_FLOAT;
case Type.LONG:
return Constants.TYPE_LONG;
case Type.INT:
return Constants.TYPE_INTEGER;
case Type.SHORT:
return Constants.TYPE_SHORT;
case Type.BYTE:
return Constants.TYPE_BYTE;
default:
return type;
}
}
private void pushDefault(Type type) {
switch (type.getSort()) {
case Type.VOID:
break;
case Type.DOUBLE:
mv.visitInsn(DCONST_0);
break;
case Type.LONG:
mv.visitInsn(LCONST_0);
break;
case Type.FLOAT:
mv.visitInsn(FCONST_0);
break;
case Type.OBJECT:
case Type.ARRAY:
mv.visitInsn(ACONST_NULL);
break;
default:
mv.visitInsn(ICONST_0);
break;
}
}
public static AbstractInsnNode nullValueForType(Type returnType) {
switch (returnType.getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.CHAR:
case Type.SHORT:
case Type.INT:
return new InsnNode(ICONST_0);
case Type.FLOAT:
return new InsnNode(FCONST_0);
case Type.DOUBLE:
return new InsnNode(DCONST_0);
case Type.LONG:
return new InsnNode(LCONST_0);
case Type.ARRAY:
case Type.OBJECT:
return new InsnNode(ACONST_NULL);
default:
throw new UnsupportedOperationException();
}
}
public Variable getReturnCacheVar(Type type) {
Validate.notNull(type);
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.CHAR:
case Type.SHORT:
case Type.INT:
return getIntReturnCacheVar();
case Type.LONG:
return getLongReturnCacheVar();
case Type.FLOAT:
return getFloatReturnCacheVar();
case Type.DOUBLE:
return getDoubleReturnCacheVar();
case Type.ARRAY:
case Type.OBJECT:
return getObjectReturnCacheVar();
case Type.VOID:
return null;
default:
throw new IllegalArgumentException("Bad type");
}
}
Type getBoxedType(final Type type) {
switch (type.getSort()) {
case Type.BYTE:
return BYTE_TYPE;
case Type.BOOLEAN:
return BOOLEAN_TYPE;
case Type.SHORT:
return SHORT_TYPE;
case Type.CHAR:
return CHARACTER_TYPE;
case Type.INT:
return INTEGER_TYPE;
case Type.FLOAT:
return FLOAT_TYPE;
case Type.LONG:
return LONG_TYPE;
case Type.DOUBLE:
return DOUBLE_TYPE;
}
return type;
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
switch (type.getSort()) {
case Type.VOID:
return null;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return BasicValue.INT_VALUE;
case Type.FLOAT:
return BasicValue.FLOAT_VALUE;
case Type.LONG:
return BasicValue.LONG_VALUE;
case Type.DOUBLE:
return BasicValue.DOUBLE_VALUE;
case Type.ARRAY:
case Type.OBJECT:
return BasicValue.REFERENCE_VALUE;
default:
throw new AssertionError();
}
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
switch (type.getSort()) {
case Type.VOID:
return null;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return BasicValue.INT_VALUE;
case Type.FLOAT:
return BasicValue.FLOAT_VALUE;
case Type.LONG:
return BasicValue.LONG_VALUE;
case Type.DOUBLE:
return BasicValue.DOUBLE_VALUE;
case Type.ARRAY:
case Type.OBJECT:
return BasicValue.REFERENCE_VALUE;
default:
throw new AssertionError();
}
}
/**
* Generates the instructions to unbox the top stack value. This value is replaced by its unboxed
* equivalent on top of the stack.
*
* @param type the type of the top stack value.
*/
public void unbox(final Type type) {
Type boxedType = NUMBER_TYPE;
Method unboxMethod;
switch (type.getSort()) {
case Type.VOID:
return;
case Type.CHAR:
boxedType = CHARACTER_TYPE;
unboxMethod = CHAR_VALUE;
break;
case Type.BOOLEAN:
boxedType = BOOLEAN_TYPE;
unboxMethod = BOOLEAN_VALUE;
break;
case Type.DOUBLE:
unboxMethod = DOUBLE_VALUE;
break;
case Type.FLOAT:
unboxMethod = FLOAT_VALUE;
break;
case Type.LONG:
unboxMethod = LONG_VALUE;
break;
case Type.INT:
case Type.SHORT:
case Type.BYTE:
unboxMethod = INT_VALUE;
break;
default:
unboxMethod = null;
break;
}
if (unboxMethod == null) {
checkCast(type);
} else {
checkCast(boxedType);
invokeVirtual(boxedType, unboxMethod);
}
}
/**
* Generates the instructions to unbox the top stack value. This value is replaced by its unboxed
* equivalent on top of the stack.
*
* @param type the type of the top stack value.
*/
public void unbox(final Type type) {
Type boxedType = NUMBER_TYPE;
Method unboxMethod;
switch (type.getSort()) {
case Type.VOID:
return;
case Type.CHAR:
boxedType = CHARACTER_TYPE;
unboxMethod = CHAR_VALUE;
break;
case Type.BOOLEAN:
boxedType = BOOLEAN_TYPE;
unboxMethod = BOOLEAN_VALUE;
break;
case Type.DOUBLE:
unboxMethod = DOUBLE_VALUE;
break;
case Type.FLOAT:
unboxMethod = FLOAT_VALUE;
break;
case Type.LONG:
unboxMethod = LONG_VALUE;
break;
case Type.INT:
case Type.SHORT:
case Type.BYTE:
unboxMethod = INT_VALUE;
break;
default:
unboxMethod = null;
}
if (unboxMethod == null) {
checkCast(type);
} else {
checkCast(boxedType);
invokeVirtual(boxedType, unboxMethod);
}
}
/**
* Generates the instruction to create a new array.
*
* @param type the type of the array elements.
*/
public void newArray(final Type type) {
int arrayType;
switch (type.getSort()) {
case Type.BOOLEAN:
arrayType = Opcodes.T_BOOLEAN;
break;
case Type.CHAR:
arrayType = Opcodes.T_CHAR;
break;
case Type.BYTE:
arrayType = Opcodes.T_BYTE;
break;
case Type.SHORT:
arrayType = Opcodes.T_SHORT;
break;
case Type.INT:
arrayType = Opcodes.T_INT;
break;
case Type.FLOAT:
arrayType = Opcodes.T_FLOAT;
break;
case Type.LONG:
arrayType = Opcodes.T_LONG;
break;
case Type.DOUBLE:
arrayType = Opcodes.T_DOUBLE;
break;
default:
typeInsn(Opcodes.ANEWARRAY, type);
return;
}
mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
}
public static boolean isPrimitiveType(Type type) {
switch (type.getSort()) {
case Type.BYTE:
case Type.BOOLEAN:
case Type.CHAR:
case Type.SHORT:
case Type.INT:
case Type.FLOAT:
case Type.LONG:
case Type.DOUBLE:
return true;
default:
return false;
}
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final Type value) {
if (value == null) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
switch (value.getSort()) {
case Type.BOOLEAN:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.CHAR:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.BYTE:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.SHORT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.INT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.FLOAT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.LONG:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.DOUBLE:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", CLASS_DESCRIPTOR);
break;
default:
mv.visitLdcInsn(value);
break;
}
}
}
/**
* Generates the instructions to unbox the top stack value. This value is replaced by its unboxed
* equivalent on top of the stack.
*
* @param type the type of the top stack value.
*/
public void unbox(final Type type) {
Type boxedType = NUMBER_TYPE;
Method unboxMethod;
switch (type.getSort()) {
case Type.VOID:
return;
case Type.CHAR:
boxedType = CHARACTER_TYPE;
unboxMethod = CHAR_VALUE;
break;
case Type.BOOLEAN:
boxedType = BOOLEAN_TYPE;
unboxMethod = BOOLEAN_VALUE;
break;
case Type.DOUBLE:
unboxMethod = DOUBLE_VALUE;
break;
case Type.FLOAT:
unboxMethod = FLOAT_VALUE;
break;
case Type.LONG:
unboxMethod = LONG_VALUE;
break;
case Type.INT:
case Type.SHORT:
case Type.BYTE:
unboxMethod = INT_VALUE;
break;
default:
unboxMethod = null;
break;
}
if (unboxMethod == null) {
checkCast(type);
} else {
checkCast(boxedType);
invokeVirtual(boxedType, unboxMethod);
}
}
/**
* Creates an array of {@link Class} objects with the same size of the array of the passed
* parameter types. For each parameter type, stores its {@link Class} object into the
* result array. For intrinsic types which are not present in the class constant pool, just
* push the actual {@link Type} object on the stack and let ASM do the rest. For non
* intrinsic type use a {@link MethodVisitor#visitLdcInsn(Object)} to ensure the
* referenced class's presence in this class constant pool.
* <p>
* Stack Before : nothing of interest
* Stack After : <array of {@link Class}>
*
* @param parameterTypes a method list of parameters.
*/
private void pushParameterTypesOnStack(Type[] parameterTypes) {
push(parameterTypes.length);
newArray(Type.getType(Class.class));
for (int i = 0; i < parameterTypes.length; i++) {
dup();
push(i);
switch (parameterTypes[i].getSort()) {
case Type.OBJECT:
case Type.ARRAY:
visitLdcInsn(parameterTypes[i]);
break;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
case Type.LONG:
case Type.FLOAT:
case Type.DOUBLE:
push(parameterTypes[i]);
break;
default:
throw new RuntimeException(
"Unexpected parameter type " + parameterTypes[i]);
}
arrayStore(Type.getType(Class.class));
}
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
switch (type.getSort()) {
case Type.VOID:
return null;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return BasicValue.INT_VALUE;
case Type.FLOAT:
return BasicValue.FLOAT_VALUE;
case Type.LONG:
return BasicValue.LONG_VALUE;
case Type.DOUBLE:
return BasicValue.DOUBLE_VALUE;
case Type.ARRAY:
case Type.OBJECT:
return BasicValue.REFERENCE_VALUE;
default:
throw new AssertionError();
}
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final Type value) {
if (value == null) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
switch (value.getSort()) {
case Type.BOOLEAN:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.CHAR:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.BYTE:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.SHORT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.INT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.FLOAT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.LONG:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.DOUBLE:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", CLASS_DESCRIPTOR);
break;
default:
mv.visitLdcInsn(value);
}
}
}
/**
* Generates instructions that returns a dummy value. Return values are as follows:
* <ul>
* <li>void -> no value</li>
* <li>boolean -> false</li>
* <li>byte/short/char/int -> 0</li>
* <li>long -> 0L</li>
* <li>float -> 0.0f</li>
* <li>double -> 0.0</li>
* <li>Object -> null</li>
* </ul>
*
* @param returnType return type of the method this generated bytecode is for
* @return instructions to return a dummy value
* @throws NullPointerException if any argument is {@code null}
* @throws IllegalArgumentException if {@code returnType}'s sort is of {@link Type#METHOD}
*/
private static InsnList returnDummy(Type returnType) {
Validate.notNull(returnType);
Validate.isTrue(returnType.getSort() != Type.METHOD);
InsnList ret = new InsnList();
switch (returnType.getSort()) {
case Type.VOID:
ret.add(new InsnNode(Opcodes.RETURN));
break;
case Type.BOOLEAN:
case Type.BYTE:
case Type.SHORT:
case Type.CHAR:
case Type.INT:
ret.add(new InsnNode(Opcodes.ICONST_0));
ret.add(new InsnNode(Opcodes.IRETURN));
break;
case Type.LONG:
ret.add(new InsnNode(Opcodes.LCONST_0));
ret.add(new InsnNode(Opcodes.LRETURN));
break;
case Type.FLOAT:
ret.add(new InsnNode(Opcodes.FCONST_0));
ret.add(new InsnNode(Opcodes.FRETURN));
break;
case Type.DOUBLE:
ret.add(new InsnNode(Opcodes.DCONST_0));
ret.add(new InsnNode(Opcodes.DRETURN));
break;
case Type.OBJECT:
case Type.ARRAY:
ret.add(new InsnNode(Opcodes.ACONST_NULL));
ret.add(new InsnNode(Opcodes.ARETURN));
break;
default:
throw new IllegalStateException();
}
return ret;
}
/**
* Returns whether a given instruction can be used to push argument of {@code type} on stack.
*/
private /* static */ boolean isPushForType(AbstractInsnNode insn, Type type) {
int opcode = insn.getOpcode();
if (opcode == type.getOpcode(Opcodes.ILOAD)) {
return true;
}
// b/62060793: AsyncAwait rewrites bytecode to convert java methods into state machine with
// support of lambdas. Constant zero values are pushed on stack for all yet uninitialized
// local variables. And SIPUSH instruction is used to advance an internal state of a state
// machine.
switch (type.getSort()) {
case Type.BOOLEAN:
return opcode == Opcodes.ICONST_0 || opcode == Opcodes.ICONST_1;
case Type.BYTE:
case Type.CHAR:
case Type.SHORT:
case Type.INT:
return opcode == Opcodes.SIPUSH
|| opcode == Opcodes.ICONST_0
|| opcode == Opcodes.ICONST_1
|| opcode == Opcodes.ICONST_2
|| opcode == Opcodes.ICONST_3
|| opcode == Opcodes.ICONST_4
|| opcode == Opcodes.ICONST_5
|| opcode == Opcodes.ICONST_M1;
case Type.LONG:
return opcode == Opcodes.LCONST_0 || opcode == Opcodes.LCONST_1;
case Type.FLOAT:
return opcode == Opcodes.FCONST_0
|| opcode == Opcodes.FCONST_1
|| opcode == Opcodes.FCONST_2;
case Type.DOUBLE:
return opcode == Opcodes.DCONST_0 || opcode == Opcodes.DCONST_1;
case Type.OBJECT:
case Type.ARRAY:
return opcode == Opcodes.ACONST_NULL;
default:
// Support for BIPUSH and LDC* opcodes is not implemented as there is no known use case.
return false;
}
}
/**
* Compute sizes required for the storage arrays that will contain the operand stack at this frame.
* @param frame frame to compute for
* @param offset the position within the operand stack to start calculating
* @param length the number of stack items to include in calculation
* @return size required by each storage array
* @throws NullPointerException if any argument is {@code null}
* @throws IllegalArgumentException if any numeric argument is negative, or if {@code offset + length} is larger than the size of the
* operand stack
*/
public static StorageSizes computeSizes(Frame<BasicValue> frame, int offset, int length) {
Validate.notNull(frame);
Validate.isTrue(offset >= 0);
Validate.isTrue(length >= 0);
Validate.isTrue(offset < frame.getStackSize());
Validate.isTrue(offset + length <= frame.getStackSize());
// Count size required for each storage array
int intsSize = 0;
int longsSize = 0;
int floatsSize = 0;
int doublesSize = 0;
int objectsSize = 0;
for (int i = offset + length - 1; i >= offset; i--) {
BasicValue basicValue = frame.getStack(i);
Type type = basicValue.getType();
// If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise'
// the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this
// point in the code so we can avoid saving it. When we load it back up, we can simply push a null in to that slot, thereby
// keeping the same 'Lnull;' type.
if ("Lnull;".equals(type.getDescriptor())) {
continue;
}
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.SHORT:
case Type.CHAR:
case Type.INT:
intsSize++;
break;
case Type.FLOAT:
floatsSize++;
break;
case Type.LONG:
longsSize++;
break;
case Type.DOUBLE:
doublesSize++;
break;
case Type.ARRAY:
case Type.OBJECT:
objectsSize++;
break;
case Type.METHOD:
case Type.VOID:
default:
throw new IllegalStateException();
}
}
return new StorageSizes(intsSize, longsSize, floatsSize, doublesSize, objectsSize);
}