List of usage examples for org.objectweb.asm Opcodes INVOKEINTERFACE
int INVOKEINTERFACE
To view the source code for org.objectweb.asm Opcodes INVOKEINTERFACE.
Click Source Link
From source file:org.jboss.byteman.rule.expression.ComparisonExpression.java
License:Open Source License
public void compile(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); Expression oper0 = getOperand(0); Expression oper1 = getOperand(1); int removed = 0; // evaluate the operands and ensure the reuslt is of the correct type for comparison adds 2 oper0.compile(mv, compileContext);/*from w w w .ja v a 2 s . co m*/ compileTypeConversion(oper0.getType(), comparisonType, mv, compileContext); oper1.compile(mv, compileContext); compileTypeConversion(oper1.getType(), comparisonType, mv, compileContext); // now do the appropriate type of comparison if (comparisonType == type.B || comparisonType == type.S || comparisonType == type.S || comparisonType == type.I) { Label elsetarget = new Label(); Label endtarget = new Label(); // we remove 2 words from the stack and then add 1 back removed = 2; switch (oper) { case LT: mv.visitJumpInsn(Opcodes.IF_ICMPGE, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case LE: mv.visitJumpInsn(Opcodes.IF_ICMPGT, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case GT: mv.visitJumpInsn(Opcodes.IF_ICMPLE, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case GE: mv.visitJumpInsn(Opcodes.IF_ICMPLT, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case EQ: mv.visitJumpInsn(Opcodes.IF_ICMPNE, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case NE: mv.visitJumpInsn(Opcodes.IF_ICMPEQ, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; } } else if (comparisonType == type.J || comparisonType == type.F || comparisonType == type.D) { if (comparisonType == type.J) { mv.visitInsn(Opcodes.LCMP); // we remove four words from the stack and add 1 back removed = 4; } else if (comparisonType == type.F) { // we remove two words from the stack and add 1 back removed = 2; mv.visitInsn(Opcodes.FCMPG); } else if (comparisonType == type.D) { // we remove four words from the stack and add 1 back removed = 4; mv.visitInsn(Opcodes.DCMPG); } Label elsetarget = new Label(); Label endtarget = new Label(); switch (oper) { case LT: mv.visitJumpInsn(Opcodes.IFGE, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case LE: mv.visitJumpInsn(Opcodes.IFGT, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case GT: mv.visitJumpInsn(Opcodes.IFLE, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case GE: mv.visitJumpInsn(Opcodes.IFLT, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case EQ: mv.visitJumpInsn(Opcodes.IFNE, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case NE: mv.visitJumpInsn(Opcodes.IFEQ, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; } } else if (comparable) { // we add a further two words setting up the relevant test then remove them // and also remove the original two words replacing them with a single word removed = 4; compileContext.addStackCount(2); // we need to deal with null values correctly // if op1 == null || op2 == null // then // EQ: // push value1 == value2 // NE: // push value1 != value2 // ow: // push false // else // execute compareTo or equals and test for the desired outcome // end if Label splittarget = new Label(); // else Label jointarget = new Label(); // end if mv.visitInsn(Opcodes.DUP2); // [... op1, op2 ] ==> [... op1, op2, op1, op2] mv.visitInsn(Opcodes.POP); // [... op1, op2, op1, op2 ] ==> [... op1, op2, op1] // if op1 == null mv.visitJumpInsn(Opcodes.IFNULL, splittarget); // [... op1, op2, op1] ==> [... op1, op2] mv.visitInsn(Opcodes.DUP); // [... op1, op2 ] ==> [... op1, op2, op2] // || op2 == null mv.visitJumpInsn(Opcodes.IFNULL, splittarget); // [... op1, op2, op2] ==> [... op1, op2] // so, it is ok to call compareTo leaving an int or equals leaving a boolean if (oper != EQ && oper != NE) { mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I"); } else { mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z"); } // now if we did a compareTo we need to generate the required boolean Label elsetarget = new Label(); Label endtarget = new Label(); // if needed the convert the compareTo result to the required boolean outcome switch (oper) { case LT: mv.visitJumpInsn(Opcodes.IFGE, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case LE: mv.visitJumpInsn(Opcodes.IFGT, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case GT: mv.visitJumpInsn(Opcodes.IFLE, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case GE: mv.visitJumpInsn(Opcodes.IFLT, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); break; case NE: mv.visitJumpInsn(Opcodes.IFEQ, elsetarget); mv.visitLdcInsn(false); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(true); mv.visitLabel(endtarget); break; } // skip to the join point mv.visitJumpInsn(Opcodes.GOTO, jointarget); // label the split point mv.visitLabel(splittarget); if (oper == EQ) { elsetarget = new Label(); endtarget = new Label(); mv.visitJumpInsn(Opcodes.IF_ACMPEQ, elsetarget); mv.visitLdcInsn(false); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(true); mv.visitLabel(endtarget); } else if (oper == NE) { elsetarget = new Label(); endtarget = new Label(); mv.visitJumpInsn(Opcodes.IF_ACMPNE, elsetarget); mv.visitLdcInsn(false); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(true); mv.visitLabel(endtarget); } else { // pop the operands and stack false mv.visitInsn(Opcodes.POP2); mv.visitLdcInsn(false); } // label the join point mv.visitLabel(jointarget); } else if (comparisonType == Type.Z) { // unboxed booleans need special treatment // we remove two words replacing them with a single word removed = 2; Label elsetarget = new Label(); Label endtarget = new Label(); mv.visitJumpInsn(Opcodes.IFEQ, elsetarget); // on this branch for EQ the stacked value is what we need and for NE // the stacked value needs flipping if (oper == NE) { Label elsetarget2 = new Label(); mv.visitJumpInsn(Opcodes.IFEQ, elsetarget2); mv.visitLdcInsn(false); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget2); mv.visitLdcInsn(true); } mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); // on this branch for NE the stacked value is what we need and for EQ // the stacked value needs flipping if (oper == EQ) { Label elsetarget2 = new Label(); mv.visitJumpInsn(Opcodes.IFEQ, elsetarget2); mv.visitLdcInsn(false); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget2); mv.visitLdcInsn(true); } mv.visitLabel(endtarget); } else if (comparisonType == Type.BOOLEAN) { // boxed booleans need special treatment // we remove two words replacing them with a single word removed = 2; Label elsetarget = new Label(); Label endtarget = new Label(); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java.lang.Boolean", "equals", "(Ljava/lang/Boolean;)Z"); if (oper == NE) { mv.visitJumpInsn(Opcodes.IFEQ, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); } } else { // we remove two words replacing them with a single word removed = 2; Label elsetarget = new Label(); Label endtarget = new Label(); if (oper == EQ) { mv.visitJumpInsn(Opcodes.IF_ACMPNE, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); } else { mv.visitJumpInsn(Opcodes.IF_ACMPEQ, elsetarget); mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endtarget); mv.visitLabel(elsetarget); mv.visitLdcInsn(false); mv.visitLabel(endtarget); } } compileContext.addStackCount(1 - removed); }
From source file:org.jboss.byteman.rule.expression.DollarExpression.java
License:Open Source License
public void compile(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); String targetName = binding.getName(); int currentStack = compileContext.getStackCount(); int expected = (type.getNBytes() > 4 ? 2 : 1); // TODO/*w ww . j a v a 2 s .com*/ // optimise compile of trigger class and trigger method just to push the required String literal // ditto for $# or any other binding which is known in advance if (index == HELPER_IDX) { // reference to the current helper so just stack this mv.visitVarInsn(Opcodes.ALOAD, 0); compileContext.addStackCount(1); } else { // stack the current helper // stack the name for the variable // call the getBinding method mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitLdcInsn(targetName); compileContext.addStackCount(2); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "getBinding", "(Ljava/lang/String;)Ljava/lang/Object;"); compileContext.addStackCount(-1); // perform any necessary type conversion if (type.isPrimitive()) { // cast down to the boxed type then do an unbox Type boxType = Type.boxType(type); compileObjectConversion(Type.OBJECT, boxType, mv, compileContext); compileUnbox(boxType, type, mv, compileContext); } else { // cast down to the required type compileObjectConversion(Type.OBJECT, type, mv, compileContext); } } // ensure we have only increased the stack by the return value size if (compileContext.getStackCount() != currentStack + expected) { throw new CompileException("DollarExpression.compile : invalid stack height " + compileContext.getStackCount() + " expecting " + (currentStack + expected)); } }
From source file:org.jboss.byteman.rule.expression.DollarExpression.java
License:Open Source License
@Override public void compileAssign(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); String targetName = binding.getName(); int currentStack = compileContext.getStackCount(); int size = ((type.getNBytes() > 4) ? 2 : 1); if (index == HELPER_IDX) { // not allowed to reassign the helper binding throw new CompileException("DollarExpression.compileAssign : invalid assignment to helper binding $$"); } else {/*from ww w. jav a 2 s. com*/ // value to be assigned is TOS and will already be coerced to the correct value type // copy it so we leave it as a a return value on the stack if (size == 2) { mv.visitInsn(Opcodes.DUP2); } else { mv.visitInsn(Opcodes.DUP); } // stack the current helper then insert it below the value mv.visitVarInsn(Opcodes.ALOAD, 0); if (size == 2) { // use a DUP_X2 to push a copy below the value then pop the redundant value mv.visitInsn(Opcodes.DUP_X2); mv.visitInsn(Opcodes.POP); } else { // we can just swap the two values mv.visitInsn(Opcodes.SWAP); } // stack the name for the variable and swap below the value mv.visitLdcInsn(targetName); if (size == 2) { // use a DUP_X2 to push a copy below the value then pop the redundant value mv.visitInsn(Opcodes.DUP_X2); // this is the high water mark // at this point the stack has gone from [ .. val1 val2] to [.. val1 val2 helper name val1 val2 name] compileContext.addStackCount(5); mv.visitInsn(Opcodes.POP); compileContext.addStackCount(-1); } else { // this is the high water mark // at this point the stack has gone from [ .. val] to [.. val helper val name] compileContext.addStackCount(3); // we can just swap the two values mv.visitInsn(Opcodes.SWAP); } // ensure we have an object compileObjectConversion(type, Type.OBJECT, mv, compileContext); // call the setBinding method mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "setBinding", "(Ljava/lang/String;Ljava/lang/Object;)V"); // the call will remove 3 from the stack height compileContext.addStackCount(-3); // ok, the stack height should be as it was if (compileContext.getStackCount() != currentStack) { throw new CompileException("variable.compileAssignment : invalid stack height " + compileContext.getStackCount() + " expecting " + currentStack); } } }
From source file:org.jboss.byteman.rule.expression.FieldExpression.java
License:Open Source License
public void compile(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); int currentStack = compileContext.getStackCount(); int expected = (type.getNBytes() > 4 ? 2 : 1); if (indirectStatic != null) { // this is just wrapping a static field expression so compile it indirectStatic.compile(mv, compileContext); } else if (isArrayLength) { owner.compile(mv, compileContext); mv.visitInsn(Opcodes.ARRAYLENGTH); // we removed the owner and replaced with expected words compileContext.addStackCount(expected - 1); } else {// w w w . j a v a 2 s . c o m if (isPublicField) { // we can use GETFIELD to access a public field String ownerType = Type.internalName(field.getDeclaringClass()); String fieldName = field.getName(); String fieldType = Type.internalName(field.getType(), true); // compile the owner expression owner.compile(mv, compileContext); mv.visitFieldInsn(Opcodes.GETFIELD, ownerType, fieldName, fieldType); // we removed the owner and replaced with expected words compileContext.addStackCount(expected - 1); } else { // since this is a private field we need to do the access using reflection // stack the helper, owner and the field index mv.visitVarInsn(Opcodes.ALOAD, 0); compileContext.addStackCount(1); owner.compile(mv, compileContext); mv.visitLdcInsn(fieldIndex); compileContext.addStackCount(1); // use the HelperAdapter method getAccessibleField to get the field value mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "getAccessibleField", "(Ljava/lang/Object;I)Ljava/lang/Object;"); // we popped three words and added one object as result compileContext.addStackCount(-2); // convert Object to primitive or cast to subtype if required compileTypeConversion(Type.OBJECT, type, mv, compileContext); } } // check the stack height is ok if (compileContext.getStackCount() != currentStack + expected) { throw new CompileException("FieldExpression.compile : invalid stack height " + compileContext.getStackCount() + " expecting " + (currentStack + expected)); } }
From source file:org.jboss.byteman.rule.expression.FieldExpression.java
License:Open Source License
@Override public void compileAssign(MethodVisitor mv, CompileContext compileContext) throws CompileException { if (indirectStatic != null) { // this is just wrapping a static field expression so compile it indirectStatic.compileAssign(mv, compileContext); } else {/*from w w w . j a va2 s. c om*/ // make sure we are at the right source line compileContext.notifySourceLine(line); int currentStack = compileContext.getStackCount(); int size = (type.getNBytes() > 4 ? 2 : 1); // copy the value so we leave it as a result if (size == 1) { // this means at the maximum we add 1 to the current stack // [.. val] ==> [.. val val] mv.visitInsn(Opcodes.DUP); } else { // [.. val1 val2] ==> [.. val1 val2 val1 val2] mv.visitInsn(Opcodes.DUP2); } compileContext.addStackCount(size); // compile the owner expression and swap with the value owner.compile(mv, compileContext); if (size == 1) { // [.. val val owner] ==> [.. val owner val] mv.visitInsn(Opcodes.SWAP); } else { // we have to use a DUP_X2 and a POP to insert the owner below the two word value // i.e. [.. val1 val2 val1 val2] ==> [.. val1 val2 val1 val2 owner] ==> // [.. val1 val2 owner val1 val2 owner] ==> [.. val1 val2 owner val1 val2] mv.visitInsn(Opcodes.DUP_X2); compileContext.addStackCount(1); mv.visitInsn(Opcodes.POP); compileContext.addStackCount(-1); } if (isPublicField) { // now compile a field update String ownerType = Type.internalName(field.getDeclaringClass()); String fieldName = field.getName(); String fieldType = Type.internalName(field.getType(), true); mv.visitFieldInsn(Opcodes.PUTFIELD, ownerType, fieldName, fieldType); // we removed the owner and the value compileContext.addStackCount(-(1 + size)); } else { // since this is a private field we need to do the update using reflection // box the value to an object if necessary if (type.isPrimitive()) { compileBox(Type.boxType(type), mv, compileContext); } // stack the helper and then dupx2 it so it goes under the owner and value // [.. val(s) owner valObj ==> val(s) owner valObj helper ] mv.visitVarInsn(Opcodes.ALOAD, 0); // [.. val(s) owner valObj helper ==> val(s) helper owner valObj helper ] mv.visitInsn(Opcodes.DUP_X2); // stack now has 2 more words so count them compileContext.addStackCount(2); // now pop the redundant top word and stack the field index instead // [.. val(s) helper owner valObj helper ==> val(s) helper owner valObj index ] mv.visitInsn(Opcodes.POP); mv.visitLdcInsn(fieldIndex); // use the HelperAdapter method setAccessibleField to set the field value mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "setAccessibleField", "(Ljava/lang/Object;Ljava/lang/Object;I)V"); // we popped four args compileContext.addStackCount(-4); } // check the stack height is ok if (compileContext.getStackCount() != currentStack) { throw new CompileException("FieldExpression.compileAssign : invalid stack height " + compileContext.getStackCount() + " expecting " + (currentStack)); } } }
From source file:org.jboss.byteman.rule.expression.MethodExpression.java
License:Open Source License
public void compile(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); int currentStack = compileContext.getStackCount(); int extraParams = 0; // space used by stacked args after conversion int expected = 0; // no need for type conversion as return type was derived from method if (type.getNBytes() > 4) { expected = 2;/*from w w w. j a v a 2 s . co m*/ } else if (type != Type.VOID) { expected = 1; } else { expected = 0; } int argCount = arguments.size(); if (isPublicMethod) { // we can just do this as a direct call // stack the recipient if necessary then stack the args and then invoke the method if (recipient != null) { // compile code for recipient recipient.compile(mv, compileContext); extraParams += 1; } for (int i = 0; i < argCount; i++) { Expression argument = arguments.get(i); Type argType = argumentTypes.get(i); Type paramType = paramTypes.get(i); // compile code to stack argument and type convert if necessary argument.compile(mv, compileContext); compileTypeConversion(argType, paramType, mv, compileContext); // allow for stacked paramType value extraParams += (paramType.getNBytes() > 4 ? 2 : 1); } // enable triggering before we call the method // this adds an extra value to the stack so modify the compile context to ensure // we increase the maximum height if necessary mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jboss/byteman/rule/Rule", "enableTriggersInternal", "()Z"); compileContext.addStackCount(1); mv.visitInsn(Opcodes.POP); compileContext.addStackCount(-1); // ok, now just call the method -- removes extraParams words String ownerName = Type.internalName(method.getDeclaringClass()); if (recipient == null) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, ownerName, method.getName(), getDescriptor()); } else if (method.getDeclaringClass().isInterface()) { mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, ownerName, method.getName(), getDescriptor()); } else { mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ownerName, method.getName(), getDescriptor()); } // decrement the stack height to account for stacked param values (removed) and return value (added) compileContext.addStackCount(expected - extraParams); // now disable triggering again // this temporarily adds an extra value to the stack -- n.b. we *must* increment and // then decrement the stack height even though we bumped the max before the call. in // some cases the stack may be larger after the method call than before e.g. calling // a static which returns a value or calling a non-static which returns a long/double mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jboss/byteman/rule/Rule", "disableTriggersInternal", "()Z"); compileContext.addStackCount(1); mv.visitInsn(Opcodes.POP); compileContext.addStackCount(-1); } else { // if we are calling a method by reflection then we need to stack the current helper then // the recipient or null if there is none and then build an object array on the stack mv.visitVarInsn(Opcodes.ALOAD, 0); compileContext.addStackCount(1); if (recipient != null) { // compile code for recipient recipient.compile(mv, compileContext); } else { mv.visitInsn(Opcodes.ACONST_NULL); compileContext.addStackCount(1); } // stack arg count then create a new array mv.visitLdcInsn(argCount); compileContext.addStackCount(1); // this just swaps one word for another mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); // duplicate the array, stack the index, compile code to generate the arg and the do an array put for (int i = 0; i < argCount; i++) { mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(i); // that was two extra words compileContext.addStackCount(2); Expression argument = arguments.get(i); Type argType = argumentTypes.get(i); Type paramType = paramTypes.get(i); // compile code to stack argument and type convert/box if necessary argument.compile(mv, compileContext); compileTypeConversion(argType, paramType, mv, compileContext); compileBox(paramType, mv, compileContext); // that's 3 extra words which now get removed mv.visitInsn(Opcodes.AASTORE); compileContext.addStackCount(-3); } // now stack the method object index mv.visitLdcInsn(methodIndex); compileContext.addStackCount(1); // enable triggering before we call the method // this adds an extra value to the stack so modify the compile context to ensure // we increase the maximum height if necessary mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jboss/byteman/rule/Rule", "enableTriggersInternal", "()Z"); compileContext.addStackCount(1); mv.visitInsn(Opcodes.POP); compileContext.addStackCount(-1); // ok, we now have the recipient, args array and method index on the stack // so we can call the HelperAdapter method to do the actual reflective invocation mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "invokeAccessibleMethod", "(Ljava/lang/Object;[Ljava/lang/Object;I)Ljava/lang/Object;"); // we popped 4 words and left one in its place compileContext.addStackCount(-3); if (type == Type.VOID) { mv.visitInsn(Opcodes.POP); compileContext.addStackCount(-1); } else { // do any necessary casting and/or unboxing compileTypeConversion(Type.OBJECT, type, mv, compileContext); } // now disable triggering again // this temporarily adds an extra value to the stack -- n.b. no need to increment and // then decrement the stack height here because the previous enable call will already have // bumped the max when we had 4 slots on the stack and any return value on the stack will // occupy at most 2 slots mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jboss/byteman/rule/Rule", "disableTriggersInternal", "()Z"); compileContext.addStackCount(1); mv.visitInsn(Opcodes.POP); compileContext.addStackCount(-1); } // ensure we have only increased the stack by the return value size if (compileContext.getStackCount() != currentStack + expected) { throw new CompileException("MethodExpression.compile : invalid stack height " + compileContext.getStackCount() + " expecting " + (currentStack + expected)); } // no need to update max stack since compiling the recipient or arguments will // have done so (and there will be no change if there was no such compile call) }
From source file:org.jboss.byteman.rule.expression.StaticExpression.java
License:Open Source License
public void compile(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); int currentStack = compileContext.getStackCount(); int expected; // compile a field access if (isPublicField) { String ownerType = Type.internalName(field.getDeclaringClass()); String fieldName = field.getName(); String fieldType = Type.internalName(field.getType(), true); mv.visitFieldInsn(Opcodes.GETSTATIC, ownerType, fieldName, fieldType); expected = (type.getNBytes() > 4 ? 2 : 1); compileContext.addStackCount(expected); } else {//from w w w . ja va2s . c o m // since this is a private field we need to do the access using reflection // stack the helper, a null owner and the field index mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitInsn(Opcodes.ACONST_NULL); mv.visitLdcInsn(fieldIndex); compileContext.addStackCount(3); // use the HelperAdapter method getAccessibleField to get the field value mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "getAccessibleField", "(Ljava/lang/Object;I)Ljava/lang/Object;"); // we popped three words and added one object as result compileContext.addStackCount(-2); // convert Object to primitive or cast to subtype if required compileTypeConversion(Type.OBJECT, type, mv, compileContext); } }
From source file:org.jboss.byteman.rule.expression.StaticExpression.java
License:Open Source License
@Override public void compileAssign(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); int currentStack = compileContext.getStackCount(); int size = (type.getNBytes() > 4 ? 2 : 1); // copy the value so we leave a result // increases stack height by size words if (size == 1) { mv.visitInsn(Opcodes.DUP);//from w w w . j av a2 s. c om } else { mv.visitInsn(Opcodes.DUP2); } compileContext.addStackCount(size); // compile a static field update if (isPublicField) { String ownerType = Type.internalName(field.getDeclaringClass()); String fieldName = field.getName(); String fieldType = Type.internalName(field.getType(), true); compileContext.addStackCount(-size); mv.visitFieldInsn(Opcodes.PUTSTATIC, ownerType, fieldName, fieldType); } else { // since this is a private field we need to do the update using reflection // box the value to an object if necessary // [.. val(s) val(s) ==> val(s) valObj] if (type.isPrimitive()) { compileBox(Type.boxType(type), mv, compileContext); } // stack the helper and then swap it so it goes under the value // [.. val(s) valObj ==> val(s) valObj helper ==> val(s) helper valObj] mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitInsn(Opcodes.SWAP); // stack a null owner then swap it so it goes under the value // [val(s) helper valObj ==> val(s) helper valObj null ==> val(s) helper null valObj] mv.visitInsn(Opcodes.ACONST_NULL); mv.visitInsn(Opcodes.SWAP); // now stack the field index // [.. val(s) helper null valObj ==> val(s) helper null valObj index ] mv.visitLdcInsn(fieldIndex); // we added three more words compileContext.addStackCount(3); // use the HelperAdapter method setAccessibleField to set the field value mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "setAccessibleField", "(Ljava/lang/Object;Ljava/lang/Object;I)V"); // we popped four args compileContext.addStackCount(-4); } if (compileContext.getStackCount() != currentStack) { throw new CompileException("StaticExpression.compileAssign : invalid stack height " + compileContext.getStackCount() + " expecting " + currentStack); } }
From source file:org.jboss.byteman.rule.expression.Variable.java
License:Open Source License
public void compile(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); // stack the current helper // stack the name for the variable // call the getBinding method mv.visitVarInsn(Opcodes.ALOAD, 0);//from w ww. ja va2 s. co m mv.visitLdcInsn(name); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "getBinding", "(Ljava/lang/String;)Ljava/lang/Object;"); // ok, we added 2 to the stack and then popped them leaving 1 compileContext.addStackCount(2); compileContext.addStackCount(-1); // perform any necessary type conversion if (type.isPrimitive()) { // cast down to the boxed type then do an unbox Type boxType = Type.boxType(type); compileObjectConversion(Type.OBJECT, boxType, mv, compileContext); compileUnbox(boxType, type, mv, compileContext); } else { // cast down to the required type compileObjectConversion(Type.OBJECT, type, mv, compileContext); } }
From source file:org.jboss.byteman.rule.expression.Variable.java
License:Open Source License
@Override public void compileAssign(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); int currentStack = compileContext.getStackCount(); int size = ((type.getNBytes() > 4) ? 2 : 1); int max;/* w ww .ja v a 2s . co m*/ // value to be assigned is TOS and will already be coerced to the correct value type // copy it so we leave it as a a return value on the stack if (size == 2) { // [... val1 val2 ==> ... val1 val2 val1 val2] mv.visitInsn(Opcodes.DUP2); } else { // [... val ==> ... val val] mv.visitInsn(Opcodes.DUP); } // stack the current helper then insert it below the value mv.visitVarInsn(Opcodes.ALOAD, 0); if (size == 2) { // use a DUP_X2 to push a copy below the value then pop the redundant value // [... val1 val2 val1 val2 helper ==> ... val1 val2 helper val1 val2 helper] mv.visitInsn(Opcodes.DUP_X2); // [... val1 val2 helper val1 val2 helper ==> ... val1 val2 helper val1 val2] mv.visitInsn(Opcodes.POP); } else { // we can just swap the two values // [... val val helper ==> ... val helper val] mv.visitInsn(Opcodes.SWAP); } // stack the name for the variable and swap below the value mv.visitLdcInsn(name); if (size == 2) { // use a DUP_X2 to push a copy below the value then pop the redundant value // [... val1 val2 helper val1 val2 name ==> [... val1 val2 helper name val1 val2 name] mv.visitInsn(Opcodes.DUP_X2); // this is the high water mark compileContext.addStackCount(5); // [... val1 val2 helper name val1 val2 name ==> [... val1 val2 helper name val1 val2] mv.visitInsn(Opcodes.POP); compileContext.addStackCount(-1); // and now we have the desired arrangement for the call[.. val1 val2 helper name val1 val2] } else { // this is the high water mark // at this point the stack has gone from [ .. val] to [.. val helper val name] compileContext.addStackCount(3); // we can just swap the two values // [... val helper val name ==> ... val helper name val] mv.visitInsn(Opcodes.SWAP); // and now we have the desired arrangement for the call[.. val helper name val] } // ensure we have an object compileObjectConversion(type, Type.OBJECT, mv, compileContext); // call the setBinding method mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "setBinding", "(Ljava/lang/String;Ljava/lang/Object;)V"); // the call will remove 3 from the stack height compileContext.addStackCount(-3); // ok, the stack height should be as it was if (compileContext.getStackCount() != currentStack) { throw new CompileException("variable.compileAssignment : invalid stack height " + compileContext.getStackCount() + " expecting " + currentStack); } }