下面列出了org.objectweb.asm.Type#ARRAY 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static Object convert(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return INTEGER;
case Type.FLOAT:
return FLOAT;
case Type.LONG:
return LONG;
case Type.DOUBLE:
return DOUBLE;
case Type.ARRAY:
return type.getDescriptor();
case Type.OBJECT:
return type.getInternalName();
case Type.METHOD:
return type.getDescriptor();
default:
throw new IllegalStateException("Unexpected type: " + type.getDescriptor());
}
}
/**
* Inject the appropriate return code for the method type
*
* @param callback callback handle
*/
protected void injectReturnCode(final Callback callback) {
if (callback.target.returnType.equals(Type.VOID_TYPE)) {
// Void method, so just return void
callback.add(new InsnNode(Opcodes.RETURN));
} else {
// Non-void method, so work out which accessor to call to get the
// return value, and return it
callback.add(new VarInsnNode(Opcodes.ALOAD, callback.marshalVar()));
String accessor = CallbackInfoReturnable.getReturnAccessor(callback.target.returnType);
String descriptor = CallbackInfoReturnable.getReturnDescriptor(callback.target.returnType);
callback.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, this.callbackInfoClass, accessor, descriptor, false));
if (callback.target.returnType.getSort() >= Type.ARRAY) {
callback.add(new TypeInsnNode(Opcodes.CHECKCAST, callback.target.returnType.getInternalName()));
}
callback.add(new InsnNode(callback.target.returnType.getOpcode(Opcodes.IRETURN)));
}
}
/**
* Returns the given {@link Type}, remapped with {@link #map(String)} or {@link
* #mapMethodDesc(String)}.
*
* @param type a type, which can be a method type.
* @return the given type, with its [array element type] internal name remapped with {@link
* #map(String)} (if the type is an array or object type, otherwise the type is returned as
* is) or, of the type is a method type, with its descriptor remapped with {@link
* #mapMethodDesc(String)}.
*/
private Type mapType(final Type type) {
switch (type.getSort()) {
case Type.ARRAY:
StringBuilder remappedDescriptor = new StringBuilder();
for (int i = 0; i < type.getDimensions(); ++i) {
remappedDescriptor.append('[');
}
remappedDescriptor.append(mapType(type.getElementType()).getDescriptor());
return Type.getType(remappedDescriptor.toString());
case Type.OBJECT:
String remappedInternalName = map(type.getInternalName());
return remappedInternalName != null ? Type.getObjectType(remappedInternalName) : type;
case Type.METHOD:
return Type.getMethodType(mapMethodDesc(type.getDescriptor()));
default:
return type;
}
}
/**
* Generates the instructions to box the top stack value. This value is replaced by its boxed
* equivalent on top of the stack.
*
* @param type the type of the top stack value.
*/
public void box(final Type type) {
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
return;
}
if (type == Type.VOID_TYPE) {
push((String) null);
} else {
Type boxedType = getBoxedType(type);
newInstance(boxedType);
if (type.getSize() == 2) {
// Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
dupX2();
dupX2();
pop();
} else {
// p -> po -> opo -> oop -> o
dupX1();
swap();
}
invokeConstructor(boxedType, new Method("<init>", Type.VOID_TYPE, new Type[] {type}));
}
}
@Override
public void visitLdcInsn(final Object value) {
super.visitLdcInsn(value);
if (this.locals == null) {
labels = null;
return;
}
if (value instanceof Integer) {
push(Opcodes.INTEGER);
} else if (value instanceof Long) {
push(Opcodes.LONG);
push(Opcodes.TOP);
} else if (value instanceof Float) {
push(Opcodes.FLOAT);
} else if (value instanceof Double) {
push(Opcodes.DOUBLE);
push(Opcodes.TOP);
} else if (value instanceof String) {
push("java/lang/String");
} else if (value instanceof Type) {
int sort = ((Type) value).getSort();
if (sort == Type.OBJECT || sort == Type.ARRAY) {
push("java/lang/Class");
} else if (sort == Type.METHOD) {
push("java/lang/invoke/MethodType");
} else {
throw new IllegalArgumentException();
}
} else if (value instanceof Handle) {
push("java/lang/invoke/MethodHandle");
} else if (value instanceof ConstantDynamic) {
pushDescriptor(((ConstantDynamic) value).getDescriptor());
} else {
throw new IllegalArgumentException();
}
labels = null;
}
private void addType(final Type type) {
switch (type.getSort()) {
case Type.ARRAY:
addType(type.getElementType());
break;
case Type.OBJECT:
addPackage(type.getInternalName());
break;
case Type.METHOD:
addMethodTypes(type.getDescriptor());
break;
default:
}
}
@Override
protected boolean isAssignableFrom(Type t, Type u) {
if (t.equals(u)) {
return true;
}
// Null is assignable to any reference type
if ("Lnull;".equals(u.getDescriptor()) && t.getSort() >= Type.ARRAY) {
return true;
}
Type et, eu;
if (t.getSort() == Type.ARRAY) {
if (u.getSort() != Type.ARRAY ) {
return false;
}
et = t.getElementType();
eu = u.getElementType();
int dt = t.getDimensions();
int du = u.getDimensions();
boolean isObject = et.equals(((BasicValue)BasicValue.REFERENCE_VALUE).getType());
// u must be an array of equals dimension or bigger dimension if t is Object
if (dt == du || dt < du && isObject) {
// Ok
} else {
return false;
}
} else {
et = t;
eu = u;
}
/*
Type commonType = classHierarchy.getCommonSuperType(et, eu);
*/
// isAssignableFrom(Number, Integer) => getCommonSuperType(Integer, Number) == Number
// Use ClassHierarchy.isSubclass biased behavior (for performance)
Type commonType = classHierarchy.getCommonSuperType(eu, et);
return commonType.equals(et);
}
private Type getMirrorType(final Type type) {
int numDimensions = 0;
final Type basicType;
if (type.getSort() == Type.ARRAY) {
numDimensions = type.getDimensions();
basicType = type.getElementType();
} else {
basicType = type;
}
if (basicType.getSort() != Type.OBJECT) {
return type;
}
final Mirror mirror = getMirror(basicType.getInternalName());
if (mirror.isClassMirror()) {
final StringBuilder name = new StringBuilder();
for (int i = 0; i < numDimensions; ++i) {
name.append('[');
}
name.append('L').append(mirror.getTranslatedName()).append(';');
return Type.getType(name.toString());
}
return type;
}
/**
* Loads the class corresponding to the given type. The class is loaded with the class loader
* specified with {@link #setClassLoader}, or with the class loader of this class if no class
* loader was specified.
*
* @param type a type.
* @return the class corresponding to 'type'.
*/
protected Class<?> getClass(final Type type) {
try {
if (type.getSort() == Type.ARRAY) {
return Class.forName(type.getDescriptor().replace('/', '.'), false, loader);
}
return Class.forName(type.getClassName(), false, loader);
} catch (ClassNotFoundException e) {
throw new TypeNotPresentException(e.toString(), e);
}
}
/**
* Loads the class corresponding to the given type. The class is loaded with the class loader
* specified with {@link #setClassLoader}, or with the class loader of this class if no class
* loader was specified.
*
* @param type a type.
* @return the class corresponding to 'type'.
*/
protected Class<?> getClass(final Type type) {
try {
if (type.getSort() == Type.ARRAY) {
return Class.forName(type.getDescriptor().replace('/', '.'), false, loader);
}
return Class.forName(type.getClassName(), false, loader);
} catch (ClassNotFoundException e) {
throw new TypeNotPresentException(e.toString(), e);
}
}
/**
* Loads the class corresponding to the given type. The class is loaded with the class loader specified with {@link #setClassLoader}, or with the class loader of this class if no class loader was specified.
*
* @param type
* a type.
* @return the class corresponding to 'type'.
*/
protected Class<?> getClass(final Type type) {
try {
if (type.getSort() == Type.ARRAY) {
return Class.forName(type.getDescriptor().replace('/', '.'), false, loader);
}
return Class.forName(type.getClassName(), false, loader);
} catch (ClassNotFoundException e) {
throw new TypeNotPresentException(e.toString(), e);
}
}
private void checkType(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.CHAR:
case Type.SHORT:
case Type.INT:
case Type.LONG:
case Type.FLOAT:
case Type.DOUBLE:
case Type.VOID:
return; // Ignore primitive types.
case Type.ARRAY:
checkType(type.getElementType());
return;
case Type.METHOD:
for (Type argumentType : type.getArgumentTypes()) {
checkType(argumentType);
}
checkType(type.getReturnType());
return;
case Type.OBJECT:
checkInternalName(type.getInternalName());
return;
default:
throw new UnsupportedOperationException("Unhandled type: " + type);
}
}
private void addType(final Type type) {
switch (type.getSort()) {
case Type.ARRAY:
addType(type.getElementType());
break;
case Type.OBJECT:
addPackage(type.getInternalName());
break;
case Type.METHOD:
addMethodTypes(type.getDescriptor());
break;
}
}
@Override
public String getTypeName() {
switch (type.getSort()) {
case Type.ARRAY:
return type.getDescriptor();
case Type.OBJECT:
return type.getInternalName().replace("/", ".");
case Type.VOID:
return "void";
case Type.METHOD:
return type.getDescriptor();
case Type.BOOLEAN:
return "boolean";
case Type.SHORT:
return "short";
case Type.INT:
return "int";
case Type.CHAR:
return "char";
case Type.FLOAT:
return "float";
case Type.LONG:
return "long";
case Type.DOUBLE:
return "double";
default:
throw new UnsupportedOperationException("Unknown JVM type: " + type);
}
}
private void generateGetFromCache(final CodeBlock block)
{
final Type[] paramTypes = Type.getArgumentTypes(method.desc);
cacheFieldName = findUnusedCacheFieldName();
// if we have no parameters we use a simple Rule field as cache,
// otherwise a HashMap
final String cacheFieldDesc = paramTypes.length == 0
? CodegenUtils.ci(Rule.class)
: CodegenUtils.ci(HashMap.class);
final FieldNode field = new FieldNode(ACC_PRIVATE, cacheFieldName,
cacheFieldDesc, null, null);
classNode.fields.add(field);
block.aload(0).getfield(classNode.name, cacheFieldName, cacheFieldDesc);
if (paramTypes.length == 0)
return; // if we have no parameters we are done
// generate: if (<cache> == null) <cache> = new HashMap<Object, Rule>();
final LabelNode alreadyInitialized = new LabelNode();
block.dup()
.ifnonnull(alreadyInitialized)
.pop()
.aload(0)
.newobj(CodegenUtils.p(HashMap.class)).dup_x1().dup()
.invokespecial(CodegenUtils.p(HashMap.class), "<init>",
CodegenUtils.sig(void.class))
.putfield(classNode.name, cacheFieldName, cacheFieldDesc)
.label(alreadyInitialized);
// if we have more than one parameter or the parameter is an array we
// have to wrap with our Arguments class since we need to unroll all
// inner arrays and apply custom hashCode(...) and equals(...)
// implementations
if (paramTypes.length > 1 || paramTypes[0].getSort() == Type.ARRAY) {
// generate: push new Arguments(new Object[] {<params>})
block.newobj(CodegenUtils.p(CacheArguments.class)).dup();
generatePushNewParameterObjectArray(block, paramTypes);
block.invokespecial(CodegenUtils.p(CacheArguments.class), "<init>",
CodegenUtils.sig(void.class, Object[].class));
} else {
generatePushParameterAsObject(block, paramTypes, 0);
}
// generate: <hashMap>.get(...)
block.dup().astore(method.maxLocals)
.invokevirtual(CodegenUtils.p(HashMap.class), "get",
CodegenUtils.sig(Object.class, Object.class));
}
/**
* Checks that the given value is a valid operand for the LDC instruction.
*
* @param value the value to be checked.
*/
private void checkLdcConstant(final Object value) {
if (value instanceof Type) {
int sort = ((Type) value).getSort();
if (sort != Type.OBJECT && sort != Type.ARRAY && sort != Type.METHOD) {
throw new IllegalArgumentException("Illegal LDC constant value");
}
if (sort != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
throw new IllegalArgumentException("ldc of a constant class requires at least version 1.5");
}
if (sort == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
throw new IllegalArgumentException("ldc of a method type requires at least version 1.7");
}
} else if (value instanceof Handle) {
if ((version & 0xFFFF) < Opcodes.V1_7) {
throw new IllegalArgumentException("ldc of a Handle requires at least version 1.7");
}
Handle handle = (Handle) value;
int tag = handle.getTag();
if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
throw new IllegalArgumentException("invalid handle tag " + tag);
}
checkInternalName(this.version, handle.getOwner(), "handle owner");
if (tag <= Opcodes.H_PUTSTATIC) {
checkDescriptor(this.version, handle.getDesc(), false);
} else {
checkMethodDescriptor(this.version, handle.getDesc());
}
String handleName = handle.getName();
if (!("<init>".equals(handleName) && tag == Opcodes.H_NEWINVOKESPECIAL)) {
checkMethodIdentifier(this.version, handleName, "handle name");
}
} else if (value instanceof ConstantDynamic) {
if ((version & 0xFFFF) < Opcodes.V11) {
throw new IllegalArgumentException("ldc of a ConstantDynamic requires at least version 11");
}
ConstantDynamic constantDynamic = (ConstantDynamic) value;
checkMethodIdentifier(this.version, constantDynamic.getName(), "constant dynamic name");
checkDescriptor(this.version, constantDynamic.getDescriptor(), false);
checkLdcConstant(constantDynamic.getBootstrapMethod());
int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
checkLdcConstant(constantDynamic.getBootstrapMethodArgument(i));
}
} else {
checkConstant(value);
}
}
/**
* Create the types of local variables at the very beginning of the method with the information of
* the declaring class and the method descriptor.
*/
private static ArrayList<InferredType> createInitialLocalVariableTypes(
int access, String ownerClass, String methodName, String methodDescriptor) {
ArrayList<InferredType> types = new ArrayList<>();
if (!isStatic(access)) {
// Instance method, and this is the receiver
types.add(InferredType.create(convertToDescriptor(ownerClass)));
}
Type[] argumentTypes = Type.getArgumentTypes(methodDescriptor);
for (Type argumentType : argumentTypes) {
switch (argumentType.getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.CHAR:
case Type.SHORT:
case Type.INT:
types.add(InferredType.INT);
break;
case Type.FLOAT:
types.add(InferredType.FLOAT);
break;
case Type.LONG:
types.add(InferredType.LONG);
types.add(InferredType.TOP);
break;
case Type.DOUBLE:
types.add(InferredType.DOUBLE);
types.add(InferredType.TOP);
break;
case Type.ARRAY:
case Type.OBJECT:
types.add(InferredType.create(argumentType.getDescriptor()));
break;
default:
throw new RuntimeException(
"Unhandled argument type: "
+ argumentType
+ " in "
+ ownerClass
+ "."
+ methodName
+ methodDescriptor);
}
}
return types;
}
@Override
protected boolean isArrayValue(final BasicValue value) {
Type type = value.getType();
return type != null && (type.getSort() == Type.ARRAY || type.equals(NULL_TYPE));
}
public boolean isReference() {
return type != null && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
}
/**
* Convert class and field {@link Type} references to it's fully-qualified
* name. The class's implemented interfaces should get the fully-qualified
* name via {@link #getFullyQualifiedInterfaceName(Type)}.
*
* @param type {@code Type} used in a reference
* @return fully qualified name for {@code Type}
*/
public static String getFullyQualifiedTypeName(Type type) {
if (type.getSort() == Type.ARRAY) {
return Type.getType(type.toString().replaceAll("^\\[*", ""))
.getClassName();
}
return type.getClassName();
}