コード例 #1
0
 @Override
 public void makeSingleArgumentCall(
     final Expression receiver, final String message, final Expression arguments) {
   TypeChooser typeChooser = controller.getTypeChooser();
   ClassNode classNode = controller.getClassNode();
   ClassNode rType = typeChooser.resolveType(receiver, classNode);
   ClassNode aType = typeChooser.resolveType(arguments, classNode);
   if (trySubscript(receiver, message, arguments, rType, aType)) {
     return;
   }
   // new try with flow type instead of declaration type
   rType = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
   if (rType != null && trySubscript(receiver, message, arguments, rType, aType)) {
     return;
   }
   // todo: more cases
   throw new GroovyBugError(
       "At line "
           + receiver.getLineNumber()
           + " column "
           + receiver.getColumnNumber()
           + "\n"
           + "On receiver: "
           + receiver.getText()
           + " with message: "
           + message
           + " and arguments: "
           + arguments.getText()
           + "\n"
           + "This method should not have been called. Please try to create a simple example reproducing this error and file"
           + "a bug report at http://jira.codehaus.org/browse/GROOVY");
 }
コード例 #2
0
  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);
    }
  }
コード例 #3
0
  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);
  }
コード例 #4
0
  @Override
  protected void evaluateCompareExpression(
      final MethodCaller compareMethod, BinaryExpression binExp) {
    ClassNode current = getController().getClassNode();
    TypeChooser typeChooser = getController().getTypeChooser();

    Expression leftExp = binExp.getLeftExpression();
    ClassNode leftType = typeChooser.resolveType(leftExp, current);
    Expression rightExp = binExp.getRightExpression();
    ClassNode rightType = typeChooser.resolveType(rightExp, current);

    if (!doPrimitiveCompare(leftType, rightType, binExp)) {
      super.evaluateCompareExpression(compareMethod, binExp);
    }
  }
コード例 #5
0
  @Override
  public void visitConstructorCallExpression(final ConstructorCallExpression call) {
    super.visitConstructorCallExpression(call);

    MethodNode target = (MethodNode) call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
    if (target == null && call.getLineNumber() > 0) {
      addError("Target constructor for constructor call expression hasn't been set", call);
    } else {
      if (target == null) {
        // try to find a target
        ArgumentListExpression argumentListExpression =
            InvocationWriter.makeArgumentList(call.getArguments());
        List<Expression> expressions = argumentListExpression.getExpressions();
        ClassNode[] args = new ClassNode[expressions.size()];
        for (int i = 0; i < args.length; i++) {
          args[i] = typeChooser.resolveType(expressions.get(i), classNode);
        }
        MethodNode constructor =
            findMethodOrFail(
                call, call.isSuperCall() ? classNode.getSuperClass() : classNode, "<init>", args);
        call.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, constructor);
        target = constructor;
      }
    }
    if (target != null) {
      memorizeInitialExpressions(target);
    }
  }
コード例 #6
0
  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);
  }
コード例 #7
0
  @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);
  }
コード例 #8
0
  @Override
  public void makeGroovyObjectGetPropertySite(
      final Expression receiver,
      final String methodName,
      final boolean safe,
      final boolean implicitThis) {
    TypeChooser typeChooser = controller.getTypeChooser();
    ClassNode classNode = controller.getClassNode();
    ClassNode receiverType = typeChooser.resolveType(receiver, classNode);
    if (receiver instanceof VariableExpression
        && ((VariableExpression) receiver).isThisExpression()
        && !controller.isInClosure()) {
      receiverType = classNode;
    }

    String property = methodName;
    if (implicitThis) {
      if (controller.getInvocationWriter() instanceof StaticInvocationWriter) {
        MethodCallExpression currentCall =
            ((StaticInvocationWriter) controller.getInvocationWriter()).getCurrentCall();
        if (currentCall != null
            && currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER) != null) {
          property = (String) currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
          String[] props = property.split("\\.");
          BytecodeExpression thisLoader =
              new BytecodeExpression() {
                @Override
                public void visit(final MethodVisitor mv) {
                  mv.visitVarInsn(ALOAD, 0); // load this
                }
              };
          thisLoader.setType(CLOSURE_TYPE);
          Expression pexp =
              new PropertyExpression(thisLoader, new ConstantExpression(props[0]), safe);
          for (int i = 1, propsLength = props.length; i < propsLength; i++) {
            final String prop = props[i];
            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, CLOSURE_TYPE);
            pexp = new PropertyExpression(pexp, prop);
          }
          pexp.visit(controller.getAcg());
          return;
        }
      }
    }

    if (makeGetPropertyWithGetter(receiver, receiverType, property, safe, implicitThis)) return;
    if (makeGetField(
        receiver,
        receiverType,
        property,
        implicitThis,
        samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;

    MethodCallExpression call =
        new MethodCallExpression(
            receiver, "getProperty", new ArgumentListExpression(new ConstantExpression(property)));
    call.setImplicitThis(implicitThis);
    call.setSafe(safe);
    call.setMethodTarget(GROOVYOBJECT_GETPROPERTY_METHOD);
    call.visit(controller.getAcg());
    return;
  }
コード例 #9
0
  public void evaluateEqual(BinaryExpression expression, boolean defineVariable) {
    AsmClassGenerator acg = controller.getAcg();
    CompileStack compileStack = controller.getCompileStack();
    OperandStack operandStack = controller.getOperandStack();
    Expression rightExpression = expression.getRightExpression();
    Expression leftExpression = expression.getLeftExpression();
    ClassNode lhsType =
        controller.getTypeChooser().resolveType(leftExpression, controller.getClassNode());

    if (defineVariable
        && rightExpression instanceof EmptyExpression
        && !(leftExpression instanceof TupleExpression)) {
      VariableExpression ve = (VariableExpression) leftExpression;
      BytecodeVariable var =
          compileStack.defineVariable(
              ve, controller.getTypeChooser().resolveType(ve, controller.getClassNode()), false);
      operandStack.loadOrStoreVariable(var, false);
      return;
    }

    // let's evaluate the RHS and store the result
    ClassNode rhsType;
    if (rightExpression instanceof ListExpression && lhsType.isArray()) {
      ListExpression list = (ListExpression) rightExpression;
      ArrayExpression array =
          new ArrayExpression(lhsType.getComponentType(), list.getExpressions());
      array.setSourcePosition(list);
      array.visit(acg);
    } else if (rightExpression instanceof EmptyExpression) {
      rhsType = leftExpression.getType();
      loadInitValue(rhsType);
    } else {
      rightExpression.visit(acg);
    }
    rhsType = operandStack.getTopOperand();

    boolean directAssignment = defineVariable && !(leftExpression instanceof TupleExpression);
    int rhsValueId;
    if (directAssignment) {
      VariableExpression var = (VariableExpression) leftExpression;
      if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(rhsType)) {
        // GROOVY-5570: if a closure shared variable is a primitive type, it must be boxed
        rhsType = ClassHelper.getWrapper(rhsType);
        operandStack.box();
      }

      // ensure we try to unbox null to cause a runtime NPE in case we assign
      // null to a primitive typed variable, even if it is used only in boxed
      // form as it is closure shared
      if (var.isClosureSharedVariable()
          && ClassHelper.isPrimitiveType(var.getOriginType())
          && isNull(rightExpression)) {
        operandStack.doGroovyCast(var.getOriginType());
        // these two are never reached in bytecode and only there
        // to avoid verifyerrors and compiler infrastructure hazzle
        operandStack.box();
        operandStack.doGroovyCast(lhsType);
      }
      // normal type transformation
      if (!ClassHelper.isPrimitiveType(lhsType) && isNull(rightExpression)) {
        operandStack.replace(lhsType);
      } else {
        operandStack.doGroovyCast(lhsType);
      }
      rhsType = lhsType;
      rhsValueId = compileStack.defineVariable(var, lhsType, true).getIndex();
    } else {
      rhsValueId = compileStack.defineTemporaryVariable("$rhs", rhsType, true);
    }
    // TODO: if rhs is VariableSlotLoader already, then skip crating a new one
    BytecodeExpression rhsValueLoader = new VariableSlotLoader(rhsType, rhsValueId, operandStack);

    // assignment for subscript
    if (leftExpression instanceof BinaryExpression) {
      BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
      if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
        assignToArray(
            expression,
            leftBinExpr.getLeftExpression(),
            leftBinExpr.getRightExpression(),
            rhsValueLoader);
      }
      compileStack.removeVar(rhsValueId);
      return;
    }

    compileStack.pushLHS(true);

    // multiple declaration
    if (leftExpression instanceof TupleExpression) {
      TupleExpression tuple = (TupleExpression) leftExpression;
      int i = 0;
      for (Expression e : tuple.getExpressions()) {
        VariableExpression var = (VariableExpression) e;
        MethodCallExpression call =
            new MethodCallExpression(
                rhsValueLoader, "getAt", new ArgumentListExpression(new ConstantExpression(i)));
        call.visit(acg);
        i++;
        if (defineVariable) {
          operandStack.doGroovyCast(var);
          compileStack.defineVariable(var, true);
          operandStack.remove(1);
        } else {
          acg.visitVariableExpression(var);
        }
      }
    }
    // single declaration
    else if (defineVariable) {
      rhsValueLoader.visit(acg);
      operandStack.remove(1);
      compileStack.popLHS();
      return;
    }
    // normal assignment
    else {
      int mark = operandStack.getStackLength();
      // to leave a copy of the rightExpression value on the stack after the assignment.
      rhsValueLoader.visit(acg);
      TypeChooser typeChooser = controller.getTypeChooser();
      ClassNode targetType = typeChooser.resolveType(leftExpression, controller.getClassNode());
      operandStack.doGroovyCast(targetType);
      leftExpression.visit(acg);
      operandStack.remove(operandStack.getStackLength() - mark);
    }
    compileStack.popLHS();

    // return value of assignment
    rhsValueLoader.visit(acg);
    compileStack.removeVar(rhsValueId);
  }