@Override
 public void compileIf(Label onElse, IEnvironmentMethod environment) {
   a.compile(true, environment);
   environment.getOutput().ifEQ(onElse);
   b.compile(true, environment);
   environment.getOutput().ifEQ(onElse);
 }
  @Override
  public Rvalue compile(IntermediateCompiler ic, Scope scope) throws SyntaxException {
    FunctionType funcType = getFunctionType(scope);

    // Reserve space for return value.
    if (!funcType.getReturnType().equals(CType.VOID))
      ic.emit("add", VirtualRegister.SP, "=" + funcType.getReturnType().getSize());

    // Push arguments to stack.
    argumentList.compile(ic, scope, funcType.getParameterTypes());

    // Evaluate the function pointer.
    Rvalue funcPtrVal = functionPointer.compile(ic, scope);

    // Make the call.
    ic.emit("call", VirtualRegister.SP, funcPtrVal.getRegister());

    // Read the return value.
    VirtualRegister retReg = null;
    if (!funcType.getReturnType().equals(CType.VOID)) {
      retReg = new VirtualRegister();
      ic.emit("pop", VirtualRegister.SP, retReg);
    }

    return new Rvalue(retReg);
  }
  @Override
  void compile(CompileContext ctx, boolean push) {
    boolean has_rest_arg = false;
    int arg_count = 0;
    for (int i = 0; init != null && i < init.size(); i++) {
      Expression exp = init.get(i);

      // System.out.println("st:"+ctx.get_stack_depth()+" before "+exp);

      if (exp.isRestArg()) {
        ((RestArgExpression) exp).compile(ctx, push, arg_count);
        has_rest_arg = true;
        break;
      }
      exp.compile(ctx, push);
      arg_count += 1;
    }

    // System.out.println("st:"+ctx.get_stack_depth()+" after loop");

    if (push) {
      ctx.emit_new_array(has_rest_arg ? 0 : arg_count, has_rest_arg);
      // System.out.println("st:"+ctx.get_stack_depth()+" after new_array("+arg_count+",
      // "+has_rest_arg+")");
    }
  }
  @Override
  public void compile(boolean result, IEnvironmentMethod environment) {
    // if not a: return false
    // if not b: return false
    // return true

    MethodOutput output = environment.getOutput();

    Label skip = new Label();
    a.compile(true, environment);
    output.ifEQ(skip);
    b.compile(true, environment);
    output.ifEQ(skip);
    output.iConst1();
    output.label(skip);

    if (!result) {
      output.pop();
    }
  }
Beispiel #5
0
  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;
    } 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)
  }