Example #1
0
  @Override
  public Node leave(Node parent, Node old, Node n, NodeVisitor v) {
    // do context bookkeeping first
    if (old instanceof X10MethodDecl) {
      assert ((X10MethodDecl) old).returnType().type() == returnType.peek();
      returnType.pop();
    }

    // NB: for calls and closure calls, the rules for boxing are complicated,
    // so we insert a simple Cast AST node, so that codegen makes a decision
    // whether to do boxing/unboxing. The goal is to ensure, that
    // the only places, where codegen needs to consider boxing/unboxing
    // are:
    // * casts
    // * method or closure call arguments

    // Generic methods (return type T) can return boxed values (e.g., x10.core.UInt)
    // but in the type instantiated [UInt] subclass it is treated as unboxed int.
    // We need to insert explicit cast to
    // an unboxed type,  so that proper conversion method call is inserted later.
    if (n instanceof X10Call && !(parent instanceof Eval)) {
      X10Call call = (X10Call) n;
      Receiver target = call.target();
      MethodInstance mi = call.methodInstance();
      Type expectedReturnType = call.type();
      // do not insert cast the expected type is already boxed or is void
      if (X10PrettyPrinterVisitor.isBoxedType(expectedReturnType)
          || expectedReturnType.isVoid() // (void) never needs boxing
          // or if the method def type is void -- it is a synthetic method without a proper
          // definition
          || mi.def().returnType().get().isVoid()) return n;
      if (X10PrettyPrinterVisitor.isBoxedType(mi.def().returnType().get())) {
        // only insert cast if the actual returned type is boxed
        return cast(call, expectedReturnType);
      }
    }

    // Closures may be implemented by methods returning boxed or unboxed values,
    // depending on some involved condition that is checked in codegen.
    // So add the dummy type cast to give the codegen
    // chance to handle unboxing in a single place
    if (n instanceof ClosureCall && !(parent instanceof Eval) && !(parent instanceof Cast)) {
      ClosureCall call = (ClosureCall) n;
      // if the return type is not primitive, then unboxing will not be needed
      if (X10PrettyPrinterVisitor.isBoxedType(call.type()) || call.type().isVoid()) return n;
      return cast(call, call.type());
    }

    if (n instanceof Expr) { // boxing may be needed only for expressions
      Expr expr = (Expr) n;

      // parent node still has "old" as its child
      if (isBoxed(expr) && expectsUnboxed(parent, old)) {
        return unbox(expr);
      } else if (isUnboxed(expr) && expectsBoxed(parent, old)) {
        return box(expr);
      }
    }
    return n;
  }
Example #2
0
 private boolean isBoxed(ClosureCall call) {
   // FIXME: these conditions are copied over from Emitter.printApplyMethodName() and
   // X10PrettyPrinterVisitor.visit(ClosureCall)
   Expr target = call.target();
   if (target instanceof ParExpr) {
     target = ((ParExpr) target).expr();
   }
   boolean newClosure = target instanceof Closure_c;
   MethodInstance mi = call.closureInstance();
   if ((!newClosure && !mi.returnType().isVoid() && mi.formalTypes().size() == 0)
       || !(mi.returnType().isVoid() || (newClosure && !mi.returnType().isParameterType()))) {
     // in this case generic apply$G is used
     return true;
   }
   Type type = call.closureInstance().def().returnType().get();
   if (isBoxedType(type)) return true;
   return false;
 }