Skip to content

Commit

Permalink
#4: Implicit type conversion for javac plugin. + refactorings.
Browse files Browse the repository at this point in the history
  • Loading branch information
amelentev committed Nov 26, 2012
1 parent e8ad485 commit 8011620
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 191 deletions.
94 changes: 75 additions & 19 deletions javac-oo-plugin/src/main/java/com/sun/tools/javac/comp/OOAttr.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,80 @@
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Warner;

import java.util.Map;
import java.util.WeakHashMap;

import static com.sun.tools.javac.code.Kinds.VAR;
import static com.sun.tools.javac.code.TypeTags.ERROR;
import static com.sun.tools.javac.code.TypeTags.*;

// XXX: NBAttr?
public class OOAttr extends Attr {
protected OOAttr(Context context) {
super(context);
}
public static OOAttr hook(Context context) {
public static OOAttr instance(Context context) {
Attr attr = context.get(attrKey);
if (attr instanceof OOAttr) return (OOAttr) attr;
context.put(attrKey, (Attr)null);
return new OOAttr(context);
}

/** WeakHashMap to allow GC collect entries. Because we don't need them then they are gone */
public Map<JCTree, JCTree.JCExpression> translateMap = new WeakHashMap<>();

@Override
Type check(JCTree tree, Type owntype, int ownkind, int pkind, Type pt) {
if (owntype.tag != ERROR && pt.tag == CLASS && (ownkind & ~pkind) == 0) {
JCTree.JCExpression t = tryImplicitConversion(tree, owntype, pt);
if (t != null) {
translateMap.put(tree, t);
return tree.type = owntype;
}
}
return super.check(tree, owntype, ownkind, pkind, pt);
}

/** try implicit conversion tree to pt type via #valueOf
* @return static valueOf method call iff successful */
JCTree.JCMethodInvocation tryImplicitConversion(JCTree tree, Type owntype, Type req) {
if (!isBoxingAllowed(owntype, req))
return null;
JCTree.JCExpression param = translateMap.get(tree);
// construct "<req>.valueOf(tree)" static method call
tree.type = owntype;
JCTree.JCMethodInvocation valueOf = make.Apply(null,
make.Select(make.Ident(pt.tsym), names.fromString("valueOf")),
List.of(param == null ? (JCTree.JCExpression)tree : param));
valueOf.type = attribTree(valueOf, env, pkind, pt);
return types.isAssignable(valueOf.type, req) ? valueOf : null;
}
boolean isBoxingAllowed(Type found, Type req) {
// similar to Check#checkType
if (req.tag == ERROR)
return false; // req
if (found.tag == FORALL)
return false; // chk.instantiatePoly(pos, (ForAll)found, req, convertWarner(pos, found, req));
if (req.tag == NONE)
return false; //found;
if (types.isAssignable(found, req)) //convertWarner(pos, found, req)))
return false; // found;
if (found.tag <= DOUBLE && req.tag <= DOUBLE)
return false; // typeError(pos, diags.fragment("possible.loss.of.precision"), found, req);
if (found.isSuperBound()) {
//log.error(pos, "assignment.from.super-bound", found);
return false; //types.createErrorType(found);
}
if (req.isExtendsBound()) {
//log.error(pos, "assignment.to.extends-bound", req);
return false; //types.createErrorType(found);
}
return true;
}

@Override
public void visitIndexed(JCTree.JCArrayAccess tree) {
Type owntype = types.createErrorType(tree.type);
Expand All @@ -41,31 +100,28 @@ public void visitIndexed(JCTree.JCArrayAccess tree) {
} else if (atype.tag != ERROR) {
attribExpr(tree.index, env);
boolean ok = false;
if (env.tree.getKind() == Tree.Kind.ASSIGNMENT) {
if (env.tree.getKind() == Tree.Kind.ASSIGNMENT && ((JCTree.JCAssign)env.tree).lhs == tree) {
JCTree.JCAssign ass = (JCTree.JCAssign) env.tree;
if (ass.lhs == tree) {
Type rhstype = attribExpr(ass.rhs, env);
List<Type> argtypes = List.of(tree.index.type, rhstype);
Symbol m = rs.findMethod(env, atype, names.fromString("set"), argtypes, null, true, false, false);
if (m.kind != Kinds.MTH)
m = rs.findMethod(env, atype, names.fromString("put"), argtypes, null, true, false, false); // Map#put
if (m.kind == Kinds.MTH) {
JCTree.JCMethodInvocation mi = make.Apply(null, make.Select(tree.indexed, m), List.of(tree.index, ass.rhs));
mi.type = attribExpr(mi, env);
tree.indexed = mi;
owntype = rhstype;
ok = true;
}
Type rhstype = attribExpr(ass.rhs, env);
List<Type> argtypes = List.of(tree.index.type, rhstype);
Symbol m = rs.findMethod(env, atype, names.fromString("set"), argtypes, null, true, false, false);
if (m.kind != Kinds.MTH)
m = rs.findMethod(env, atype, names.fromString("put"), argtypes, null, true, false, false); // Map#put
if (m.kind == Kinds.MTH) {
JCTree.JCMethodInvocation mi = make.Apply(null, make.Select(tree.indexed, m), List.of(tree.index, ass.rhs));
mi.type = attribExpr(mi, env);
translateMap.put(ass, mi);
owntype = rhstype;
ok = true;
}
}
if (!ok) {
} else {
List<Type> argtypes = List.of(tree.index.type);
Symbol m = rs.findMethod(env, atype, names.fromString("get"), argtypes, null, true, false, false);
if (m.kind == Kinds.MTH) {
//owntype = rs.instantiate(env, atype, m, argtypes, null, true, false, noteWarner).getReturnType();
JCTree.JCMethodInvocation mi = make.Apply(null, make.Select(tree.indexed, m), List.of(tree.index));
attribExpr(mi, env);
tree.indexed = mi;
translateMap.put(tree, mi);
owntype = mi.type;
ok = true;
}
Expand Down
149 changes: 23 additions & 126 deletions javac-oo-plugin/src/main/java/com/sun/tools/javac/comp/OOLower.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@
******************************************************************************/
package com.sun.tools.javac.comp;

import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.jvm.ByteCodes;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
Expand All @@ -25,26 +22,22 @@

import java.lang.reflect.Field;

import static com.sun.tools.javac.jvm.ByteCodes.bool_not;

public class OOLower extends Lower {
public static OOLower hook(Context context) {
public static OOLower instance(Context context) {
Lower res = context.get(lowerKey);
if (res instanceof OOLower) return (OOLower) res;
context.put(lowerKey, (Lower)null);
return new OOLower(context);
}
protected OOLower(Context context) {
super(context);
syms = Symtab.instance(context);
types = Types.instance(context);
make = TreeMaker.instance(context);
rs = Resolve.instance(context);
cfolder = ConstFold.instance(context);
rs = OOResolve.instance(context);
}
protected Types types;
protected Symtab syms;
protected TreeMaker make;
protected Resolve rs;
protected ConstFold cfolder;
private Symtab syms;
private TreeMaker make;
private OOResolve rs;
protected JCDiagnostic.DiagnosticPosition getMake_pos() {
try {
Field f = Lower.class.getDeclaredField("make_pos");
Expand All @@ -56,34 +49,22 @@ protected JCDiagnostic.DiagnosticPosition getMake_pos() {
}

@Override
public void visitIndexed(JCArrayAccess tree) {
if (types.isArray(tree.indexed.type)) {
tree.indexed = translate(tree.indexed);
tree.index = translate(tree.index, syms.intType);
result = tree;
} else {
result = translate(tree.indexed);
}
}

@Override
public void visitAssign(JCAssign tree) {
JCTree waslhs = tree.lhs;
tree.lhs = translate(tree.lhs, tree);
tree.rhs = translate(tree.rhs, tree.lhs.type);

// If translated left hand side is an Apply, we are
// seeing an access method invocation. In this case, append
// right hand side as last argument of the access method.
if (tree.lhs.getTag() == JCTree.APPLY) {
JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
app.args = List.of(tree.rhs).prependList(app.args);
result = app;
} else if (waslhs.getKind() == Tree.Kind.ARRAY_ACCESS && !types.isArray(((JCArrayAccess)waslhs).indexed.type)) {
result = tree.lhs;
} else {
result = tree;
public void visitUnary(JCUnary tree) {
if (tree.operator instanceof Symbol.OperatorSymbol) {
// similar to #visitBinary
Symbol.OperatorSymbol os = (Symbol.OperatorSymbol) tree.operator;
if (os.opcode == ByteCodes.error+1) {
Symbol.MethodSymbol ms = (Symbol.MethodSymbol) os.owner;
JCFieldAccess meth = make.Select(tree.arg, ms.name);
meth.type = ms.type;
meth.sym = ms;
result = make.Apply(null, meth, List.<JCExpression>nil())
.setType(tree.type);
result = translate(result);
return;
}
}
super.visitUnary(tree);
}

@Override
Expand All @@ -110,90 +91,6 @@ public void visitBinary(JCBinary tree) {
return;
}
}
List<Type> formals = tree.operator.type.getParameterTypes();
JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
switch (tree.getTag()) {
case JCTree.OR:
if (lhs.type.isTrue()) {
result = lhs;
return;
}
if (lhs.type.isFalse()) {
result = translate(tree.rhs, formals.tail.head);
return;
}
break;
case JCTree.AND:
if (lhs.type.isFalse()) {
result = lhs;
return;
}
if (lhs.type.isTrue()) {
result = translate(tree.rhs, formals.tail.head);
return;
}
break;
}
tree.rhs = translate(tree.rhs, formals.tail.head);
result = tree;
}

@Override
public void visitUnary(JCUnary tree) {
if (tree.operator instanceof Symbol.OperatorSymbol) {
// similar to #visitBinary
Symbol.OperatorSymbol os = (Symbol.OperatorSymbol) tree.operator;
if (os.opcode == ByteCodes.error+1) {
Symbol.MethodSymbol ms = (Symbol.MethodSymbol) os.owner;
JCFieldAccess meth = make.Select(tree.arg, ms.name);
meth.type = ms.type;
meth.sym = ms;
result = make.Apply(null, meth, List.<JCExpression>nil())
.setType(tree.type);
result = translate(result);
return;
}
}
boolean isUpdateOperator =
JCTree.PREINC <= tree.getTag() && tree.getTag() <= JCTree.POSTDEC;
if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
switch(tree.getTag()) {
case JCTree.PREINC: // ++ e
// translate to e += 1
case JCTree.PREDEC: // -- e
// translate to e -= 1
{
int opcode = (tree.getTag() == JCTree.PREINC)
? JCTree.PLUS_ASG : JCTree.MINUS_ASG;
JCAssignOp newTree = makeAssignop(opcode,
tree.arg,
make.Literal(1));
result = translate(newTree, tree.type);
return;
}
case JCTree.POSTINC: // e ++
case JCTree.POSTDEC: // e --
{
result = translate(lowerBoxedPostop(tree), tree.type);
return;
}
}
throw new AssertionError(tree);
}

tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);

if (tree.getTag() == JCTree.NOT && tree.arg.type.constValue() != null) {
tree.type = cfolder.fold1(bool_not, tree.arg.type);
}

// If translated left hand side is an Apply, we are
// seeing an access method invocation. In this case, return
// that access method invocation as result.
if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
result = tree.arg;
} else {
result = tree;
}
super.visitBinary(tree);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ public class OOResolve extends Resolve {
protected OOResolve(Context context) {
super(context);
}
public static OOResolve hook(Context context) {
public static OOResolve instance(Context context) {
Resolve res = context.get(resolveKey);
if (res instanceof OOResolve) return (OOResolve)res;
context.put(resolveKey, (Resolve)null);
return new OOResolve(context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,27 @@
******************************************************************************/
package com.sun.tools.javac.comp;

import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Context;

public class OOTransTypes extends TransTypes {
public static OOTransTypes hook(Context context) {
public static OOTransTypes instance(Context context) {
TransTypes res = context.get(transTypesKey);
if (res instanceof OOTransTypes) return (OOTransTypes) res;
context.put(transTypesKey, (TransTypes)null);
return new OOTransTypes(context);
}
protected OOTransTypes(Context context) {
super(context);
syms = Symtab.instance(context);
types = Types.instance(context);
attr = OOAttr.instance(context);
}
protected Types types;
protected Symtab syms;
private OOAttr attr;

@Override
public void visitIndexed(JCTree.JCArrayAccess tree) {
if (types.isArray(tree.indexed.type))
super.visitIndexed(tree);
// index overload
tree.indexed = translate(tree.indexed, types.erasure(tree.indexed.type));
tree.index = translate(tree.index, syms.intType);
result = tree;
public <T extends JCTree> T translate(T tree) {
JCTree.JCExpression t = attr.translateMap.remove(tree);
if (t!=null)
return (T) translate(t);
return super.translate(tree);
}
}
8 changes: 4 additions & 4 deletions javac-oo-plugin/src/main/java/javaoo/javac/OOProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ static void patch(JavaCompiler compiler, ClassLoader pcl) {
Class<?> resolveClass = reloadClass("com.sun.tools.javac.comp.OOResolve", pcl, Resolve.class.getClassLoader());
Class<?> lowerClass = reloadClass("com.sun.tools.javac.comp.OOLower", pcl, Lower.class.getClassLoader());
Class<?> transTypesClass = reloadClass("com.sun.tools.javac.comp.OOTransTypes", pcl, TransTypes.class.getClassLoader());
resolveClass.getDeclaredMethod("hook", Context.class).invoke(null, context);
Object lower = lowerClass.getDeclaredMethod("hook", Context.class).invoke(null, context);
Object transTypes = transTypesClass.getDeclaredMethod("hook", Context.class).invoke(null, context);
Object attr = attrClass.getDeclaredMethod("hook", Context.class).invoke(null, context);
resolveClass.getDeclaredMethod("instance", Context.class).invoke(null, context);
Object attr = attrClass.getDeclaredMethod("instance", Context.class).invoke(null, context);
Object lower = lowerClass.getDeclaredMethod("instance", Context.class).invoke(null, context);
Object transTypes = transTypesClass.getDeclaredMethod("instance", Context.class).invoke(null, context);

set(compiler, "attr", attr);
set(MemberEnter.instance(context), "attr", attr);
Expand Down
Loading

0 comments on commit 8011620

Please sign in to comment.