8020718: RETURN symbol has wrong type in split functions

Reviewed-by: lagergren, attila
This commit is contained in:
Hannes Wallnöfer 2013-07-24 13:16:34 +02:00
parent 85d68499be
commit cf28b19245
8 changed files with 65 additions and 17 deletions

View file

@ -1754,7 +1754,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
caller.ifne(breakLabel);
//has to be zero
caller.label(new Label("split_return"));
method.loadCompilerConstant(RETURN);
caller.loadCompilerConstant(RETURN);
caller._return(lc.getCurrentFunction().getReturnType());
caller.label(breakLabel);
} else {
@ -1785,6 +1785,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
caller.label(breakLabel);
}
// If split has a return and caller is itself a split method it needs to propagate the return.
if (hasReturn) {
caller.setHasReturn();
}
return splitNode;
}

View file

@ -649,8 +649,8 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
/**
* A symbol (and {@link Property}) can be tagged as "may be primitive". This is
* used a hint for dual fields that it is even worth it to try representing this
* A symbol (and {@link jdk.nashorn.internal.runtime.Property}) can be tagged as "may be primitive".
* This is used a hint for dual fields that it is even worth it to try representing this
* field as something other than java.lang.Object.
*
* @param node node in which to tag symbols as primitive
@ -856,7 +856,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
* if the expression type changes.
*
* Assignments use their lhs as node symbol, and in this case we can't modify
* it. Then {@link CodeGenerator#Store} needs to do an explicit conversion.
* it. Then {@link CodeGenerator.Store} needs to do an explicit conversion.
* This is happens very rarely.
*
* @param node

View file

@ -1281,10 +1281,14 @@ public class MethodEmitter implements Emitter {
}
MethodEmitter registerReturn() {
this.hasReturn = true;
setHasReturn();
return this;
}
void setHasReturn() {
this.hasReturn = true;
}
/**
* Perform a non void return, popping the type from the stack
*

View file

@ -77,15 +77,15 @@ public class SplitMethodEmitter extends MethodEmitter {
}
if (lc.isExternalTarget(splitNode, label)) {
externalTargets.add(label);
return externalTargets.size() - 1;
}
return -1;
externalTargets.add(label);
return externalTargets.size() - 1;
}
return -1;
}
@Override
MethodEmitter registerReturn() {
super.registerReturn();
setHasReturn();
loadCompilerConstant(SCOPE);
checkcast(Scope.class);
load(0);

View file

@ -33,10 +33,14 @@ import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
/**
* IR representation for a list of statements.
*/
@ -212,6 +216,19 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
return isTerminal ? setFlag(lc, IS_TERMINAL) : clearFlag(lc, IS_TERMINAL);
}
/**
* Set the type of the return symbol in this block if present.
* @param returnType the new type
* @return this block
*/
public Block setReturnType(final Type returnType) {
final Symbol symbol = getExistingSymbol(RETURN.symbolName());
if (symbol != null) {
symbol.setTypeOverride(returnType);
}
return this;
}
@Override
public boolean isTerminal() {
return getFlag(IS_TERMINAL);

View file

@ -817,6 +817,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if (this.returnType == returnType) {
return this;
}
final Type type = Type.widest(this.returnType, returnType.isObject() ? Type.OBJECT : returnType);
return Node.replaceInLexicalContext(
lc,
this,
@ -825,12 +826,10 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
lastToken,
flags,
name,
Type.widest(this.returnType, returnType.isObject() ?
Type.OBJECT :
returnType),
type,
compileUnit,
compilationState,
body,
body.setReturnType(type),
parameters,
snapshot,
hints));

View file

@ -153,14 +153,27 @@ public final class IdentNode extends Expression implements PropertyKey, TypeOver
}
/**
* We can only override type if the symbol lives in the scope, otherwise
* it is strongly determined by the local variable already allocated
* We can only override type if the symbol lives in the scope, as otherwise
* it is strongly determined by the local variable already allocated.
*
* <p>We also return true if the symbol represents the return value of a function with a
* non-generic return type as in this case we need to propagate the type instead of
* converting to object, for example if the symbol is used as the left hand side of an
* assignment such as in the code below.</p>
*
* <pre>{@code
* try {
* return 2;
* } finally {
* return 3;
* }
* }</pre>
*
* @return true if can have callsite type
*/
@Override
public boolean canHaveCallSiteType() {
return getSymbol() != null && getSymbol().isScope();
return getSymbol() != null && (getSymbol().isScope() || getSymbol().isNonGenericReturn());
}
/**

View file

@ -35,6 +35,8 @@ import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.options.Options;
import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
/**
* Maps a name to specific data.
*/
@ -441,6 +443,14 @@ public final class Symbol implements Comparable<Symbol> {
this.range = range;
}
/**
* Check if this symbol represents a return value with a known non-generic type.
* @return true if specialized return value
*/
public boolean isNonGenericReturn() {
return getName().equals(RETURN.symbolName()) && type != Type.OBJECT;
}
/**
* Check if this symbol is a function parameter of known
* narrowest type