Skip to content

Commit f41fa39

Browse files
author
Mourad Abbay
committed
Reduce number of local variables when transforming code model builder to AST
Reviewed-by: psandoz
1 parent 93b4b32 commit f41fa39

File tree

2 files changed

+67
-61
lines changed

2 files changed

+67
-61
lines changed

src/jdk.incubator.code/share/classes/jdk/incubator/code/internal/CodeModelToAST.java

+66-60
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
import com.sun.tools.javac.tree.TreeInfo;
1212
import com.sun.tools.javac.tree.TreeMaker;
1313
import com.sun.tools.javac.util.*;
14+
import com.sun.tools.javac.util.List;
1415
import jdk.incubator.code.*;
1516
import jdk.incubator.code.op.CoreOp;
1617
import jdk.incubator.code.type.*;
1718

18-
import java.util.HashMap;
19-
import java.util.Map;
19+
import java.util.*;
2020

2121
import static com.sun.tools.javac.code.Flags.*;
2222

@@ -30,9 +30,13 @@ public class CodeModelToAST {
3030
private final Types types;
3131
private final Symbol.ClassSymbol currClassSym;
3232
private final CodeReflectionSymbols crSym;
33-
private final Map<Value, Symbol.VarSymbol> valueToVarSym = new HashMap<>();
3433
private Symbol.MethodSymbol ms;
3534
private int localVarCount = 0; // used to name variables we introduce in the AST
35+
private final Map<Value, JCTree> valueToTree = new HashMap<>();
36+
private static final MethodRef M_BLOCK_BUILDER_OP = MethodRef.method(Block.Builder.class, "op",
37+
Op.Result.class, Op.class);
38+
private static final MethodRef M_BLOCK_BUILDER_PARAM = MethodRef.method(Block.Builder.class, "parameter",
39+
Block.Parameter.class, TypeElement.class);
3640

3741
public CodeModelToAST(TreeMaker treeMaker, Names names, Symtab syms, Resolve resolve,
3842
Types types, Env<AttrContext> attrEnv, CodeReflectionSymbols crSym) {
@@ -66,6 +70,14 @@ private Type typeElementToType(TypeElement jt) {
6670
};
6771
}
6872

73+
private JCExpression toExpr(JCTree t) {
74+
return switch (t) {
75+
case JCExpression e -> e;
76+
case JCTree.JCVariableDecl vd -> treeMaker.Ident(vd);
77+
case null, default -> throw new IllegalArgumentException();
78+
};
79+
}
80+
6981
private JCTree invokeOpToJCMethodInvocation(CoreOp.InvokeOp invokeOp) {
7082
Value receiver = (invokeOp.invokeKind() == CoreOp.InvokeOp.InvokeKind.INSTANCE) ?
7183
invokeOp.operands().get(0) : null;
@@ -75,10 +87,10 @@ private JCTree invokeOpToJCMethodInvocation(CoreOp.InvokeOp invokeOp) {
7587
var methodSym = methodDescriptorToSymbol(invokeOp.invokeDescriptor());
7688
var meth = (receiver == null) ?
7789
treeMaker.Ident(methodSym) :
78-
treeMaker.Select(exprTree(receiver), methodSym);
90+
treeMaker.Select(toExpr(opToTree(receiver)), methodSym);
7991
var args = new ListBuffer<JCTree.JCExpression>();
8092
for (Value operand : arguments) {
81-
args.add(exprTree(operand));
93+
args.add(toExpr(opToTree(operand)));
8294
}
8395
var methodInvocation = treeMaker.App(meth, args.toList());
8496
if (invokeOp.isVarArgs()) {
@@ -96,7 +108,48 @@ void setVarargs(JCExpression tree, FunctionType type) {
96108
}
97109
}
98110

99-
private JCTree opToTree(Op op) {
111+
public JCTree.JCMethodDecl transformFuncOpToAST(CoreOp.FuncOp funcOp, Name methodName) {
112+
Assert.check(funcOp.body().blocks().size() == 1);
113+
114+
var paramTypes = List.of(crSym.opFactoryType, crSym.typeElementFactoryType);
115+
var mt = new Type.MethodType(paramTypes, crSym.opType, List.nil(), syms.methodClass);
116+
ms = new Symbol.MethodSymbol(PUBLIC | STATIC | SYNTHETIC, methodName, mt, currClassSym);
117+
currClassSym.members().enter(ms);
118+
119+
for (int i = 0; i < funcOp.parameters().size(); i++) {
120+
valueToTree.put(funcOp.parameters().get(i), treeMaker.Ident(ms.params().get(i)));
121+
}
122+
123+
java.util.List<Value> rootValues = funcOp.traverse(new ArrayList<>(), (l, ce) -> {
124+
if (ce instanceof Op op && op.result() != null && op.result().uses().size() != 1) {
125+
l.add(op.result());
126+
} else if (ce instanceof CoreOp.InvokeOp invokeOp && (invokeOp.invokeDescriptor().equals(M_BLOCK_BUILDER_OP)
127+
|| invokeOp.invokeDescriptor().equals(M_BLOCK_BUILDER_PARAM))) {
128+
l.add(invokeOp.result());
129+
}
130+
return l;
131+
});
132+
133+
var stats = new ListBuffer<JCTree.JCStatement>();
134+
for (Value root : rootValues) {
135+
JCTree tree = opToTree(root);
136+
if (tree instanceof JCExpression e) {
137+
var vs = new Symbol.VarSymbol(LocalVarFlags | SYNTHETIC, names.fromString("_$" + localVarCount++), tree.type, ms);
138+
tree = treeMaker.VarDef(vs, e);
139+
valueToTree.put(root, tree);
140+
}
141+
stats.add((JCTree.JCStatement) tree);
142+
}
143+
var mb = treeMaker.Block(0, stats.toList());
144+
145+
return treeMaker.MethodDef(ms, mb);
146+
}
147+
148+
private JCTree opToTree(Value v) {
149+
if (valueToTree.containsKey(v)) {
150+
return valueToTree.get(v);
151+
}
152+
Op op = ((Op.Result) v).op();
100153
JCTree tree = switch (op) {
101154
case CoreOp.ConstantOp constantOp when constantOp.value() == null ->
102155
treeMaker.Literal(TypeTag.BOT, null).setType(syms.botType);
@@ -106,7 +159,7 @@ private JCTree opToTree(Op op) {
106159
var elemType = treeMaker.Ident(typeElementToType(at.componentType()).tsym);
107160
var dims = new ListBuffer<JCTree.JCExpression>();
108161
for (int d = 0; d < at.dimensions(); d++) {
109-
dims.add(exprTree(newOp.operands().get(d)));
162+
dims.add(toExpr(opToTree(newOp.operands().get(d))));
110163
}
111164
var na = treeMaker.NewArray(elemType, dims.toList(), null);
112165
na.type = typeElementToType(at);
@@ -117,7 +170,7 @@ private JCTree opToTree(Op op) {
117170
var clazz = treeMaker.Ident(ownerType.tsym);
118171
var args = new ListBuffer<JCTree.JCExpression>();
119172
for (Value operand : newOp.operands()) {
120-
args.add(exprTree(operand));
173+
args.add(toExpr(opToTree(operand)));
121174
}
122175
var nc = treeMaker.NewClass(null, null, clazz, args.toList(), null);
123176
if (newOp.isVarargs()) {
@@ -129,7 +182,7 @@ private JCTree opToTree(Op op) {
129182
yield nc;
130183
}
131184
case CoreOp.ReturnOp returnOp ->
132-
treeMaker.Return(exprTree(returnOp.returnValue()));
185+
treeMaker.Return(toExpr(opToTree(returnOp.returnValue())));
133186
case CoreOp.FieldAccessOp.FieldLoadOp fieldLoadOp -> {
134187
var sym = fieldDescriptorToSymbol(fieldLoadOp.fieldDescriptor());
135188
Assert.check(sym.isStatic());
@@ -140,63 +193,16 @@ private JCTree opToTree(Op op) {
140193
var val = arrayStoreOp.operands().get(1);
141194
var index = arrayStoreOp.operands().get(2);
142195
var as = treeMaker.Assign(
143-
treeMaker.Indexed(exprTree(array), exprTree(index)), exprTree(val)
196+
treeMaker.Indexed(
197+
toExpr(opToTree(array)), toExpr(opToTree(index))), toExpr(opToTree(val))
144198
);
145199
as.type = typeElementToType(((ArrayType) array.type()).componentType());
146200
yield as;
147201
}
148202
default -> throw new IllegalStateException("Op -> JCTree not supported for :" + op.getClass().getName());
149203
};
150-
if (tree instanceof JCTree.JCExpression expr) {
151-
// introduce a local variable to hold the expr, to make sure an op's tree is inserted right away
152-
// for some operations this is essential, e.g. to ensure the correct order of operations
153-
Type type;
154-
if (op instanceof CoreOp.ConstantOp cop && cop.value() == null) {
155-
// if ConstantOp value is null, tree.type will be null_type
156-
// if null_type is used to create a VarSymbol, an exception will be thrown
157-
type = typeElementToType(cop.resultType());
158-
} else {
159-
type = tree.type;
160-
}
161-
var vs = new Symbol.VarSymbol(LocalVarFlags, names.fromString("_$" + localVarCount++), type, ms);
162-
var varDef = treeMaker.VarDef(vs, expr);
163-
map(op.result(), vs);
164-
return varDef;
165-
} else {
166-
return tree;
167-
}
168-
}
169-
170-
private JCTree.JCExpression exprTree(Value v) {
171-
return treeMaker.Ident(valueToVarSym.get(v));
172-
}
173-
174-
private void map(Value v, Symbol.VarSymbol vs) {
175-
valueToVarSym.put(v, vs);
176-
}
177-
178-
public JCTree.JCMethodDecl transformFuncOpToAST(CoreOp.FuncOp funcOp, Name methodName) {
179-
Assert.check(funcOp.body().blocks().size() == 1);
180-
181-
var paramTypes = List.of(crSym.opFactoryType, crSym.typeElementFactoryType);
182-
var mt = new Type.MethodType(paramTypes, crSym.opType, List.nil(), syms.methodClass);
183-
ms = new Symbol.MethodSymbol(PUBLIC | STATIC | SYNTHETIC, methodName, mt, currClassSym);
184-
currClassSym.members().enter(ms);
185-
186-
for (int i = 0; i < funcOp.parameters().size(); i++) {
187-
map(funcOp.parameters().get(i), ms.params().get(i));
188-
}
189-
190-
var stats = new ListBuffer<JCTree.JCStatement>();
191-
for (Op op : funcOp.body().entryBlock().ops()) {
192-
var tree = opToTree(op);
193-
if (tree instanceof JCTree.JCStatement stat) {
194-
stats.add(stat);
195-
}
196-
}
197-
var mb = treeMaker.Block(0, stats.toList());
198-
199-
return treeMaker.MethodDef(ms, mb);
204+
valueToTree.put(v, tree);
205+
return tree;
200206
}
201207

202208
VarSymbol fieldDescriptorToSymbol(FieldRef fieldRef) {

src/jdk.incubator.code/share/classes/jdk/incubator/code/internal/ReflectMethods.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ private enum CodeModelStorageOption {
403403

404404
public static CodeModelStorageOption parse(String s) {
405405
if (s == null) {
406-
return CodeModelStorageOption.TEXT;
406+
return CodeModelStorageOption.CODE_BUILDER;
407407
}
408408
return CodeModelStorageOption.valueOf(s);
409409
}

0 commit comments

Comments
 (0)