8066225: NPE in MethodEmitter with duplicate integer switch cases
Reviewed-by: hannesw, lagergren
This commit is contained in:
parent
d3b4347330
commit
47e744920e
@ -917,7 +917,7 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
|
|||||||
@Override
|
@Override
|
||||||
public Node leaveSwitchNode(final SwitchNode switchNode) {
|
public Node leaveSwitchNode(final SwitchNode switchNode) {
|
||||||
// We only need a symbol for the tag if it's not an integer switch node
|
// We only need a symbol for the tag if it's not an integer switch node
|
||||||
if(!switchNode.isInteger()) {
|
if(!switchNode.isUniqueInteger()) {
|
||||||
switchNode.setTag(newObjectInternal(SWITCH_TAG_PREFIX));
|
switchNode.setTag(newObjectInternal(SWITCH_TAG_PREFIX));
|
||||||
}
|
}
|
||||||
return switchNode;
|
return switchNode;
|
||||||
|
@ -2817,7 +2817,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
|||||||
Label defaultLabel = defaultCase != null ? defaultCase.getEntry() : breakLabel;
|
Label defaultLabel = defaultCase != null ? defaultCase.getEntry() : breakLabel;
|
||||||
final boolean hasSkipConversion = LocalVariableConversion.hasLiveConversion(switchNode);
|
final boolean hasSkipConversion = LocalVariableConversion.hasLiveConversion(switchNode);
|
||||||
|
|
||||||
if (switchNode.isInteger()) {
|
if (switchNode.isUniqueInteger()) {
|
||||||
// Tree for sorting values.
|
// Tree for sorting values.
|
||||||
final TreeMap<Integer, Label> tree = new TreeMap<>();
|
final TreeMap<Integer, Label> tree = new TreeMap<>();
|
||||||
|
|
||||||
|
@ -26,12 +26,16 @@
|
|||||||
package jdk.nashorn.internal.codegen;
|
package jdk.nashorn.internal.codegen;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import jdk.nashorn.internal.codegen.types.Type;
|
import jdk.nashorn.internal.codegen.types.Type;
|
||||||
import jdk.nashorn.internal.ir.BinaryNode;
|
import jdk.nashorn.internal.ir.BinaryNode;
|
||||||
import jdk.nashorn.internal.ir.Block;
|
import jdk.nashorn.internal.ir.Block;
|
||||||
import jdk.nashorn.internal.ir.BlockStatement;
|
import jdk.nashorn.internal.ir.BlockStatement;
|
||||||
|
import jdk.nashorn.internal.ir.CaseNode;
|
||||||
import jdk.nashorn.internal.ir.EmptyNode;
|
import jdk.nashorn.internal.ir.EmptyNode;
|
||||||
|
import jdk.nashorn.internal.ir.Expression;
|
||||||
import jdk.nashorn.internal.ir.FunctionNode;
|
import jdk.nashorn.internal.ir.FunctionNode;
|
||||||
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
|
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
|
||||||
import jdk.nashorn.internal.ir.IfNode;
|
import jdk.nashorn.internal.ir.IfNode;
|
||||||
@ -40,6 +44,7 @@ import jdk.nashorn.internal.ir.LiteralNode;
|
|||||||
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
|
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
|
||||||
import jdk.nashorn.internal.ir.Node;
|
import jdk.nashorn.internal.ir.Node;
|
||||||
import jdk.nashorn.internal.ir.Statement;
|
import jdk.nashorn.internal.ir.Statement;
|
||||||
|
import jdk.nashorn.internal.ir.SwitchNode;
|
||||||
import jdk.nashorn.internal.ir.TernaryNode;
|
import jdk.nashorn.internal.ir.TernaryNode;
|
||||||
import jdk.nashorn.internal.ir.UnaryNode;
|
import jdk.nashorn.internal.ir.UnaryNode;
|
||||||
import jdk.nashorn.internal.ir.VarNode;
|
import jdk.nashorn.internal.ir.VarNode;
|
||||||
@ -131,6 +136,32 @@ final class FoldConstants extends NodeVisitor<LexicalContext> implements Loggabl
|
|||||||
return ternaryNode;
|
return ternaryNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node leaveSwitchNode(final SwitchNode switchNode) {
|
||||||
|
return switchNode.setUniqueInteger(lc, isUniqueIntegerSwitchNode(switchNode));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isUniqueIntegerSwitchNode(final SwitchNode switchNode) {
|
||||||
|
final Set<Integer> alreadySeen = new HashSet<>();
|
||||||
|
for (final CaseNode caseNode : switchNode.getCases()) {
|
||||||
|
final Expression test = caseNode.getTest();
|
||||||
|
if (test != null && !isUniqueIntegerLiteral(test, alreadySeen)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isUniqueIntegerLiteral(final Expression expr, final Set<Integer> alreadySeen) {
|
||||||
|
if (expr instanceof LiteralNode) {
|
||||||
|
final Object value = ((LiteralNode<?>)expr).getValue();
|
||||||
|
if (value instanceof Integer) {
|
||||||
|
return alreadySeen.add((Integer)value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to evaluate constant expressions at compile time This is
|
* Helper class to evaluate constant expressions at compile time This is
|
||||||
* also a simplifier used by BinaryNode visits, UnaryNode visits and
|
* also a simplifier used by BinaryNode visits, UnaryNode visits and
|
||||||
|
@ -709,7 +709,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{
|
|||||||
|
|
||||||
// Control flow is different for all-integer cases where we dispatch by switch table, and for all other cases
|
// Control flow is different for all-integer cases where we dispatch by switch table, and for all other cases
|
||||||
// where we do sequential comparison. Note that CaseNode objects act as join points.
|
// where we do sequential comparison. Note that CaseNode objects act as join points.
|
||||||
final boolean isInteger = switchNode.isInteger();
|
final boolean isInteger = switchNode.isUniqueInteger();
|
||||||
final Label breakLabel = switchNode.getBreakLabel();
|
final Label breakLabel = switchNode.getBreakLabel();
|
||||||
final boolean hasDefault = switchNode.getDefaultCase() != null;
|
final boolean hasDefault = switchNode.getDefaultCase() != null;
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Lo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node leaveSwitchNode(final SwitchNode switchNode) {
|
public Node leaveSwitchNode(final SwitchNode switchNode) {
|
||||||
if(!switchNode.isInteger()) {
|
if(!switchNode.isUniqueInteger()) {
|
||||||
// Wrap it in a block so its internally created tag is restricted in scope
|
// Wrap it in a block so its internally created tag is restricted in scope
|
||||||
addStatementEnclosedInBlock(switchNode);
|
addStatementEnclosedInBlock(switchNode);
|
||||||
} else {
|
} else {
|
||||||
|
@ -48,6 +48,10 @@ public final class SwitchNode extends BreakableStatement {
|
|||||||
/** Switch default index. */
|
/** Switch default index. */
|
||||||
private final int defaultCaseIndex;
|
private final int defaultCaseIndex;
|
||||||
|
|
||||||
|
/** True if all cases are 32-bit signed integer constants, without repetitions. It's a prerequisite for
|
||||||
|
* using a tableswitch/lookupswitch when generating code. */
|
||||||
|
private final boolean uniqueInteger;
|
||||||
|
|
||||||
/** Tag symbol. */
|
/** Tag symbol. */
|
||||||
private Symbol tag;
|
private Symbol tag;
|
||||||
|
|
||||||
@ -66,15 +70,17 @@ public final class SwitchNode extends BreakableStatement {
|
|||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.cases = cases;
|
this.cases = cases;
|
||||||
this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
|
this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
|
||||||
|
this.uniqueInteger = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SwitchNode(final SwitchNode switchNode, final Expression expression, final List<CaseNode> cases,
|
private SwitchNode(final SwitchNode switchNode, final Expression expression, final List<CaseNode> cases,
|
||||||
final int defaultCaseIndex, final LocalVariableConversion conversion) {
|
final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger) {
|
||||||
super(switchNode, conversion);
|
super(switchNode, conversion);
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.cases = cases;
|
this.cases = cases;
|
||||||
this.defaultCaseIndex = defaultCaseIndex;
|
this.defaultCaseIndex = defaultCaseIndex;
|
||||||
this.tag = switchNode.getTag(); //TODO are symbols inhereted as references?
|
this.tag = switchNode.getTag(); //TODO are symbols inherited as references?
|
||||||
|
this.uniqueInteger = uniqueInteger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -83,7 +89,7 @@ public final class SwitchNode extends BreakableStatement {
|
|||||||
for (final CaseNode caseNode : cases) {
|
for (final CaseNode caseNode : cases) {
|
||||||
newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody(), caseNode.getLocalVariableConversion()));
|
newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody(), caseNode.getLocalVariableConversion()));
|
||||||
}
|
}
|
||||||
return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion));
|
return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -151,7 +157,7 @@ public final class SwitchNode extends BreakableStatement {
|
|||||||
if (this.cases == cases) {
|
if (this.cases == cases) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion));
|
return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,7 +189,7 @@ public final class SwitchNode extends BreakableStatement {
|
|||||||
if (this.expression == expression) {
|
if (this.expression == expression) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion));
|
return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -205,25 +211,30 @@ public final class SwitchNode extends BreakableStatement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if all cases of this switch statement are 32-bit signed integer constants.
|
* Returns true if all cases of this switch statement are 32-bit signed integer constants, without repetitions.
|
||||||
* @return true if all cases of this switch statement are 32-bit signed integer constants.
|
* @return true if all cases of this switch statement are 32-bit signed integer constants, without repetitions.
|
||||||
*/
|
*/
|
||||||
public boolean isInteger() {
|
public boolean isUniqueInteger() {
|
||||||
for (final CaseNode caseNode : cases) {
|
return uniqueInteger;
|
||||||
final Expression test = caseNode.getTest();
|
}
|
||||||
if (test != null && !isIntegerLiteral(test)) {
|
|
||||||
return false;
|
/**
|
||||||
}
|
* Sets whether all cases of this switch statement are 32-bit signed integer constants, without repetitions.
|
||||||
|
* @param lc lexical context
|
||||||
|
* @param uniqueInteger if true, all cases of this switch statement have been determined to be 32-bit signed
|
||||||
|
* integer constants, without repetitions.
|
||||||
|
* @return this switch node, if the value didn't change, or a new switch node with the changed value
|
||||||
|
*/
|
||||||
|
public SwitchNode setUniqueInteger(final LexicalContext lc, final boolean uniqueInteger) {
|
||||||
|
if(this.uniqueInteger == uniqueInteger) {
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
return true;
|
return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
|
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
|
||||||
return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion));
|
return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isIntegerLiteral(final Expression expr) {
|
|
||||||
return expr instanceof LiteralNode && ((LiteralNode<?>)expr).getValue() instanceof Integer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
36
nashorn/test/script/basic/JDK-8066225.js
Normal file
36
nashorn/test/script/basic/JDK-8066225.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDK-8066225: NPE in MethodEmitter with duplicate integer switch cases
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (x){
|
||||||
|
switch(x) {
|
||||||
|
case 44: for (var x in {}) {x}; print("1");
|
||||||
|
case 44: print("2");
|
||||||
|
}
|
||||||
|
})(44);
|
2
nashorn/test/script/basic/JDK-8066225.js.EXPECTED
Normal file
2
nashorn/test/script/basic/JDK-8066225.js.EXPECTED
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
1
|
||||||
|
2
|
Loading…
x
Reference in New Issue
Block a user