Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8291769: Translation of switch with record patterns could be improved #9746

Closed
wants to merge 14 commits into from

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@

package com.sun.tools.javac.comp;

import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotatedType;
@@ -44,6 +45,7 @@
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCConditional;
import com.sun.tools.javac.tree.JCTree.JCConstantCaseLabel;
import com.sun.tools.javac.tree.JCTree.JCContinue;
import com.sun.tools.javac.tree.JCTree.JCDefaultCaseLabel;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
@@ -69,6 +71,7 @@
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCOpens;
import com.sun.tools.javac.tree.JCTree.JCPackageDecl;
import com.sun.tools.javac.tree.JCTree.JCPatternCaseLabel;
import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCProvides;
import com.sun.tools.javac.tree.JCTree.JCRecordPattern;
@@ -297,6 +300,18 @@ public void visitCase(JCCase tree) {
result = scan(tree.labels, that.labels) && scan(tree.stats, that.stats);
}

@Override
public void visitConstantCaseLabel(JCConstantCaseLabel tree) {
JCConstantCaseLabel that = (JCConstantCaseLabel) parameter;
result = scan(tree.expr, that.expr);
}

@Override
public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
JCPatternCaseLabel that = (JCPatternCaseLabel) parameter;
result = scan(tree.pat, that.pat) && scan(tree.guard, that.guard);
}

@Override
public void visitDefaultCaseLabel(JCDefaultCaseLabel tree) {
result = true;
69 changes: 58 additions & 11 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@

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

import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.tree.TreeInfo.PosKind;
@@ -170,6 +171,8 @@ protected Gen(Context context) {
Chain switchExpressionFalseChain;
List<LocalItem> stackBeforeSwitchExpression;
LocalItem switchResult;
Set<JCMethodInvocation> invocationsWithPatternMatchingCatch = Set.of();
ListBuffer<int[]> patternMatchingInvocationRanges;

/** Generate code to load an integer constant.
* @param n The integer to be loaded.
@@ -1049,6 +1052,29 @@ public void visitSkip(JCSkip tree) {
}

public void visitBlock(JCBlock tree) {
if (tree.patternMatchingCatch != null) {
Set<JCMethodInvocation> prevInvocationsWithPatternMatchingCatch = invocationsWithPatternMatchingCatch;
ListBuffer<int[]> prevRanges = patternMatchingInvocationRanges;
State startState = code.state.dup();
try {
invocationsWithPatternMatchingCatch = tree.patternMatchingCatch.calls2Handle();
patternMatchingInvocationRanges = new ListBuffer<>();
doVisitBlock(tree);
} finally {
Chain skipCatch = code.branch(goto_);
JCCatch handler = tree.patternMatchingCatch.handler();
code.entryPoint(startState, handler.param.sym.type);
genPatternMatchingCatch(handler, env, patternMatchingInvocationRanges.toList());
code.resolve(skipCatch);
invocationsWithPatternMatchingCatch = prevInvocationsWithPatternMatchingCatch;
patternMatchingInvocationRanges = prevRanges;
}
} else {
doVisitBlock(tree);
}
}

private void doVisitBlock(JCBlock tree) {
int limit = code.nextreg;
Env<GenContext> localEnv = env.dup(tree, new GenContext());
genStats(tree.stats, localEnv);
@@ -1611,18 +1637,33 @@ void genCatch(JCCatch tree,
}
}
}
VarSymbol exparam = tree.param.sym;
code.statBegin(tree.pos);
code.markStatBegin();
int limit = code.nextreg;
code.newLocal(exparam);
items.makeLocalItem(exparam).store();
code.statBegin(TreeInfo.firstStatPos(tree.body));
genStat(tree.body, env, CRT_BLOCK);
code.endScopes(limit);
code.statBegin(TreeInfo.endPos(tree.body));
genCatchBlock(tree, env);
}
}
void genPatternMatchingCatch(JCCatch tree,
Env<GenContext> env,
List<int[]> ranges) {
for (int[] range : ranges) {
JCExpression subCatch = tree.param.vartype;
int catchType = makeRef(tree.pos(), subCatch.type);
registerCatch(tree.pos(),
range[0], range[1], code.curCP(),
catchType);
}
genCatchBlock(tree, env);
}
void genCatchBlock(JCCatch tree, Env<GenContext> env) {
VarSymbol exparam = tree.param.sym;
code.statBegin(tree.pos);
code.markStatBegin();
int limit = code.nextreg;
code.newLocal(exparam);
items.makeLocalItem(exparam).store();
code.statBegin(TreeInfo.firstStatPos(tree.body));
genStat(tree.body, env, CRT_BLOCK);
code.endScopes(limit);
code.statBegin(TreeInfo.endPos(tree.body));
}
// where
List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotations(JCCatch tree) {
return TreeInfo.isMultiCatch(tree) ?
@@ -1839,7 +1880,13 @@ public void visitApply(JCMethodInvocation tree) {
if (!msym.isDynamic()) {
code.statBegin(tree.pos);
}
result = m.invoke();
if (invocationsWithPatternMatchingCatch.contains(tree)) {
int start = code.curCP();
result = m.invoke();
patternMatchingInvocationRanges.add(new int[] {start, code.curCP()});
} else {
result = m.invoke();
}
}

public void visitConditional(JCConditional tree) {
Original file line number Diff line number Diff line change
@@ -89,11 +89,15 @@

import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.main.Option.*;
import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;

import static javax.tools.StandardLocation.CLASS_OUTPUT;

import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
import com.sun.tools.javac.tree.JCTree.JCRecordPattern;
import com.sun.tools.javac.tree.JCTree.JCSwitch;
import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;

/** This class could be the main entry point for GJC when GJC is used as a
* component in a larger software system. It provides operations to
@@ -1465,6 +1469,7 @@ protected void desugar(final Env<AttrContext> env, Queue<Pair<Env<AttrContext>,
class ScanNested extends TreeScanner {
Set<Env<AttrContext>> dependencies = new LinkedHashSet<>();
protected boolean hasLambdas;
protected boolean hasPatterns;
@Override
public void visitClassDef(JCClassDecl node) {
Type st = types.supertype(node.sym.type);
@@ -1475,16 +1480,19 @@ public void visitClassDef(JCClassDecl node) {
if (stEnv != null && env != stEnv) {
if (dependencies.add(stEnv)) {
boolean prevHasLambdas = hasLambdas;
boolean prevHasPatterns = hasPatterns;
try {
scan(stEnv.tree);
} finally {
/*
* ignore any updates to hasLambdas made during
* the nested scan, this ensures an initialized
* LambdaToMethod is available only to those
* classes that contain lambdas
* ignore any updates to hasLambdas and hasPatterns
* made during the nested scan, this ensures an
* initialized LambdaToMethod or TransPatterns is
* available only to those classes that contain
* lambdas or patterns, respectivelly
*/
hasLambdas = prevHasLambdas;
hasPatterns = prevHasPatterns;
}
}
envForSuperTypeFound = true;
@@ -1503,6 +1511,31 @@ public void visitReference(JCMemberReference tree) {
hasLambdas = true;
super.visitReference(tree);
}
@Override
public void visitBindingPattern(JCBindingPattern tree) {
hasPatterns = true;
super.visitBindingPattern(tree);
}
@Override
public void visitRecordPattern(JCRecordPattern that) {
hasPatterns = true;
super.visitRecordPattern(that);
}
@Override
public void visitParenthesizedPattern(JCTree.JCParenthesizedPattern tree) {
hasPatterns = true;
super.visitParenthesizedPattern(tree);
}
@Override
public void visitSwitch(JCSwitch tree) {
hasPatterns |= tree.patternSwitch;
super.visitSwitch(tree);
}
@Override
public void visitSwitchExpression(JCSwitchExpression tree) {
hasPatterns |= tree.patternSwitch;
super.visitSwitchExpression(tree);
}
}
ScanNested scanner = new ScanNested();
scanner.scan(env.tree);
@@ -1551,7 +1584,10 @@ public void visitReference(JCMemberReference tree) {
if (shouldStop(CompileState.TRANSPATTERNS))
return;

env.tree = TransPatterns.instance(context).translateTopLevelClass(env, env.tree, localMake);
if (scanner.hasPatterns) {
env.tree = TransPatterns.instance(context).translateTopLevelClass(env, env.tree, localMake);
}

compileStates.put(env, CompileState.TRANSPATTERNS);

if (scanner.hasLambdas) {
Original file line number Diff line number Diff line change
@@ -1074,6 +1074,12 @@ public static class JCBlock extends JCStatement implements BlockTree {
public List<JCStatement> stats;
/** Position of closing brace, optional. */
public int endpos = Position.NOPOS;
/** If this block contains record pattern, it is necessary to catch
* exceptions from the deconstructors and wrap them.
* The {@code patternMatchingCatch} keeps the list of the deconstructor
* invocations, and the additional catch block that wraps the exceptions.
*/
public PatternMatchingCatch patternMatchingCatch;
protected JCBlock(long flags, List<JCStatement> stats) {
this.stats = stats;
this.flags = flags;
@@ -1098,6 +1104,8 @@ public <R,D> R accept(TreeVisitor<R,D> v, D d) {
public Tag getTag() {
return BLOCK;
}

public record PatternMatchingCatch(JCCatch handler, Set<JCMethodInvocation> calls2Handle) {}
}

/**
@@ -2218,6 +2226,9 @@ public Tag getTag() {
public static class JCInstanceOf extends JCExpression implements InstanceOfTree {
public JCExpression expr;
public JCTree pattern;
/**{@code true} if this instanceof test should have
* value {@code true} when the {@code expr} is {@code null}.*/
public boolean allowNull;
protected JCInstanceOf(JCExpression expr, JCTree pattern) {
this.expr = expr;
this.pattern = pattern;
Original file line number Diff line number Diff line change
@@ -838,6 +838,15 @@ public static JCTree skipParens(JCTree tree) {
return tree;
}

/** Skip parens and return the enclosed expression
*/
public static JCPattern skipParens(JCPattern tree) {
while (tree.hasTag(PARENTHESIZEDPATTERN)) {
tree = ((JCParenthesizedPattern) tree).pattern;
}
return tree;
}

/** Return the types of a list of trees.
*/
public static List<Type> types(List<? extends JCTree> trees) {
Original file line number Diff line number Diff line change
@@ -209,27 +209,27 @@ public void runDeconstruction() throws Exception {
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
RuntimeInvisibleTypeAnnotations:
0: #_A_(): LOCAL_VARIABLE, {start_pc=251, length=11, index=2}
0: #_A_(): LOCAL_VARIABLE, {start_pc=316, length=11, index=2}
Patterns$DeconstructionPattern$A
1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=290, length=11, index=3}
1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=359, length=11, index=3}
Patterns$DeconstructionPattern$CA(
value=[@Patterns$DeconstructionPattern$A,@Patterns$DeconstructionPattern$A]
)
2: #_A_(): LOCAL_VARIABLE, {start_pc=26, length=11, index=1}
2: #_A_(): LOCAL_VARIABLE, {start_pc=30, length=11, index=1}
Patterns$DeconstructionPattern$A
3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=63, length=11, index=1}
3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=71, length=11, index=1}
Patterns$DeconstructionPattern$CA(
value=[@Patterns$DeconstructionPattern$A,@Patterns$DeconstructionPattern$A]
)
4: #_A_(): LOCAL_VARIABLE, {start_pc=101, length=11, index=2}
4: #_A_(): LOCAL_VARIABLE, {start_pc=114, length=11, index=2}
Patterns$DeconstructionPattern$A
5: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=140, length=11, index=3}
5: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=157, length=11, index=3}
Patterns$DeconstructionPattern$CA(
value=[@Patterns$DeconstructionPattern$A,@Patterns$DeconstructionPattern$A]
)
6: #_A_(): LOCAL_VARIABLE, {start_pc=176, length=11, index=2}
6: #_A_(): LOCAL_VARIABLE, {start_pc=215, length=11, index=2}
Patterns$DeconstructionPattern$A
7: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=215, length=11, index=3}
7: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=258, length=11, index=3}
Patterns$DeconstructionPattern$CA(
value=[@Patterns$DeconstructionPattern$A,@Patterns$DeconstructionPattern$A]
)
@@ -238,30 +238,26 @@ public void runDeconstruction() throws Exception {
descriptor: ()V
flags: (0x0000)
RuntimeInvisibleTypeAnnotations:
0: #_A_(): LOCAL_VARIABLE, {start_pc=23, length=11, index=2}
0: #_A_(): LOCAL_VARIABLE, {start_pc=28, length=11, index=2}
Patterns$DeconstructionPattern$A
1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=62, length=11, index=3}
1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=71, length=11, index=3}
Patterns$DeconstructionPattern$CA(
value=[@Patterns$DeconstructionPattern$A,@Patterns$DeconstructionPattern$A]
)

private static java.lang.String $proxy$s(Patterns$DeconstructionPattern$R);
descriptor: (LPatterns$DeconstructionPattern$R;)Ljava/lang/String;
flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC

static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
RuntimeInvisibleTypeAnnotations:
0: #_A_(): LOCAL_VARIABLE, {start_pc=26, length=11, index=0}
0: #_A_(): LOCAL_VARIABLE, {start_pc=28, length=11, index=0}
Patterns$DeconstructionPattern$A
1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=62, length=11, index=0}
1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=66, length=11, index=0}
Patterns$DeconstructionPattern$CA(
value=[@Patterns$DeconstructionPattern$A,@Patterns$DeconstructionPattern$A]
)
2: #_A_(): LOCAL_VARIABLE, {start_pc=98, length=11, index=1}
2: #_A_(): LOCAL_VARIABLE, {start_pc=106, length=11, index=1}
Patterns$DeconstructionPattern$A
3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=134, length=11, index=2}
3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=147, length=11, index=2}
Patterns$DeconstructionPattern$CA(
value=[@Patterns$DeconstructionPattern$A,@Patterns$DeconstructionPattern$A]
)
Loading