Skip to content

Commit

Permalink
Add support for constant expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
mcimadamore committed Oct 25, 2023
1 parent 0e44f14 commit bd74278
Show file tree
Hide file tree
Showing 17 changed files with 188 additions and 125 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package com.sun.source.tree;

/**
* A tree node for a constant expression.
*
* For example:
* <pre>
* const <em>expression</em>
* </pre>
*/
public interface ConstantExpressionTree extends ExpressionTree {
/**
* Returns the initializer of the constant expression.
* @return the initializer of the constant expression.
*/
ExpressionTree getExpression();
}
5 changes: 5 additions & 0 deletions src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ public enum Kind {
*/
PARENTHESIZED(ParenthesizedTree.class),

/**
* Used for instances of {@link ConstantExpressionTree}.
*/
CONSTANT_EXPRESSION(ConstantExpressionTree.class),

/**
* Used for instances of {@link BindingPatternTree}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,14 @@ public interface TreeVisitor<R,P> {
*/
R visitParenthesized(ParenthesizedTree node, P p);

/**
* Visits a {@code ConstantExpressionTree} node.
* @param node the node being visited
* @param p a parameter value
* @return a result value
*/
R visitConstantExpression(ConstantExpressionTree node, P p);

/**
* Visits a {@code ReturnTree} node.
* @param node the node being visited
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,20 @@ public R visitParenthesized(ParenthesizedTree node, P p) {
return defaultAction(node, p);
}

/**
* {@inheritDoc}
*
* @implSpec This implementation calls {@code defaultAction}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of {@code defaultAction}
*/
@Override
public R visitConstantExpression(ConstantExpressionTree node, P p) {
return defaultAction(node, p);
}

/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,20 @@ public R visitParenthesized(ParenthesizedTree node, P p) {
return scan(node.getExpression(), p);
}

/**
* {@inheritDoc}
*
* @implSpec This implementation scans the children in left to right order.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of scanning
*/
@Override
public R visitConstantExpression(ConstantExpressionTree node, P p) {
return scan(node.getExpression(), p);
}

/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ public static String toSource(long flags) {
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT | SEALED | NON_SEALED,
InterfaceMethodMask = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | DEFAULT,
AnnotationTypeElementMask = ABSTRACT | PUBLIC,
LocalVarFlags = FINAL | PARAMETER | STATIC,
LocalVarFlags = FINAL | PARAMETER,
ReceiverParamFlags = PARAMETER;

public static Set<Modifier> asModifierSet(long flags) {
Expand Down
14 changes: 14 additions & 0 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
Original file line number Diff line number Diff line change
Expand Up @@ -3974,6 +3974,20 @@ public void visitParens(JCParens tree) {
log.error(tree.pos(), Errors.IllegalParenthesizedExpression);
}

public void visitConstExpr(JCConstExpr tree) {
Env<AttrContext> initEnv = env.dup(tree);
try {
initEnv.info.staticLevel++;
Type owntype = attribTree(tree.expr, initEnv, resultInfo);
result = check(tree, owntype, pkind(), resultInfo);
Symbol sym = TreeInfo.symbol(tree);
if (sym != null && sym.kind.matches(KindSelector.TYP_PCK) && sym.kind != Kind.ERR)
log.error(tree.pos(), Errors.IllegalParenthesizedExpression);
} finally {
initEnv.info.staticLevel--;
}
}

public void visitAssign(JCAssign tree) {
Type owntype = attribTree(tree.lhs, env.dup(tree), varAssignmentInfo);
Type capturedType = capture(owntype);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,42 +25,29 @@

package com.sun.tools.javac.comp;

import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.DynamicVarSymbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.MethodType;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.jvm.Target;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCConstExpr;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;

import java.util.HashMap;
import java.util.Map;

import static com.sun.tools.javac.code.Flags.PRIVATE;
import static com.sun.tools.javac.code.Flags.STATIC;
import static com.sun.tools.javac.code.Flags.SYNTHETIC;
import static com.sun.tools.javac.code.Kinds.Kind.MTH;

public class TransConstants extends TreeTranslator {

Expand Down Expand Up @@ -97,45 +84,11 @@ protected TransConstants(Context context) {
*/
Env<AttrContext> attrEnv;

/** A table mapping static local symbols to their desugared counterparts.
*/
Map<VarSymbol, VarSymbol> staticLocalsTable;

ListBuffer<JCTree> pendingClassDefs;

public void visitVarDef(JCVariableDecl tree) {
if (tree.sym.isStatic() && tree.sym.owner.kind == MTH) {
if (isSplittableStaticLocal(tree)) {
splitStaticLocalInit(tree);
} else {
liftStaticLocal(tree);
}
// do not emit the variable declaration
result = make.Skip();
} else {
super.visitVarDef(tree);
}
}

@Override
public void visitIdent(JCIdent tree) {
if (staticLocalsTable != null && staticLocalsTable.containsKey(tree.sym)) {
Symbol translatedSym = staticLocalsTable.get(tree.sym);
result = make.Ident(translatedSym);
} else {
super.visitIdent(tree);
}
}

@Override
public void visitMethodDef(JCMethodDecl tree) {
Map<VarSymbol, VarSymbol> prevStaticLocalsTable = staticLocalsTable;
try {
staticLocalsTable = new HashMap<>();
super.visitMethodDef(tree);
} finally {
staticLocalsTable = prevStaticLocalsTable;
}
public void visitConstExpr(JCConstExpr tree) {
result = splitConstant(tree);
}

@Override
Expand All @@ -153,48 +106,21 @@ public void visitClassDef(JCClassDecl tree) {
}
}

boolean isSplittableStaticLocal(JCVariableDecl tree) {
return tree.sym.isFinal() &&
!hasAnonClassDefs(tree);
}

boolean hasAnonClassDefs(JCTree tree) {
class AnonClassFinder extends TreeScanner {
boolean anonFound;

@Override
public void visitNewClass(JCNewClass tree) {
if (tree.def != null) {
anonFound = true;
}
super.visitNewClass(tree);
}

@Override
public void visitClassDef(JCClassDecl tree) {
// do not recurse
}
}
AnonClassFinder anonClassFinder = new AnonClassFinder();
tree.accept(anonClassFinder);
return anonClassFinder.anonFound;
}

private void splitStaticLocalInit(JCVariableDecl tree) {
Assert.checkNonNull(tree.init);
private JCExpression splitConstant(JCConstExpr tree) {
Name constName = names.fromString("const")
.append('$', names.fromString(String.valueOf(pendingClassDefs.size())));
// create synthetic init symbol
MethodSymbol initSym = new MethodSymbol(
STATIC | SYNTHETIC | PRIVATE,
tree.name.append('$', names.fromString("init")),
constName.append('$', names.fromString("init")),
new MethodType(List.nil(), tree.type, List.nil(), syms.methodClass),
currentClass.sym);
enterSynthetic(tree.pos(), initSym, currentClass.sym.members());
currentClass.sym.members().enter(initSym);
// create synthetic init tree
JCExpression initExpr = translate(tree.init);
JCExpression initExpr = translate(tree.expr);
JCMethodDecl initDef = make.MethodDef(initSym, make.Block(0, List.of(make.Return(initExpr))));
pendingClassDefs.add(initDef);
// drop original init
tree.init = null;

List<Type> lazyInit_staticArgTypes = List.of(syms.methodHandleLookupType,
syms.stringType,
syms.classType,
Expand All @@ -204,43 +130,9 @@ private void splitStaticLocalInit(JCVariableDecl tree) {
names.invoke, lazyInit_staticArgTypes, List.nil());

// set a constant value that points to a dynamic symbol, so that Gen can emit the correct ldc
DynamicVarSymbol condySym = new DynamicVarSymbol(tree.name, currentClass.sym, bsm.asHandle(), tree.type,
DynamicVarSymbol condySym = new DynamicVarSymbol(constName, currentClass.sym, bsm.asHandle(), tree.type,
new LoadableConstant[] { initSym.asHandle() });
staticLocalsTable.put(tree.sym, condySym);
}

private void liftStaticLocal(JCVariableDecl tree) {
Assert.checkNonNull(tree.init);
// create synthetic init symbol
VarSymbol liftedSym = new VarSymbol(
STATIC | SYNTHETIC | PRIVATE,
makeSyntheticName(tree.name.append('$', names.fromString("static")), currentClass.sym.members()),
tree.sym.type, currentClass.sym);
enterSynthetic(tree.pos(), liftedSym, currentClass.sym.members());
// create synthetic init tree
JCExpression initExpr = translate(tree.init);
JCVariableDecl liftedDecl = make.VarDef(liftedSym, initExpr);
pendingClassDefs.add(liftedDecl);
staticLocalsTable.put(tree.sym, liftedSym);
}

// copied from Lower
private void enterSynthetic(DiagnosticPosition pos, Symbol sym, WriteableScope s) {
s.enter(sym);
}

private Name makeSyntheticName(Name name, Scope s) {
do {
name = name.append(
target.syntheticNameChar(),
names.empty);
} while (lookupSynthetic(name, s) != null);
return name;
}

private Symbol lookupSynthetic(Name name, Scope s) {
Symbol sym = s.findFirst(name);
return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym;
return make.Ident(condySym);
}

/** Translate a toplevel class and return a list consisting of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,9 @@ void postop() {
*/
public void emitLdc(LoadableConstant constant) {
int od = poolWriter.putConstant(constant);
if (od <= 255) {
if (LoadableConstant.isLongOrDouble(constant)) {
emitop2(ldc2w, od, constant);
} else if (od <= 255) {
emitop1(ldc1, od, constant);
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@

package com.sun.tools.javac.jvm;

import com.sun.tools.javac.code.Symbol.DynamicVarSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Pair;
Expand Down Expand Up @@ -117,6 +120,18 @@ public Object poolKey(Types types) {
return data;
}
}

static boolean isLongOrDouble(LoadableConstant constant) {
return switch (constant) {
case DynamicVarSymbol dynamicVar ->
dynamicVar.type.hasTag(TypeTag.LONG) ||
dynamicVar.type.hasTag(TypeTag.DOUBLE);
case BasicConstant bc ->
bc.tag == ClassFile.CONSTANT_Long ||
bc.tag == ClassFile.CONSTANT_Double;
default -> false;
};
}
}

/**
Expand Down
Loading

0 comments on commit bd74278

Please sign in to comment.