/** swap two top level operands */
 public void swap() {
   MethodVisitor mv = controller.getMethodVisitor();
   int size = stack.size();
   ClassNode b = stack.get(size - 1);
   ClassNode a = stack.get(size - 2);
   //        dup_x1:     ---
   //        dup_x2:     aab  -> baab
   //        dup2_x1:    abb  -> bbabb
   //        dup2_x2:    aabb -> bbaabb
   //        b = top element, a = element under b
   //        top element at right
   if (isTwoSlotType(a)) { // aa
     if (isTwoSlotType(b)) { // aabb
       // aabb -> bbaa
       mv.visitInsn(DUP2_X2); // bbaabb
       mv.visitInsn(POP2); // bbaa
     } else {
       // aab -> baa
       mv.visitInsn(DUP_X2); // baab
       mv.visitInsn(POP); // baa
     }
   } else { // a
     if (isTwoSlotType(b)) { // abb
       // abb -> bba
       mv.visitInsn(DUP2_X1); // bbabb
       mv.visitInsn(POP2); // bba
     } else {
       // ab -> ba
       mv.visitInsn(SWAP);
     }
   }
   stack.set(size - 1, a);
   stack.set(size - 2, b);
 }
 /**
  * ensure last marked parameter on the stack is a primitive boolean if mark==stack size, we assume
  * an empty expression or statement. was used and we will use the value given in emptyDefault as
  * boolean if mark==stack.size()-1 the top element will be cast to boolean using Groovy truth. In
  * other cases we throw a GroovyBugError
  */
 public void castToBool(int mark, boolean emptyDefault) {
   int size = stack.size();
   MethodVisitor mv = controller.getMethodVisitor();
   if (mark == size) {
     // no element, so use emptyDefault
     if (emptyDefault) {
       mv.visitIntInsn(BIPUSH, 1);
     } else {
       mv.visitIntInsn(BIPUSH, 0);
     }
     stack.add(null);
   } else if (mark == stack.size() - 1) {
     ClassNode last = stack.get(size - 1);
     // nothing to do in that case
     if (last == ClassHelper.boolean_TYPE) return;
     // not a primitive type, so call booleanUnbox
     if (!ClassHelper.isPrimitiveType(last)) {
       controller.getInvocationWriter().castNonPrimitiveToBool(last);
     } else {
       primitive2b(mv, last);
     }
   } else {
     throw new GroovyBugError(
         "operand stack contains " + stack.size() + " elements, but we expected only " + mark);
   }
   stack.set(mark, ClassHelper.boolean_TYPE);
 }
  public static void loadReference(String name, WriterController controller) {
    CompileStack compileStack = controller.getCompileStack();
    MethodVisitor mv = controller.getMethodVisitor();
    ClassNode classNode = controller.getClassNode();
    AsmClassGenerator acg = controller.getAcg();

    // compileStack.containsVariable(name) means to ask if the variable is already declared
    // compileStack.getScope().isReferencedClassVariable(name) means to ask if the variable is a
    // field
    // If it is no field and is not yet declared, then it is either a closure shared variable or
    // an already declared variable.
    if (!compileStack.containsVariable(name)
        && compileStack.getScope().isReferencedClassVariable(name)) {
      acg.visitFieldExpression(new FieldExpression(classNode.getDeclaredField(name)));
    } else {
      BytecodeVariable v =
          compileStack.getVariable(name, !classNodeUsesReferences(controller.getClassNode()));
      if (v == null) {
        // variable is not on stack because we are
        // inside a nested Closure and this variable
        // was not used before
        // then load it from the Closure field
        FieldNode field = classNode.getDeclaredField(name);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            controller.getInternalClassName(),
            name,
            BytecodeHelper.getTypeDescription(field.getType()));
      } else {
        mv.visitVarInsn(ALOAD, v.getIndex());
      }
      controller.getOperandStack().push(ClassHelper.REFERENCE_TYPE);
    }
  }
 public void storeVar(BytecodeVariable variable) {
   MethodVisitor mv = controller.getMethodVisitor();
   int idx = variable.getIndex();
   ClassNode type = variable.getType();
   // value is on stack
   if (variable.isHolder()) {
     doGroovyCast(type);
     box();
     mv.visitVarInsn(ALOAD, idx);
     mv.visitTypeInsn(CHECKCAST, "groovy/lang/Reference");
     mv.visitInsn(SWAP);
     mv.visitMethodInsn(
         INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V", false);
   } else {
     doGroovyCast(type);
     if (type == ClassHelper.double_TYPE) {
       mv.visitVarInsn(DSTORE, idx);
     } else if (type == ClassHelper.float_TYPE) {
       mv.visitVarInsn(FSTORE, idx);
     } else if (type == ClassHelper.long_TYPE) {
       mv.visitVarInsn(LSTORE, idx);
     } else if (type == ClassHelper.boolean_TYPE
         || type == ClassHelper.char_TYPE
         || type == ClassHelper.byte_TYPE
         || type == ClassHelper.int_TYPE
         || type == ClassHelper.short_TYPE) {
       mv.visitVarInsn(ISTORE, idx);
     } else {
       mv.visitVarInsn(ASTORE, idx);
     }
   }
   // remove RHS value from operand stack
   remove(1);
 }
  public boolean addGeneratedClosureConstructorCall(ConstructorCallExpression call) {
    ClassNode classNode = controller.getClassNode();
    if (!classNode.declaresInterface(ClassHelper.GENERATED_CLOSURE_Type)) return false;

    AsmClassGenerator acg = controller.getAcg();
    OperandStack operandStack = controller.getOperandStack();

    MethodVisitor mv = controller.getMethodVisitor();
    mv.visitVarInsn(ALOAD, 0);
    ClassNode callNode = classNode.getSuperClass();
    TupleExpression arguments = (TupleExpression) call.getArguments();
    if (arguments.getExpressions().size() != 2)
      throw new GroovyBugError(
          "expected 2 arguments for closure constructor super call, but got"
              + arguments.getExpressions().size());
    arguments.getExpression(0).visit(acg);
    operandStack.box();
    arguments.getExpression(1).visit(acg);
    operandStack.box();
    // TODO: replace with normal String, p not needed
    Parameter p = new Parameter(ClassHelper.OBJECT_TYPE, "_p");
    String descriptor =
        BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, new Parameter[] {p, p});
    mv.visitMethodInsn(
        INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor, false);
    operandStack.remove(2);
    return true;
  }
  public void loadOrStoreVariable(BytecodeVariable variable, boolean useReferenceDirectly) {
    CompileStack compileStack = controller.getCompileStack();

    if (compileStack.isLHS()) {
      storeVar(variable);
    } else {
      MethodVisitor mv = controller.getMethodVisitor();
      int idx = variable.getIndex();
      ClassNode type = variable.getType();

      if (variable.isHolder()) {
        mv.visitVarInsn(ALOAD, idx);
        if (!useReferenceDirectly) {
          mv.visitMethodInsn(
              INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;", false);
          BytecodeHelper.doCast(mv, type);
          push(type);
        } else {
          push(ClassHelper.REFERENCE_TYPE);
        }
      } else {
        load(type, idx);
      }
    }
  }
  protected void evaluateCompareExpression(
      MethodCaller compareMethod, BinaryExpression expression) {
    Expression leftExp = expression.getLeftExpression();
    TypeChooser typeChooser = controller.getTypeChooser();
    ClassNode cn = controller.getClassNode();
    ClassNode leftType = typeChooser.resolveType(leftExp, cn);
    Expression rightExp = expression.getRightExpression();
    ClassNode rightType = typeChooser.resolveType(rightExp, cn);

    boolean done = false;
    if (ClassHelper.isPrimitiveType(leftType) && ClassHelper.isPrimitiveType(rightType)) {
      BinaryExpressionMultiTypeDispatcher helper =
          new BinaryExpressionMultiTypeDispatcher(getController());
      done = helper.doPrimitiveCompare(leftType, rightType, expression);
    }

    if (!done) {
      AsmClassGenerator acg = controller.getAcg();
      OperandStack operandStack = controller.getOperandStack();

      leftExp.visit(acg);
      operandStack.box();
      rightExp.visit(acg);
      operandStack.box();

      compareMethod.call(controller.getMethodVisitor());
      ClassNode resType = ClassHelper.boolean_TYPE;
      if (compareMethod == findRegexMethod) {
        resType = ClassHelper.OBJECT_TYPE;
      }
      operandStack.replace(resType, 2);
    }
  }
 private void loadInitValue(ClassNode type) {
   MethodVisitor mv = controller.getMethodVisitor();
   if (ClassHelper.isPrimitiveType(type)) {
     mv.visitLdcInsn(0);
   } else {
     mv.visitInsn(ACONST_NULL);
   }
   controller.getOperandStack().push(type);
 }
 /** duplicate top element */
 public void dup() {
   ClassNode type = getTopOperand();
   stack.add(type);
   MethodVisitor mv = controller.getMethodVisitor();
   if (type == ClassHelper.double_TYPE || type == ClassHelper.long_TYPE) {
     mv.visitInsn(DUP2);
   } else {
     mv.visitInsn(DUP);
   }
 }
  private void evaluateElvisOperatorExpression(ElvisOperatorExpression expression) {
    MethodVisitor mv = controller.getMethodVisitor();
    CompileStack compileStack = controller.getCompileStack();
    OperandStack operandStack = controller.getOperandStack();
    TypeChooser typeChooser = controller.getTypeChooser();

    Expression boolPart = expression.getBooleanExpression().getExpression();
    Expression falsePart = expression.getFalseExpression();

    ClassNode truePartType = typeChooser.resolveType(boolPart, controller.getClassNode());
    ClassNode falsePartType = typeChooser.resolveType(falsePart, controller.getClassNode());
    ClassNode common = WideningCategories.lowestUpperBound(truePartType, falsePartType);

    // x?:y is equal to x?x:y, which evals to
    //      var t=x; boolean(t)?t:y
    // first we load x, dup it, convert the dupped to boolean, then
    // jump depending on the value. For true we are done, for false we
    // have to load y, thus we first remove x and then load y.
    // But since x and y may have different stack lengths, this cannot work
    // Thus we have to have to do the following:
    // Be X the type of x, Y the type of y and S the common supertype of
    // X and Y, then we have to see x?:y as
    //      var t=x;boolean(t)?S(t):S(y)
    // so we load x, dup it, store the value in a local variable (t), then
    // do boolean conversion. In the true part load t and cast it to S,
    // in the false part load y and cast y to S

    // load x, dup it, store one in $t and cast the remaining one to boolean
    int mark = operandStack.getStackLength();
    boolPart.visit(controller.getAcg());
    operandStack.dup();
    if (ClassHelper.isPrimitiveType(truePartType)
        && !ClassHelper.isPrimitiveType(operandStack.getTopOperand())) {
      truePartType = ClassHelper.getWrapper(truePartType);
    }
    int retValueId = compileStack.defineTemporaryVariable("$t", truePartType, true);
    operandStack.castToBool(mark, true);

    Label l0 = operandStack.jump(IFEQ);
    // true part: load $t and cast to S
    operandStack.load(truePartType, retValueId);
    operandStack.doGroovyCast(common);
    Label l1 = new Label();
    mv.visitJumpInsn(GOTO, l1);

    // false part: load false expression and cast to S
    mv.visitLabel(l0);
    falsePart.visit(controller.getAcg());
    operandStack.doGroovyCast(common);

    // finish and cleanup
    mv.visitLabel(l1);
    compileStack.removeVar(retValueId);
    controller.getOperandStack().replace(common, 2);
  }
 private void loadThis() {
   MethodVisitor mv = controller.getMethodVisitor();
   mv.visitVarInsn(ALOAD, 0);
   if (controller.isInClosure()) {
     mv.visitMethodInsn(
         INVOKEVIRTUAL, "groovy/lang/Closure", "getThisObject", "()Ljava/lang/Object;", false);
     controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
   } else {
     controller.getOperandStack().push(controller.getClassNode());
   }
 }
Example #12
0
 public ClassNode box() {
   MethodVisitor mv = controller.getMethodVisitor();
   int size = stack.size();
   ClassNode type = stack.get(size - 1);
   if (ClassHelper.isPrimitiveType(type) && ClassHelper.VOID_TYPE != type) {
     ClassNode wrapper = ClassHelper.getWrapper(type);
     BytecodeHelper.doCastToWrappedType(mv, type, wrapper);
     type = wrapper;
   } // else nothing to box
   stack.set(size - 1, type);
   return type;
 }
Example #13
0
 public void popDownTo(int elements) {
   int last = stack.size();
   MethodVisitor mv = controller.getMethodVisitor();
   while (last > elements) {
     last--;
     ClassNode element = popWithMessage(last);
     if (isTwoSlotType(element)) {
       mv.visitInsn(POP2);
     } else {
       mv.visitInsn(POP);
     }
   }
 }
  public void writeClosure(ClosureExpression expression) {
    CompileStack compileStack = controller.getCompileStack();
    MethodVisitor mv = controller.getMethodVisitor();
    ClassNode classNode = controller.getClassNode();
    AsmClassGenerator acg = controller.getAcg();

    // generate closure as public class to make sure it can be properly invoked by classes of the
    // Groovy runtime without circumventing JVM access checks (see CachedMethod for example).
    ClassNode closureClass = getOrAddClosureClass(expression, ACC_PUBLIC);
    String closureClassinternalName = BytecodeHelper.getClassInternalName(closureClass);
    List constructors = closureClass.getDeclaredConstructors();
    ConstructorNode node = (ConstructorNode) constructors.get(0);

    Parameter[] localVariableParams = node.getParameters();

    mv.visitTypeInsn(NEW, closureClassinternalName);
    mv.visitInsn(DUP);
    if (controller.isStaticMethod() || compileStack.isInSpecialConstructorCall()) {
      (new ClassExpression(classNode)).visit(acg);
      (new ClassExpression(controller.getOutermostClass())).visit(acg);
    } else {
      mv.visitVarInsn(ALOAD, 0);
      controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
      loadThis();
    }

    // now let's load the various parameters we're passing
    // we start at index 2 because the first variable we pass
    // is the owner instance and at this point it is already
    // on the stack
    for (int i = 2; i < localVariableParams.length; i++) {
      Parameter param = localVariableParams[i];
      String name = param.getName();
      loadReference(name, controller);
      if (param.getNodeMetaData(ClosureWriter.UseExistingReference.class) == null) {
        param.setNodeMetaData(ClosureWriter.UseExistingReference.class, Boolean.TRUE);
      }
    }

    // we may need to pass in some other constructors
    // cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", prototype + ")V");
    mv.visitMethodInsn(
        INVOKESPECIAL,
        closureClassinternalName,
        "<init>",
        BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, localVariableParams),
        false);
    controller.getOperandStack().replace(ClassHelper.CLOSURE_TYPE, localVariableParams.length);
  }
 private void writePowerCall(
     Expression receiver, Expression arguments, final ClassNode rType, ClassNode aType) {
   OperandStack operandStack = controller.getOperandStack();
   int m1 = operandStack.getStackLength();
   // slow Path
   prepareSiteAndReceiver(receiver, "power", false, controller.getCompileStack().isLHS());
   operandStack.doGroovyCast(getWrapper(rType));
   visitBoxedArgument(arguments);
   operandStack.doGroovyCast(getWrapper(aType));
   int m2 = operandStack.getStackLength();
   MethodVisitor mv = controller.getMethodVisitor();
   if (BigDecimal_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) {
     mv.visitMethodInsn(
         INVOKESTATIC,
         "org/codehaus/groovy/runtime/DefaultGroovyMethods",
         "power",
         "(Ljava/math/BigDecimal;Ljava/lang/Integer;)Ljava/lang/Number;",
         false);
   } else if (BigInteger_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) {
     mv.visitMethodInsn(
         INVOKESTATIC,
         "org/codehaus/groovy/runtime/DefaultGroovyMethods",
         "power",
         "(Ljava/math/BigInteger;Ljava/lang/Integer;)Ljava/lang/Number;",
         false);
   } else if (Long_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) {
     mv.visitMethodInsn(
         INVOKESTATIC,
         "org/codehaus/groovy/runtime/DefaultGroovyMethods",
         "power",
         "(Ljava/lang/Long;Ljava/lang/Integer;)Ljava/lang/Number;",
         false);
   } else if (Integer_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) {
     mv.visitMethodInsn(
         INVOKESTATIC,
         "org/codehaus/groovy/runtime/DefaultGroovyMethods",
         "power",
         "(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Number;",
         false);
   } else {
     mv.visitMethodInsn(
         INVOKESTATIC,
         "org/codehaus/groovy/runtime/DefaultGroovyMethods",
         "power",
         "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;",
         false);
   }
   controller.getOperandStack().replace(Number_TYPE, m2 - m1);
 }
 private void writeModCall(
     Expression receiver, Expression arguments, ClassNode rType, ClassNode aType) {
   prepareSiteAndReceiver(receiver, "mod", false, controller.getCompileStack().isLHS());
   controller.getOperandStack().doGroovyCast(Number_TYPE);
   visitBoxedArgument(arguments);
   controller.getOperandStack().doGroovyCast(Number_TYPE);
   MethodVisitor mv = controller.getMethodVisitor();
   mv.visitMethodInsn(
       INVOKESTATIC,
       "org/codehaus/groovy/runtime/typehandling/NumberMath",
       "mod",
       "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;",
       false);
   controller.getOperandStack().replace(Number_TYPE, 2);
 }
Example #17
0
  private void doConvertAndCast(ClassNode targetType, boolean coerce) {
    int size = stack.size();
    throwExceptionForNoStackElement(size, targetType, coerce);

    ClassNode top = stack.get(size - 1);
    targetType = targetType.redirect();
    if (targetType == top) return;

    if (coerce) {
      controller.getInvocationWriter().coerce(top, targetType);
      return;
    }

    boolean primTarget = ClassHelper.isPrimitiveType(targetType);
    boolean primTop = ClassHelper.isPrimitiveType(top);

    if (primTop && primTarget) {
      // here we box and unbox to get the goal type
      if (convertPrimitive(top, targetType)) {
        replace(targetType);
        return;
      }
      box();
    } else if (primTop) {
      // top is primitive, target is not
      // so box and do groovy cast
      controller.getInvocationWriter().castToNonPrimitiveIfNecessary(top, targetType);
    } else if (primTarget) {
      // top is not primitive so unbox
      // leave that BH#doCast later
    } else {
      controller.getInvocationWriter().castToNonPrimitiveIfNecessary(top, targetType);
    }

    MethodVisitor mv = controller.getMethodVisitor();
    if (primTarget
        && !ClassHelper.boolean_TYPE.equals(targetType)
        && !primTop
        && ClassHelper.getWrapper(targetType).equals(top)) {
      BytecodeHelper.doCastToPrimitive(mv, top, targetType);
    } else {
      top = stack.get(size - 1);
      if (!WideningCategories.implementsInterfaceOrSubclassOf(top, targetType)) {
        BytecodeHelper.doCast(mv, targetType);
      }
    }
    replace(targetType);
  }
  private void evaluateCompareTo(BinaryExpression expression) {
    Expression leftExpression = expression.getLeftExpression();
    AsmClassGenerator acg = controller.getAcg();
    OperandStack operandStack = controller.getOperandStack();

    leftExpression.visit(acg);
    operandStack.box();

    // if the right hand side is a boolean expression, we need to autobox
    Expression rightExpression = expression.getRightExpression();
    rightExpression.visit(acg);
    operandStack.box();

    compareToMethod.call(controller.getMethodVisitor());
    operandStack.replace(ClassHelper.Integer_TYPE, 2);
  }
 private void writeArrayGet(
     final Expression receiver,
     final Expression arguments,
     final ClassNode rType,
     final ClassNode aType) {
   OperandStack operandStack = controller.getOperandStack();
   int m1 = operandStack.getStackLength();
   // visit receiver
   receiver.visit(controller.getAcg());
   // visit arguments as array index
   arguments.visit(controller.getAcg());
   operandStack.doGroovyCast(int_TYPE);
   int m2 = operandStack.getStackLength();
   // array access
   controller.getMethodVisitor().visitInsn(AALOAD);
   operandStack.replace(rType.getComponentType(), m2 - m1);
 }
  private void evaluateInstanceof(BinaryExpression expression) {
    OperandStack operandStack = controller.getOperandStack();

    expression.getLeftExpression().visit(controller.getAcg());
    operandStack.box();
    Expression rightExp = expression.getRightExpression();
    ClassNode classType;
    if (rightExp instanceof ClassExpression) {
      ClassExpression classExp = (ClassExpression) rightExp;
      classType = classExp.getType();
    } else {
      throw new RuntimeException(
          "Right hand side of the instanceof keyword must be a class name, not: " + rightExp);
    }
    String classInternalName = BytecodeHelper.getClassInternalName(classType);
    controller.getMethodVisitor().visitTypeInsn(INSTANCEOF, classInternalName);
    operandStack.replace(ClassHelper.boolean_TYPE);
  }
 private void writeStringPlusCall(
     final Expression receiver, final String message, final Expression arguments) {
   // todo: performance would be better if we created a StringBuilder
   OperandStack operandStack = controller.getOperandStack();
   int m1 = operandStack.getStackLength();
   // slow Path
   prepareSiteAndReceiver(receiver, message, false, controller.getCompileStack().isLHS());
   visitBoxedArgument(arguments);
   int m2 = operandStack.getStackLength();
   MethodVisitor mv = controller.getMethodVisitor();
   mv.visitMethodInsn(
       INVOKESTATIC,
       "org/codehaus/groovy/runtime/DefaultGroovyMethods",
       "plus",
       "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;",
       false);
   controller.getOperandStack().replace(STRING_TYPE, m2 - m1);
 }
Example #22
0
 private boolean convertFromFloat(ClassNode target) {
   MethodVisitor mv = controller.getMethodVisitor();
   if (target == ClassHelper.int_TYPE) {
     mv.visitInsn(F2I);
     return true;
   } else if (target == ClassHelper.char_TYPE
       || target == ClassHelper.byte_TYPE
       || target == ClassHelper.short_TYPE) {
     mv.visitInsn(F2I);
     return convertFromInt(target);
   } else if (target == ClassHelper.long_TYPE) {
     mv.visitInsn(F2L);
     return true;
   } else if (target == ClassHelper.double_TYPE) {
     mv.visitInsn(F2D);
     return true;
   }
   return false;
 }
 boolean makeGetField(
     final Expression receiver,
     final ClassNode receiverType,
     final String fieldName,
     final boolean implicitThis,
     final boolean samePackage) {
   FieldNode field = receiverType.getField(fieldName);
   // direct access is allowed if we are in the same class as the declaring class
   // or we are in an inner class
   if (field != null && isDirectAccessAllowed(field, controller.getClassNode(), samePackage)) {
     CompileStack compileStack = controller.getCompileStack();
     MethodVisitor mv = controller.getMethodVisitor();
     if (field.isStatic()) {
       mv.visitFieldInsn(
           GETSTATIC,
           BytecodeHelper.getClassInternalName(field.getOwner()),
           fieldName,
           BytecodeHelper.getTypeDescription(field.getOriginType()));
       controller.getOperandStack().push(field.getOriginType());
     } else {
       if (implicitThis) {
         compileStack.pushImplicitThis(implicitThis);
       }
       receiver.visit(controller.getAcg());
       if (implicitThis) compileStack.popImplicitThis();
       if (!controller.getOperandStack().getTopOperand().isDerivedFrom(field.getOwner())) {
         mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(field.getOwner()));
       }
       mv.visitFieldInsn(
           GETFIELD,
           BytecodeHelper.getClassInternalName(field.getOwner()),
           fieldName,
           BytecodeHelper.getTypeDescription(field.getOriginType()));
     }
     controller.getOperandStack().replace(field.getOriginType());
     return true;
   }
   ClassNode superClass = receiverType.getSuperClass();
   if (superClass != null) {
     return makeGetField(receiver, superClass, fieldName, implicitThis, false);
   }
   return false;
 }
 private void writeNumberNumberCall(
     final Expression receiver, final String message, final Expression arguments) {
   OperandStack operandStack = controller.getOperandStack();
   int m1 = operandStack.getStackLength();
   // slow Path
   prepareSiteAndReceiver(receiver, message, false, controller.getCompileStack().isLHS());
   controller.getOperandStack().doGroovyCast(Number_TYPE);
   visitBoxedArgument(arguments);
   controller.getOperandStack().doGroovyCast(Number_TYPE);
   int m2 = operandStack.getStackLength();
   MethodVisitor mv = controller.getMethodVisitor();
   mv.visitMethodInsn(
       INVOKESTATIC,
       "org/codehaus/groovy/runtime/dgmimpl/NumberNumber" + MetaClassHelper.capitalize(message),
       message,
       "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;",
       false);
   controller.getOperandStack().replace(Number_TYPE, m2 - m1);
 }
Example #25
0
 private boolean convertFromInt(ClassNode target) {
   int convertCode;
   if (target == ClassHelper.char_TYPE) {
     convertCode = I2C;
   } else if (target == ClassHelper.byte_TYPE) {
     convertCode = I2B;
   } else if (target == ClassHelper.short_TYPE) {
     convertCode = I2S;
   } else if (target == ClassHelper.long_TYPE) {
     convertCode = I2L;
   } else if (target == ClassHelper.float_TYPE) {
     convertCode = I2F;
   } else if (target == ClassHelper.double_TYPE) {
     convertCode = I2D;
   } else {
     return false;
   }
   controller.getMethodVisitor().visitInsn(convertCode);
   return true;
 }
Example #26
0
  /** load the constant on the operand stack. */
  public void pushConstant(ConstantExpression expression) {
    MethodVisitor mv = controller.getMethodVisitor();
    Object value = expression.getValue();
    ClassNode origType = expression.getType().redirect();
    ClassNode type = ClassHelper.getUnwrapper(origType);
    boolean boxing = origType != type;
    boolean asPrimitive = boxing || ClassHelper.isPrimitiveType(type);

    if (value == null) {
      mv.visitInsn(ACONST_NULL);
    } else if (boxing && value instanceof Boolean) {
      // special path for boxed boolean
      Boolean bool = (Boolean) value;
      String text = bool ? "TRUE" : "FALSE";
      mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;");
      boxing = false;
      type = origType;
    } else if (asPrimitive) {
      pushPrimitiveConstant(mv, value, type);
    } else if (value instanceof BigDecimal) {
      String className = BytecodeHelper.getClassInternalName(value.getClass().getName());
      mv.visitTypeInsn(NEW, className);
      mv.visitInsn(DUP);
      mv.visitLdcInsn(value.toString());
      mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "(Ljava/lang/String;)V", false);
    } else if (value instanceof BigInteger) {
      String className = BytecodeHelper.getClassInternalName(value.getClass().getName());
      mv.visitTypeInsn(NEW, className);
      mv.visitInsn(DUP);
      mv.visitLdcInsn(value.toString());
      mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "(Ljava/lang/String;)V", false);
    } else if (value instanceof String) {
      mv.visitLdcInsn(value);
    } else {
      throw new ClassGeneratorException(
          "Cannot generate bytecode for constant: " + value + " of type: " + type.getName());
    }

    push(type);
    if (boxing) box();
  }
  private void evaluateNormalTernary(TernaryExpression expression) {
    MethodVisitor mv = controller.getMethodVisitor();
    OperandStack operandStack = controller.getOperandStack();
    TypeChooser typeChooser = controller.getTypeChooser();

    Expression boolPart = expression.getBooleanExpression();
    Expression truePart = expression.getTrueExpression();
    Expression falsePart = expression.getFalseExpression();

    ClassNode truePartType = typeChooser.resolveType(truePart, controller.getClassNode());
    ClassNode falsePartType = typeChooser.resolveType(falsePart, controller.getClassNode());
    ClassNode common = WideningCategories.lowestUpperBound(truePartType, falsePartType);

    // we compile b?x:y as
    //      boolean(b)?S(x):S(y), S = common super type of x,y
    // so we load b, do boolean conversion.
    // In the true part load x and cast it to S,
    // in the false part load y and cast y to S

    // load b and convert to boolean
    int mark = operandStack.getStackLength();
    boolPart.visit(controller.getAcg());
    operandStack.castToBool(mark, true);

    Label l0 = operandStack.jump(IFEQ);
    // true part: load x and cast to S
    truePart.visit(controller.getAcg());
    operandStack.doGroovyCast(common);
    Label l1 = new Label();
    mv.visitJumpInsn(GOTO, l1);

    // false part: load y and cast to S
    mv.visitLabel(l0);
    falsePart.visit(controller.getAcg());
    operandStack.doGroovyCast(common);

    // finish and cleanup
    mv.visitLabel(l1);
    controller.getOperandStack().replace(common, 2);
  }
  private void evaluateLogicalAndExpression(BinaryExpression expression) {
    MethodVisitor mv = controller.getMethodVisitor();
    AsmClassGenerator acg = controller.getAcg();
    OperandStack operandStack = controller.getOperandStack();

    expression.getLeftExpression().visit(acg);
    operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
    Label falseCase = operandStack.jump(IFEQ);

    expression.getRightExpression().visit(acg);
    operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
    operandStack.jump(IFEQ, falseCase);

    ConstantExpression.PRIM_TRUE.visit(acg);
    Label trueCase = new Label();
    mv.visitJumpInsn(GOTO, trueCase);

    mv.visitLabel(falseCase);
    ConstantExpression.PRIM_FALSE.visit(acg);

    mv.visitLabel(trueCase);
    operandStack.remove(1); // have to remove 1 because of the GOTO
  }
  private void evaluateLogicalOrExpression(BinaryExpression expression) {
    MethodVisitor mv = controller.getMethodVisitor();
    AsmClassGenerator acg = controller.getAcg();
    OperandStack operandStack = controller.getOperandStack();

    Label end = new Label();

    expression.getLeftExpression().visit(acg);
    operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
    Label trueCase = operandStack.jump(IFNE);

    expression.getRightExpression().visit(acg);
    operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
    Label falseCase = operandStack.jump(IFEQ);

    mv.visitLabel(trueCase);
    ConstantExpression.PRIM_TRUE.visit(acg);
    operandStack.jump(GOTO, end);

    mv.visitLabel(falseCase);
    ConstantExpression.PRIM_FALSE.visit(acg);

    mv.visitLabel(end);
  }
  @Override
  public void makeGetPropertySite(
      Expression receiver,
      final String methodName,
      final boolean safe,
      final boolean implicitThis) {
    Object dynamic =
        receiver.getNodeMetaData(StaticCompilationMetadataKeys.RECEIVER_OF_DYNAMIC_PROPERTY);
    if (dynamic != null) {
      MethodNode target =
          safe ? INVOKERHELPER_GETPROPERTYSAFE_METHOD : INVOKERHELPER_GETPROPERTY_METHOD;
      MethodCallExpression mce =
          new MethodCallExpression(
              new ClassExpression(INVOKERHELPER_TYPE),
              target.getName(),
              new ArgumentListExpression(receiver, new ConstantExpression(methodName)));
      mce.setSafe(false);
      mce.setImplicitThis(false);
      mce.setMethodTarget(target);
      mce.visit(controller.getAcg());
      return;
    }
    TypeChooser typeChooser = controller.getTypeChooser();
    ClassNode classNode = controller.getClassNode();
    ClassNode receiverType =
        (ClassNode) receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
    if (receiverType == null) {
      receiverType = typeChooser.resolveType(receiver, classNode);
    }
    Object type = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
    if (type == null && receiver instanceof VariableExpression) {
      Variable variable = ((VariableExpression) receiver).getAccessedVariable();
      if (variable instanceof Expression) {
        type = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
      }
    }
    if (type != null) {
      // in case a "flow type" is found, it is preferred to use it instead of
      // the declaration type
      receiverType = (ClassNode) type;
    }
    boolean isClassReceiver = false;
    if (isClassClassNodeWrappingConcreteType(receiverType)) {
      isClassReceiver = true;
      receiverType = receiverType.getGenericsTypes()[0].getType();
    }
    MethodVisitor mv = controller.getMethodVisitor();

    if (receiverType.isArray() && methodName.equals("length")) {
      receiver.visit(controller.getAcg());
      ClassNode arrayGetReturnType = typeChooser.resolveType(receiver, classNode);
      controller.getOperandStack().doGroovyCast(arrayGetReturnType);
      mv.visitInsn(ARRAYLENGTH);
      controller.getOperandStack().replace(int_TYPE);
      return;
    } else if ((receiverType.implementsInterface(COLLECTION_TYPE)
            || COLLECTION_TYPE.equals(receiverType))
        && ("size".equals(methodName) || "length".equals(methodName))) {
      MethodCallExpression expr =
          new MethodCallExpression(receiver, "size", ArgumentListExpression.EMPTY_ARGUMENTS);
      expr.setMethodTarget(COLLECTION_SIZE_METHOD);
      expr.setImplicitThis(implicitThis);
      expr.setSafe(safe);
      expr.visit(controller.getAcg());
      return;
    }
    if (makeGetPropertyWithGetter(receiver, receiverType, methodName, safe, implicitThis)) return;
    if (makeGetField(
        receiver,
        receiverType,
        methodName,
        implicitThis,
        samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
    if (receiverType.isEnum()) {
      mv.visitFieldInsn(
          GETSTATIC,
          BytecodeHelper.getClassInternalName(receiverType),
          methodName,
          BytecodeHelper.getTypeDescription(receiverType));
      controller.getOperandStack().push(receiverType);
      return;
    }
    if (receiver instanceof ClassExpression) {
      if (makeGetField(
          receiver,
          receiver.getType(),
          methodName,
          implicitThis,
          samePackages(receiver.getType().getPackageName(), classNode.getPackageName()))) return;
      if (makeGetPropertyWithGetter(receiver, receiver.getType(), methodName, safe, implicitThis))
        return;
      if (makeGetPrivateFieldWithBridgeMethod(
          receiver, receiver.getType(), methodName, safe, implicitThis)) return;
    }
    if (isClassReceiver) {
      // we are probably looking for a property of the class
      if (makeGetPropertyWithGetter(receiver, CLASS_Type, methodName, safe, implicitThis)) return;
      if (makeGetField(receiver, CLASS_Type, methodName, false, true)) return;
    }
    if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, methodName, safe, implicitThis))
      return;

    // GROOVY-5580, it is still possible that we're calling a superinterface property
    String getterName = "get" + MetaClassHelper.capitalize(methodName);
    if (receiverType.isInterface()) {
      Set<ClassNode> allInterfaces = receiverType.getAllInterfaces();
      MethodNode getterMethod = null;
      for (ClassNode anInterface : allInterfaces) {
        getterMethod = anInterface.getGetterMethod(getterName);
        if (getterMethod != null) break;
      }
      // GROOVY-5585
      if (getterMethod == null) {
        getterMethod = OBJECT_TYPE.getGetterMethod(getterName);
      }

      if (getterMethod != null) {
        MethodCallExpression call =
            new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
        call.setMethodTarget(getterMethod);
        call.setImplicitThis(false);
        call.setSourcePosition(receiver);
        call.visit(controller.getAcg());
        return;
      }
    }

    // GROOVY-5568, we would be facing a DGM call, but instead of foo.getText(), have foo.text
    List<MethodNode> methods =
        findDGMMethodsByNameAndArguments(
            controller.getSourceUnit().getClassLoader(),
            receiverType,
            getterName,
            ClassNode.EMPTY_ARRAY);
    if (!methods.isEmpty()) {
      List<MethodNode> methodNodes = chooseBestMethod(receiverType, methods, ClassNode.EMPTY_ARRAY);
      if (methodNodes.size() == 1) {
        MethodNode getter = methodNodes.get(0);
        MethodCallExpression call =
            new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
        call.setMethodTarget(getter);
        call.setImplicitThis(false);
        call.setSourcePosition(receiver);
        call.visit(controller.getAcg());
        return;
      }
    }

    boolean isStaticProperty =
        receiver instanceof ClassExpression
            && (receiverType.isDerivedFrom(receiver.getType())
                || receiverType.implementsInterface(receiver.getType()));

    if (!isStaticProperty) {
      if (receiverType.implementsInterface(MAP_TYPE) || MAP_TYPE.equals(receiverType)) {
        // for maps, replace map.foo with map.get('foo')
        writeMapDotProperty(receiver, methodName, mv, safe);
        return;
      }
      if (receiverType.implementsInterface(LIST_TYPE) || LIST_TYPE.equals(receiverType)) {
        writeListDotProperty(receiver, methodName, mv, safe);
        return;
      }
    }

    controller
        .getSourceUnit()
        .addError(
            new SyntaxException(
                "Access to "
                    + (receiver instanceof ClassExpression ? receiver.getType() : receiverType)
                        .toString(false)
                    + "#"
                    + methodName
                    + " is forbidden",
                receiver.getLineNumber(),
                receiver.getColumnNumber(),
                receiver.getLastLineNumber(),
                receiver.getLastColumnNumber()));
    controller.getMethodVisitor().visitInsn(ACONST_NULL);
    controller.getOperandStack().push(OBJECT_TYPE);
  }