/** * Visits a type instruction. A type instruction is an instruction that takes the internal name of * a class as parameter. * * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, * ANEWARRAY, CHECKCAST or INSTANCEOF. * @param type the operand of the instruction to be visited. This operand must be the internal * name of an object or array class (see {@link Type#getInternalName()}). */ public void visitTypeInsn(final int opcode, final String type) { if (mv != null) { mv.visitTypeInsn(opcode, type); } }
/** * Visits a type instruction. A type instruction is an instruction that takes the internal name of * a class as parameter. * * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, * ANEWARRAY, CHECKCAST or INSTANCEOF. * @param type the operand of the instruction to be visited. This operand must be the internal * name of an object or array class (see {@link Type#getInternalName()}). */ public void visitTypeInsn(final int opcode, final String type) { if (mv != null) { mv.visitTypeInsn(opcode, type); } }
/** * Insert the appropriate CHECKCAST instruction for the supplied descriptor. * @param mv the target visitor into which the instruction should be inserted * @param descriptor the descriptor of the type to cast to */ public static void insertCheckCast(MethodVisitor mv, @Nullable String descriptor) { if (descriptor != null && descriptor.length() != 1) { if (descriptor.charAt(0) == '[') { if (isPrimitiveArray(descriptor)) { mv.visitTypeInsn(CHECKCAST, descriptor); } else { mv.visitTypeInsn(CHECKCAST, descriptor + ";"); } } else { if (!descriptor.equals("Ljava/lang/Object")) { // This is chopping off the 'L' to leave us with "java/lang/String" mv.visitTypeInsn(CHECKCAST, descriptor.substring(1)); } } } }
case 'D': if (stackDescriptor.equals("Ljava/lang/Object")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Number"); case 'F': if (stackDescriptor.equals("Ljava/lang/Object")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Number"); case 'J': if (stackDescriptor.equals("Ljava/lang/Object")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Number"); case 'I': if (stackDescriptor.equals("Ljava/lang/Object")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
/** * Produce the correct bytecode to build an array. The opcode to use and the * signature to pass along with the opcode can vary depending on the signature * of the array type. * @param mv the methodvisitor into which code should be inserted * @param size the size of the array * @param arraytype the type of the array */ public static void insertNewArrayCode(MethodVisitor mv, int size, String arraytype) { insertOptimalLoad(mv, size); if (arraytype.length() == 1) { mv.visitIntInsn(NEWARRAY, CodeFlow.arrayCodeFor(arraytype)); } else { if (arraytype.charAt(0) == '[') { // Handling the nested array case here. // If vararg is [[I then we want [I and not [I; if (CodeFlow.isReferenceTypeArray(arraytype)) { mv.visitTypeInsn(ANEWARRAY, arraytype + ";"); } else { mv.visitTypeInsn(ANEWARRAY, arraytype); } } else { mv.visitTypeInsn(ANEWARRAY, arraytype.substring(1)); } } }
case 'Z': if (!stackDescriptor.equals("Ljava/lang/Boolean")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean"); case 'B': if (!stackDescriptor.equals("Ljava/lang/Byte")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Byte"); case 'C': if (!stackDescriptor.equals("Ljava/lang/Character")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Character"); case 'D': if (!stackDescriptor.equals("Ljava/lang/Double")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Double"); case 'F': if (!stackDescriptor.equals("Ljava/lang/Float")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Float"); case 'I': if (!stackDescriptor.equals("Ljava/lang/Integer")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); case 'J': if (!stackDescriptor.equals("Ljava/lang/Long")) { mv.visitTypeInsn(CHECKCAST, "java/lang/Long"); case 'S':
/** * Insert the appropriate CHECKCAST instruction for the supplied descriptor. * @param mv the target visitor into which the instruction should be inserted * @param descriptor the descriptor of the type to cast to */ public static void insertCheckCast(MethodVisitor mv, @Nullable String descriptor) { if (descriptor != null && descriptor.length() != 1) { if (descriptor.charAt(0) == '[') { if (isPrimitiveArray(descriptor)) { mv.visitTypeInsn(CHECKCAST, descriptor); } else { mv.visitTypeInsn(CHECKCAST, descriptor + ";"); } } else { if (!descriptor.equals("Ljava/lang/Object")) { // This is chopping off the 'L' to leave us with "java/lang/String" mv.visitTypeInsn(CHECKCAST, descriptor.substring(1)); } } } }
@Override public void generateCode(MethodVisitor mv, CodeFlow cf) { ReflectiveConstructorExecutor executor = ((ReflectiveConstructorExecutor) this.cachedExecutor); Assert.state(executor != null, "No cached executor"); Constructor<?> constructor = executor.getConstructor(); String classDesc = constructor.getDeclaringClass().getName().replace('.', '/'); mv.visitTypeInsn(NEW, classDesc); mv.visitInsn(DUP); // children[0] is the type of the constructor, don't want to include that in argument processing SpelNodeImpl[] arguments = new SpelNodeImpl[this.children.length - 1]; System.arraycopy(this.children, 1, arguments, 0, this.children.length - 1); generateCodeForArguments(mv, cf, constructor, arguments); mv.visitMethodInsn(INVOKESPECIAL, classDesc, "<init>", CodeFlow.createSignatureDescriptor(constructor), false); cf.pushDescriptor(this.exitTypeDescriptor); }
@Override public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) { boolean isStatic = Modifier.isStatic(this.member.getModifiers()); String descriptor = cf.lastDescriptor(); String classDesc = this.member.getDeclaringClass().getName().replace('.', '/'); if (!isStatic) { if (descriptor == null) { cf.loadTarget(mv); } if (descriptor == null || !classDesc.equals(descriptor.substring(1))) { mv.visitTypeInsn(CHECKCAST, classDesc); } } else { if (descriptor != null) { // A static field/method call will not consume what is on the stack, // it needs to be popped off. mv.visitInsn(POP); } } if (this.member instanceof Method) { mv.visitMethodInsn((isStatic ? INVOKESTATIC : INVOKEVIRTUAL), classDesc, this.member.getName(), CodeFlow.createSignatureDescriptor((Method) this.member), false); } else { mv.visitFieldInsn((isStatic ? GETSTATIC : GETFIELD), classDesc, this.member.getName(), CodeFlow.toJvmDescriptor(((Field) this.member).getType())); } } }
int insn; if ("D".equals(this.exitTypeDescriptor)) { mv.visitTypeInsn(CHECKCAST, "[D"); insn = DALOAD; mv.visitTypeInsn(CHECKCAST, "[F"); insn = FALOAD; mv.visitTypeInsn(CHECKCAST, "[J"); insn = LALOAD; mv.visitTypeInsn(CHECKCAST, "[I"); insn = IALOAD; mv.visitTypeInsn(CHECKCAST, "[S"); insn = SALOAD; mv.visitTypeInsn(CHECKCAST, "[B"); insn = BALOAD; mv.visitTypeInsn(CHECKCAST, "[C"); insn = CALOAD; mv.visitTypeInsn(CHECKCAST, "["+ this.exitTypeDescriptor + (CodeFlow.isPrimitiveArray(this.exitTypeDescriptor) ? "" : ";")); mv.visitTypeInsn(CHECKCAST, "java/util/List"); cf.enterCompilationScope(); this.children[0].generateCode(mv, cf);
/** * Produce the correct bytecode to build an array. The opcode to use and the * signature to pass along with the opcode can vary depending on the signature * of the array type. * @param mv the methodvisitor into which code should be inserted * @param size the size of the array * @param arraytype the type of the array */ public static void insertNewArrayCode(MethodVisitor mv, int size, String arraytype) { insertOptimalLoad(mv, size); if (arraytype.length() == 1) { mv.visitIntInsn(NEWARRAY, CodeFlow.arrayCodeFor(arraytype)); } else { if (arraytype.charAt(0) == '[') { // Handling the nested array case here. // If vararg is [[I then we want [I and not [I; if (CodeFlow.isReferenceTypeArray(arraytype)) { mv.visitTypeInsn(ANEWARRAY, arraytype + ";"); } else { mv.visitTypeInsn(ANEWARRAY, arraytype); } } else { mv.visitTypeInsn(ANEWARRAY, arraytype.substring(1)); } } }
@Override public void generateCode(MethodVisitor mv, CodeFlow cf) { getLeftOperand().generateCode(mv, cf); CodeFlow.insertBoxIfNecessary(mv, cf.lastDescriptor()); Assert.state(this.type != null, "No type available"); if (this.type.isPrimitive()) { // always false - but left operand code always driven // in case it had side effects mv.visitInsn(POP); mv.visitInsn(ICONST_0); // value of false } else { mv.visitTypeInsn(INSTANCEOF, Type.getInternalName(this.type)); } cf.pushDescriptor(this.exitTypeDescriptor); }
@Override public void generateCode(MethodVisitor mv, CodeFlow cf) { ReflectiveConstructorExecutor executor = ((ReflectiveConstructorExecutor) this.cachedExecutor); Assert.state(executor != null, "No cached executor"); Constructor<?> constructor = executor.getConstructor(); String classDesc = constructor.getDeclaringClass().getName().replace('.', '/'); mv.visitTypeInsn(NEW, classDesc); mv.visitInsn(DUP); // children[0] is the type of the constructor, don't want to include that in argument processing SpelNodeImpl[] arguments = new SpelNodeImpl[this.children.length - 1]; System.arraycopy(this.children, 1, arguments, 0, this.children.length - 1); generateCodeForArguments(mv, cf, constructor, arguments); mv.visitMethodInsn(INVOKESPECIAL, classDesc, "<init>", CodeFlow.createSignatureDescriptor(constructor), false); cf.pushDescriptor(this.exitTypeDescriptor); }
/** * Walk through a possible tree of nodes that combine strings and append * them all to the same (on stack) StringBuilder. */ private void walk(MethodVisitor mv, CodeFlow cf, @Nullable SpelNodeImpl operand) { if (operand instanceof OpPlus) { OpPlus plus = (OpPlus)operand; walk(mv, cf, plus.getLeftOperand()); walk(mv, cf, plus.getRightOperand()); } else if (operand != null) { cf.enterCompilationScope(); operand.generateCode(mv,cf); if (!"Ljava/lang/String".equals(cf.lastDescriptor())) { mv.visitTypeInsn(CHECKCAST, "java/lang/String"); } cf.exitCompilationScope(); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); } }
@Override public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) { if (method == null) { try { method = Payload2.class.getDeclaredMethod("getField", String.class); } catch (Exception ex) { } } String descriptor = cf.lastDescriptor(); String memberDeclaringClassSlashedDescriptor = method.getDeclaringClass().getName().replace('.','/'); if (descriptor == null) { cf.loadTarget(mv); } if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) { mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor); } mv.visitLdcInsn(propertyName); mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(), CodeFlow.createSignatureDescriptor(method), false); } }
@Override public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) { boolean isStatic = Modifier.isStatic(this.member.getModifiers()); String descriptor = cf.lastDescriptor(); String classDesc = this.member.getDeclaringClass().getName().replace('.', '/'); if (!isStatic) { if (descriptor == null) { cf.loadTarget(mv); } if (descriptor == null || !classDesc.equals(descriptor.substring(1))) { mv.visitTypeInsn(CHECKCAST, classDesc); } } else { if (descriptor != null) { // A static field/method call will not consume what is on the stack, // it needs to be popped off. mv.visitInsn(POP); } } if (this.member instanceof Method) { mv.visitMethodInsn((isStatic ? INVOKESTATIC : INVOKEVIRTUAL), classDesc, this.member.getName(), CodeFlow.createSignatureDescriptor((Method) this.member), false); } else { mv.visitFieldInsn((isStatic ? GETSTATIC : GETFIELD), classDesc, this.member.getName(), CodeFlow.toJvmDescriptor(((Field) this.member).getType())); } } }
@Override public void generateCode(MethodVisitor mv, CodeFlow cf) { getLeftOperand().generateCode(mv, cf); CodeFlow.insertBoxIfNecessary(mv, cf.lastDescriptor()); Assert.state(this.type != null, "No type available"); if (this.type.isPrimitive()) { // always false - but left operand code always driven // in case it had side effects mv.visitInsn(POP); mv.visitInsn(ICONST_0); // value of false } else { mv.visitTypeInsn(INSTANCEOF, Type.getInternalName(this.type)); } cf.pushDescriptor(this.exitTypeDescriptor); }
@Override public void generateCode(MethodVisitor mv, CodeFlow cf) { if ("Ljava/lang/String".equals(this.exitTypeDescriptor)) { mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
/** * Walk through a possible tree of nodes that combine strings and append * them all to the same (on stack) StringBuilder. */ private void walk(MethodVisitor mv, CodeFlow cf, @Nullable SpelNodeImpl operand) { if (operand instanceof OpPlus) { OpPlus plus = (OpPlus)operand; walk(mv, cf, plus.getLeftOperand()); walk(mv, cf, plus.getRightOperand()); } else if (operand != null) { cf.enterCompilationScope(); operand.generateCode(mv,cf); if (!"Ljava/lang/String".equals(cf.lastDescriptor())) { mv.visitTypeInsn(CHECKCAST, "java/lang/String"); } cf.exitCompilationScope(); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); } }
void generateClinitCode(String clazzname, String constantFieldName, MethodVisitor mv, CodeFlow codeflow, boolean nested) { mv.visitTypeInsn(NEW, "java/util/ArrayList"); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V", false);