public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
    if (!valueRequired) currentScope.problemReporter().unusedObjectAllocation(this);

    int pc = codeStream.position;
    MethodBinding codegenBinding = this.binding.original();
    ReferenceBinding allocatedType = codegenBinding.declaringClass;

    codeStream.new_(allocatedType);
    boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0;
    if (valueRequired || isUnboxing) {
      codeStream.dup();
    }
    // better highlight for allocation: display the type individually
    if (this.type != null) { // null for enum constant body
      codeStream.recordPositionsFrom(pc, this.type.sourceStart);
    } else {
      // push enum constant name and ordinal
      codeStream.ldc(String.valueOf(this.enumConstant.name));
      codeStream.generateInlinedValue(this.enumConstant.binding.id);
    }

    // handling innerclass instance allocation - enclosing instance arguments
    if (allocatedType.isNestedType()) {
      codeStream.generateSyntheticEnclosingInstanceValues(
          currentScope, allocatedType, enclosingInstance(), this);
    }
    // generate the arguments for constructor
    generateArguments(this.binding, this.arguments, currentScope, codeStream);
    // handling innerclass instance allocation - outer local arguments
    if (allocatedType.isNestedType()) {
      codeStream.generateSyntheticOuterArgumentValues(currentScope, allocatedType, this);
    }
    // invoke constructor
    if (this.syntheticAccessor == null) {
      codeStream.invoke(
          Opcodes.OPC_invokespecial, codegenBinding, null /* default declaringClass */);
    } else {
      // synthetic accessor got some extra arguments appended to its signature, which need values
      for (int i = 0,
              max = this.syntheticAccessor.parameters.length - codegenBinding.parameters.length;
          i < max;
          i++) {
        codeStream.aconst_null();
      }
      codeStream.invoke(
          Opcodes.OPC_invokespecial, this.syntheticAccessor, null /* default declaringClass */);
    }
    if (valueRequired) {
      codeStream.generateImplicitConversion(this.implicitConversion);
    } else if (isUnboxing) {
      // conversion only generated if unboxing
      codeStream.generateImplicitConversion(this.implicitConversion);
      switch (postConversionType(currentScope).id) {
        case T_long:
        case T_double:
          codeStream.pop2();
          break;
        default:
          codeStream.pop();
      }
    }
    codeStream.recordPositionsFrom(pc, this.sourceStart);
  }
  /** Generate invocation arguments, considering varargs methods */
  public void generateArguments(
      MethodBinding binding,
      Expression[] arguments,
      BlockScope currentScope,
      CodeStream codeStream) {
    if (binding.isVarargs()) {
      // 5 possibilities exist for a call to the vararg method foo(int i, int ... value) :
      //      foo(1), foo(1, null), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new int[] {1, 2})
      TypeBinding[] params = binding.parameters;
      int paramLength = params.length;
      int varArgIndex = paramLength - 1;
      for (int i = 0; i < varArgIndex; i++) {
        arguments[i].generateCode(currentScope, codeStream, true);
      }
      ArrayBinding varArgsType =
          (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type
      ArrayBinding codeGenVarArgsType = (ArrayBinding) binding.parameters[varArgIndex].erasure();
      int elementsTypeID = varArgsType.elementsType().id;
      int argLength = arguments == null ? 0 : arguments.length;

      if (argLength > paramLength) {
        // right number but not directly compatible or too many arguments - wrap extra into array
        // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4)
        // need to gen elements into an array, then gen each remaining element into created array
        codeStream.generateInlinedValue(argLength - varArgIndex);
        codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array
        for (int i = varArgIndex; i < argLength; i++) {
          codeStream.dup();
          codeStream.generateInlinedValue(i - varArgIndex);
          arguments[i].generateCode(currentScope, codeStream, true);
          codeStream.arrayAtPut(elementsTypeID, false);
        }
      } else if (argLength == paramLength) {
        // right number of arguments - could be inexact - pass argument as is
        TypeBinding lastType = arguments[varArgIndex].resolvedType;
        if (lastType == TypeBinding.NULL
            || (varArgsType.dimensions() == lastType.dimensions()
                && lastType.isCompatibleWith(varArgsType))) {
          // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is
          arguments[varArgIndex].generateCode(currentScope, codeStream, true);
        } else {
          // right number but not directly compatible or too many arguments - wrap extra into array
          // need to gen elements into an array, then gen each remaining element into created array
          codeStream.generateInlinedValue(1);
          codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array
          codeStream.dup();
          codeStream.generateInlinedValue(0);
          arguments[varArgIndex].generateCode(currentScope, codeStream, true);
          codeStream.arrayAtPut(elementsTypeID, false);
        }
      } else { // not enough arguments - pass extra empty array
        // scenario: foo(1) --> foo(1, new int[0])
        // generate code for an empty array of parameterType
        codeStream.generateInlinedValue(0);
        codeStream.newArray(null, codeGenVarArgsType); // create a mono-dimensional array
      }
    } else if (arguments != null) { // standard generation for method arguments
      for (int i = 0, max = arguments.length; i < max; i++)
        arguments[i].generateCode(currentScope, codeStream, true);
    }
  }
Beispiel #3
0
  /** Code generation for a array initializer */
  public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {

    // Flatten the values and compute the dimensions, by iterating in depth into nested array
    // initializers
    int pc = codeStream.position;
    int expressionLength = (this.expressions == null) ? 0 : this.expressions.length;
    codeStream.generateInlinedValue(expressionLength);
    codeStream.newArray(this.binding);
    if (this.expressions != null) {
      // binding is an ArrayType, so I can just deal with the dimension
      int elementsTypeID = this.binding.dimensions > 1 ? -1 : this.binding.leafComponentType.id;
      for (int i = 0; i < expressionLength; i++) {
        Expression expr;
        if ((expr = this.expressions[i]).constant != Constant.NotAConstant) {
          switch (elementsTypeID) { // filter out initializations to default values
            case T_int:
            case T_short:
            case T_byte:
            case T_char:
            case T_long:
              if (expr.constant.longValue() != 0) {
                codeStream.dup();
                codeStream.generateInlinedValue(i);
                expr.generateCode(currentScope, codeStream, true);
                codeStream.arrayAtPut(elementsTypeID, false);
              }
              break;
            case T_float:
            case T_double:
              double constantValue = expr.constant.doubleValue();
              if (constantValue == -0.0 || constantValue != 0) {
                codeStream.dup();
                codeStream.generateInlinedValue(i);
                expr.generateCode(currentScope, codeStream, true);
                codeStream.arrayAtPut(elementsTypeID, false);
              }
              break;
            case T_boolean:
              if (expr.constant.booleanValue() != false) {
                codeStream.dup();
                codeStream.generateInlinedValue(i);
                expr.generateCode(currentScope, codeStream, true);
                codeStream.arrayAtPut(elementsTypeID, false);
              }
              break;
            default:
              if (!(expr instanceof NullLiteral)) {
                codeStream.dup();
                codeStream.generateInlinedValue(i);
                expr.generateCode(currentScope, codeStream, true);
                codeStream.arrayAtPut(elementsTypeID, false);
              }
          }
        } else if (!(expr instanceof NullLiteral)) {
          codeStream.dup();
          codeStream.generateInlinedValue(i);
          expr.generateCode(currentScope, codeStream, true);
          codeStream.arrayAtPut(elementsTypeID, false);
        }
      }
    }
    if (valueRequired) {
      codeStream.generateImplicitConversion(this.implicitConversion);
    } else {
      codeStream.pop();
    }
    codeStream.recordPositionsFrom(pc, this.sourceStart);
  }