mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-20 21:03:18 +00:00
8038945: Simplify strict undefined checks
Reviewed-by: jlaskey, hannesw
This commit is contained in:
parent
1584dc799c
commit
fd8e5653a0
@ -86,6 +86,7 @@ package jdk.internal.dynalink.support;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -103,7 +104,7 @@ import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
* @author Attila Szegedi
|
||||
*/
|
||||
public class CallSiteDescriptorFactory {
|
||||
private static final WeakHashMap<CallSiteDescriptor, WeakReference<CallSiteDescriptor>> publicDescs =
|
||||
private static final WeakHashMap<CallSiteDescriptor, Reference<CallSiteDescriptor>> publicDescs =
|
||||
new WeakHashMap<>();
|
||||
|
||||
|
||||
@ -134,18 +135,27 @@ public class CallSiteDescriptorFactory {
|
||||
|
||||
static CallSiteDescriptor getCanonicalPublicDescriptor(final CallSiteDescriptor desc) {
|
||||
synchronized(publicDescs) {
|
||||
final WeakReference<CallSiteDescriptor> ref = publicDescs.get(desc);
|
||||
final Reference<CallSiteDescriptor> ref = publicDescs.get(desc);
|
||||
if(ref != null) {
|
||||
final CallSiteDescriptor canonical = ref.get();
|
||||
if(canonical != null) {
|
||||
return canonical;
|
||||
}
|
||||
}
|
||||
publicDescs.put(desc, new WeakReference<>(desc));
|
||||
publicDescs.put(desc, createReference(desc));
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to use a different kind of references for the cache
|
||||
* @param desc desc
|
||||
* @return reference
|
||||
*/
|
||||
protected static Reference<CallSiteDescriptor> createReference(final CallSiteDescriptor desc) {
|
||||
return new WeakReference<>(desc);
|
||||
}
|
||||
|
||||
private static CallSiteDescriptor createPublicCallSiteDescriptor(String[] tokenizedName, MethodType methodType) {
|
||||
final int l = tokenizedName.length;
|
||||
if(l > 0 && tokenizedName[0] == "dyn") {
|
||||
|
||||
@ -1413,7 +1413,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
|
||||
return leaveBinaryArithmetic(binaryNode);
|
||||
}
|
||||
|
||||
private Node leaveCmp(final BinaryNode binaryNode) {
|
||||
private BinaryNode leaveCmp(final BinaryNode binaryNode) {
|
||||
//infect untyped comp with opportunistic type from other
|
||||
final Expression lhs = binaryNode.lhs();
|
||||
final Expression rhs = binaryNode.rhs();
|
||||
@ -1423,7 +1423,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
|
||||
final Type widest = Type.widest(lhs.getType(), rhs.getType());
|
||||
ensureSymbol(lhs, widest);
|
||||
ensureSymbol(rhs, widest);
|
||||
return end(ensureSymbol(binaryNode, Type.BOOLEAN));
|
||||
return (BinaryNode)end(ensureSymbol(binaryNode, Type.BOOLEAN));
|
||||
}
|
||||
|
||||
private boolean enterBinaryArithmetic(final BinaryNode binaryNode) {
|
||||
|
||||
@ -1991,6 +1991,56 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
return node instanceof LiteralNode<?> && ((LiteralNode<?>) node).isNull();
|
||||
}
|
||||
|
||||
|
||||
private boolean undefinedCheck(final RuntimeNode runtimeNode, final List<Expression> args) {
|
||||
final Request request = runtimeNode.getRequest();
|
||||
|
||||
if (!Request.isUndefinedCheck(request)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Expression lhs = args.get(0);
|
||||
final Expression rhs = args.get(1);
|
||||
|
||||
if (!rhs.getSymbol().isScope()) {
|
||||
return false; //disallow undefined as local var or parameter
|
||||
}
|
||||
|
||||
//make sure that undefined has not been overridden or scoped as a local var
|
||||
//between us and global
|
||||
final CompilationEnvironment env = compiler.getCompilationEnvironment();
|
||||
RecompilableScriptFunctionData data = env.getScriptFunctionData(lc.getCurrentFunction().getId());
|
||||
final RecompilableScriptFunctionData program = compiler.getCompilationEnvironment().getProgram();
|
||||
assert data != null;
|
||||
while (data != program) {
|
||||
if (data.hasInternalSymbol("undefined")) {
|
||||
return false;
|
||||
}
|
||||
data = data.getParent();
|
||||
}
|
||||
|
||||
load(lhs);
|
||||
if (lhs.getType().isPrimitive()) {
|
||||
method.pop(); //throw away lhs, but it still needs to be evaluated for side effects, even if not in scope, as it can be optimistic
|
||||
method.load(request == Request.IS_NOT_UNDEFINED);
|
||||
method.store(runtimeNode.getSymbol());
|
||||
} else {
|
||||
final Label isUndefined = new Label("ud_check_true");
|
||||
final Label notUndefined = new Label("ud_check_false");
|
||||
final Label end = new Label("end");
|
||||
method.loadUndefined(Type.OBJECT);
|
||||
method.if_acmpeq(isUndefined);
|
||||
method.label(notUndefined);
|
||||
method.load(request == Request.IS_NOT_UNDEFINED);
|
||||
method._goto(end);
|
||||
method.label(isUndefined);
|
||||
method.load(request == Request.IS_UNDEFINED);
|
||||
method.label(end);
|
||||
method.store(runtimeNode.getSymbol());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean nullCheck(final RuntimeNode runtimeNode, final List<Expression> args) {
|
||||
final Request request = runtimeNode.getRequest();
|
||||
|
||||
@ -2078,7 +2128,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
return false;
|
||||
}
|
||||
|
||||
assert args.size() == 2;
|
||||
assert args.size() == 2 : node;
|
||||
final Type returnType = node.getType();
|
||||
|
||||
new OptimisticOperation() {
|
||||
@ -2135,7 +2185,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
*
|
||||
* TODO - remove this - Access Specializer will always know after Attr/Lower
|
||||
*/
|
||||
final List<Expression> args = runtimeNode.getArgs();
|
||||
final List<Expression> args = new ArrayList<>(runtimeNode.getArgs());
|
||||
if (runtimeNode.isPrimitive() && !runtimeNode.isFinal() && isReducible(runtimeNode.getRequest())) {
|
||||
final Expression lhs = args.get(0);
|
||||
|
||||
@ -2186,14 +2236,25 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) {
|
||||
if (undefinedCheck(runtimeNode, args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final RuntimeNode newRuntimeNode;
|
||||
if (Request.isUndefinedCheck(runtimeNode.getRequest())) {
|
||||
newRuntimeNode = runtimeNode.setRequest(runtimeNode.getRequest() == Request.IS_UNDEFINED ? Request.EQ_STRICT : Request.NE_STRICT);
|
||||
} else {
|
||||
newRuntimeNode = runtimeNode;
|
||||
}
|
||||
|
||||
if (!newRuntimeNode.isFinal() && specializationCheck(newRuntimeNode.getRequest(), newRuntimeNode, args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
new OptimisticOperation() {
|
||||
@Override
|
||||
void loadStack() {
|
||||
for (final Expression arg : args) {
|
||||
for (final Expression arg : newRuntimeNode.getArgs()) {
|
||||
load(arg, Type.OBJECT);
|
||||
}
|
||||
}
|
||||
@ -2201,17 +2262,17 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
void consumeStack() {
|
||||
method.invokestatic(
|
||||
CompilerConstants.className(ScriptRuntime.class),
|
||||
runtimeNode.getRequest().toString(),
|
||||
newRuntimeNode.getRequest().toString(),
|
||||
new FunctionSignature(
|
||||
false,
|
||||
false,
|
||||
runtimeNode.getType(),
|
||||
args.size()).toString());
|
||||
newRuntimeNode.getType(),
|
||||
newRuntimeNode.getArgs().size()).toString());
|
||||
}
|
||||
}.emit(runtimeNode);
|
||||
}.emit(newRuntimeNode);
|
||||
|
||||
method.convert(runtimeNode.getType());
|
||||
method.store(runtimeNode.getSymbol());
|
||||
method.convert(newRuntimeNode.getType());
|
||||
method.store(newRuntimeNode.getSymbol());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -477,6 +477,20 @@ public final class CompilationEnvironment {
|
||||
return optimistic;
|
||||
}
|
||||
|
||||
RecompilableScriptFunctionData getProgram() {
|
||||
if (compiledFunction == null) {
|
||||
return null;
|
||||
}
|
||||
RecompilableScriptFunctionData program = compiledFunction;
|
||||
while (true) {
|
||||
final RecompilableScriptFunctionData parent = program.getParent();
|
||||
if (parent == null) {
|
||||
return program;
|
||||
}
|
||||
program = parent;
|
||||
}
|
||||
}
|
||||
|
||||
RecompilableScriptFunctionData getScriptFunctionData(final int functionId) {
|
||||
return compiledFunction == null ? null : compiledFunction.getScriptFunctionData(functionId);
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Iterator;
|
||||
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
|
||||
@ -28,7 +28,6 @@ package jdk.nashorn.internal.codegen;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
|
||||
|
||||
import jdk.nashorn.internal.ir.BinaryNode;
|
||||
import jdk.nashorn.internal.ir.Block;
|
||||
import jdk.nashorn.internal.ir.Expression;
|
||||
@ -38,6 +37,8 @@ import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
|
||||
import jdk.nashorn.internal.ir.LexicalContext;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode.Request;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.ir.UnaryNode;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
|
||||
@ -83,6 +84,35 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
|
||||
setModify(lc, modify == null ? null : discard(modify));
|
||||
}
|
||||
|
||||
private static Node createIsUndefined(final Expression parent, final Expression lhs, final Expression rhs, final Request request) {
|
||||
if ("undefined".equals(rhs.getSymbol().getName())) {
|
||||
return new RuntimeNode(parent, request, lhs, rhs);
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
|
||||
return createIsUndefined(binaryNode, binaryNode.lhs(), binaryNode.rhs(), Request.IS_UNDEFINED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveNE_STRICT(final BinaryNode binaryNode) {
|
||||
return createIsUndefined(binaryNode, binaryNode.lhs(), binaryNode.rhs(), Request.IS_NOT_UNDEFINED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
|
||||
switch (runtimeNode.getRequest()) {
|
||||
case EQ_STRICT:
|
||||
return createIsUndefined(runtimeNode, runtimeNode.getArgs().get(0), runtimeNode.getArgs().get(1), Request.IS_UNDEFINED);
|
||||
case NE_STRICT:
|
||||
return createIsUndefined(runtimeNode, runtimeNode.getArgs().get(0), runtimeNode.getArgs().get(1), Request.IS_NOT_UNDEFINED);
|
||||
default:
|
||||
return runtimeNode;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
|
||||
assert binaryNode.getSymbol() != null;
|
||||
@ -194,7 +224,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
|
||||
|
||||
private static Expression discard(final Expression expr) {
|
||||
if (expr.getSymbol() != null) {
|
||||
UnaryNode discard = new UnaryNode(Token.recast(expr.getToken(), TokenType.DISCARD), expr);
|
||||
final UnaryNode discard = new UnaryNode(Token.recast(expr.getToken(), TokenType.DISCARD), expr);
|
||||
//discard never has a symbol in the discard node - then it would be a nop
|
||||
assert !expr.isTerminal();
|
||||
return discard;
|
||||
|
||||
@ -33,6 +33,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.nashorn.internal.ir.Block;
|
||||
import jdk.nashorn.internal.ir.Expression;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
@ -41,6 +42,7 @@ import jdk.nashorn.internal.ir.LexicalContext;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.DebugLogger;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
|
||||
|
||||
@ -57,6 +59,9 @@ final class FindScopeDepths extends NodeVisitor<LexicalContext> {
|
||||
private final CompilationEnvironment env;
|
||||
private final Map<Integer, Map<Integer, RecompilableScriptFunctionData>> fnIdToNestedFunctions = new HashMap<>();
|
||||
private final Map<Integer, Map<String, Integer>> externalSymbolDepths = new HashMap<>();
|
||||
private final Map<Integer, Set<String>> internalSymbols = new HashMap<>();
|
||||
|
||||
private final static DebugLogger LOG = new DebugLogger("scopedepths");
|
||||
|
||||
FindScopeDepths(final Compiler compiler) {
|
||||
super(new LexicalContext());
|
||||
@ -123,7 +128,7 @@ final class FindScopeDepths extends NodeVisitor<LexicalContext> {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Block findGlobalBlock(final LexicalContext lc, final FunctionNode fn, final Block block) {
|
||||
private static Block findGlobalBlock(final LexicalContext lc, final Block block) {
|
||||
final Iterator<Block> iter = lc.getBlocks(block);
|
||||
Block globalBlock = null;
|
||||
while (iter.hasNext()) {
|
||||
@ -174,7 +179,8 @@ final class FindScopeDepths extends NodeVisitor<LexicalContext> {
|
||||
allocatorMap,
|
||||
nestedFunctions,
|
||||
compiler.getSourceURL(),
|
||||
externalSymbolDepths.get(fnId)
|
||||
externalSymbolDepths.get(fnId),
|
||||
internalSymbols.get(fnId)
|
||||
);
|
||||
|
||||
if (lc.getOutermostFunction() != newFunctionNode) {
|
||||
@ -223,15 +229,15 @@ final class FindScopeDepths extends NodeVisitor<LexicalContext> {
|
||||
|
||||
final Map<String, Integer> internals = new HashMap<>();
|
||||
|
||||
final Block globalBlock = findGlobalBlock(lc, block);
|
||||
final Block bodyBlock = findBodyBlock(lc, fn, block);
|
||||
|
||||
assert globalBlock != null;
|
||||
assert bodyBlock != null;
|
||||
|
||||
for (final Symbol symbol : symbols) {
|
||||
Iterator<Block> iter;
|
||||
|
||||
final Block globalBlock = findGlobalBlock(lc, fn, block);
|
||||
final Block bodyBlock = findBodyBlock(lc, fn, block);
|
||||
|
||||
assert globalBlock != null;
|
||||
assert bodyBlock != null;
|
||||
|
||||
final int internalDepth = findInternalDepth(lc, fn, block, symbol);
|
||||
final boolean internal = internalDepth >= 0;
|
||||
if (internal) {
|
||||
@ -258,9 +264,21 @@ final class FindScopeDepths extends NodeVisitor<LexicalContext> {
|
||||
}
|
||||
}
|
||||
|
||||
addInternalSymbols(fn, internals.keySet());
|
||||
|
||||
if (LOG.isEnabled()) {
|
||||
LOG.info(fn.getName() + " internals=" + internals + " externals=" + externalSymbolDepths.get(fn.getId()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addInternalSymbols(final FunctionNode functionNode, final Set<String> symbols) {
|
||||
final int fnId = functionNode.getId();
|
||||
assert internalSymbols.get(fnId) == null || internalSymbols.get(fnId).equals(symbols); //e.g. cloned finally block
|
||||
internalSymbols.put(fnId, symbols);
|
||||
}
|
||||
|
||||
private void addExternalSymbol(final FunctionNode functionNode, final Symbol symbol, final int depthAtStart) {
|
||||
final int fnId = functionNode.getId();
|
||||
Map<String, Integer> depths = externalSymbolDepths.get(fnId);
|
||||
@ -268,7 +286,6 @@ final class FindScopeDepths extends NodeVisitor<LexicalContext> {
|
||||
depths = new HashMap<>();
|
||||
externalSymbolDepths.put(fnId, depths);
|
||||
}
|
||||
//System.err.println("PUT " + functionNode.getName() + " " + symbol + " " +depthAtStart);
|
||||
depths.put(symbol.getName(), depthAtStart);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,11 +29,11 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
|
||||
|
||||
/**
|
||||
@ -80,8 +80,10 @@ public class RuntimeNode extends Expression implements Optimistic {
|
||||
NE_STRICT(TokenType.NE_STRICT, Type.BOOLEAN, 2, true),
|
||||
/** != operator with at least one object */
|
||||
NE(TokenType.NE, Type.BOOLEAN, 2, true),
|
||||
/** Verify type */
|
||||
TYPE_GUARD(TokenType.VOID, Type.INT, 2);
|
||||
/** is undefined */
|
||||
IS_UNDEFINED(TokenType.EQ_STRICT, Type.BOOLEAN, 2),
|
||||
/** is not undefined */
|
||||
IS_NOT_UNDEFINED(TokenType.NE_STRICT, Type.BOOLEAN, 2);
|
||||
|
||||
/** token type */
|
||||
private final TokenType tokenType;
|
||||
@ -192,6 +194,17 @@ public class RuntimeNode extends Expression implements Optimistic {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an undefined check?
|
||||
*
|
||||
* @param request request
|
||||
*
|
||||
* @return true if undefined check
|
||||
*/
|
||||
public static boolean isUndefinedCheck(final Request request) {
|
||||
return request == IS_UNDEFINED || request == IS_NOT_UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an EQ or EQ_STRICT?
|
||||
*
|
||||
@ -300,6 +313,8 @@ public class RuntimeNode extends Expression implements Optimistic {
|
||||
case LT:
|
||||
case GE:
|
||||
case GT:
|
||||
case IS_UNDEFINED:
|
||||
case IS_NOT_UNDEFINED:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -403,6 +418,19 @@ public class RuntimeNode extends Expression implements Optimistic {
|
||||
this(parent, request, parent.lhs(), parent.rhs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the request for this runtime node
|
||||
* @param request request
|
||||
* @return new runtime node or same if same request
|
||||
*/
|
||||
public RuntimeNode setRequest(final Request request) {
|
||||
if (this.request == request) {
|
||||
return this;
|
||||
}
|
||||
return new RuntimeNode(this, request, isFinal, args, programPoint);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is this node final - i.e. it can never be replaced with other nodes again
|
||||
* @return true if final
|
||||
@ -473,7 +501,12 @@ public class RuntimeNode extends Expression implements Optimistic {
|
||||
return Collections.unmodifiableList(args);
|
||||
}
|
||||
|
||||
private RuntimeNode setArgs(final List<Expression> args) {
|
||||
/**
|
||||
* Set the arguments of this runtime node
|
||||
* @param args new arguments
|
||||
* @return new runtime node, or identical if no change
|
||||
*/
|
||||
public RuntimeNode setArgs(final List<Expression> args) {
|
||||
if (this.args == args) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -123,6 +123,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
|
||||
private final Map<String, Integer> externalScopeDepths;
|
||||
|
||||
private final Set<String> internalSymbols;
|
||||
|
||||
private static final int GET_SET_PREFIX_LENGTH = "*et ".length();
|
||||
|
||||
/**
|
||||
@ -135,6 +137,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
* @param nestedFunctions nested function map
|
||||
* @param sourceURL source URL
|
||||
* @param externalScopeDepths external scope depths
|
||||
* @param internalSymbols internal symbols to method, defined in its scope
|
||||
*/
|
||||
public RecompilableScriptFunctionData(
|
||||
final FunctionNode functionNode,
|
||||
@ -143,7 +146,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
final PropertyMap allocatorMap,
|
||||
final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
|
||||
final String sourceURL,
|
||||
final Map<String, Integer> externalScopeDepths) {
|
||||
final Map<String, Integer> externalScopeDepths,
|
||||
final Set<String> internalSymbols) {
|
||||
|
||||
super(functionName(functionNode),
|
||||
Math.min(functionNode.getParameters().size(), MAX_ARITY),
|
||||
@ -161,8 +165,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
this.sourceURL = sourceURL;
|
||||
this.allocatorClassName = allocatorClassName;
|
||||
this.allocatorMap = allocatorMap;
|
||||
this.nestedFunctions = nestedFunctions;//deepTraverse(nestedFunctions);
|
||||
this.nestedFunctions = nestedFunctions;
|
||||
this.externalScopeDepths = externalScopeDepths;
|
||||
this.internalSymbols = internalSymbols;
|
||||
|
||||
for (final RecompilableScriptFunctionData nfn : nestedFunctions.values()) {
|
||||
assert nfn.getParent() == null;
|
||||
@ -170,6 +175,19 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a symbol is internally defined in a function. For example
|
||||
* if "undefined" is internally defined in the outermost program function,
|
||||
* it has not been reassigned or overridden and can be optimized
|
||||
*
|
||||
* @param symbolName symbol name
|
||||
* @return true if symbol is internal to this ScriptFunction
|
||||
*/
|
||||
|
||||
public boolean hasInternalSymbol(final String symbolName) {
|
||||
return internalSymbols.contains(symbolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the external symbol table
|
||||
* @param symbolName symbol name
|
||||
|
||||
137
nashorn/test/script/basic/JDK-8038945.js
Normal file
137
nashorn/test/script/basic/JDK-8038945.js
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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-8038945.js : test various undefined strict intrinsics and that they
|
||||
* aren't erroneously applied when undefined is in any scope but global
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
//:program internals={print=0, f1=0, f2=0, f3=0, f4=0, undefined=0, f5=0} externals=null
|
||||
|
||||
//f1 internals={} externals={undefined=0}
|
||||
function f1(x) {
|
||||
return x === undefined;
|
||||
}
|
||||
|
||||
//f2 internals={} externals=null
|
||||
function f2(x, undefined) {
|
||||
return x === undefined;
|
||||
}
|
||||
|
||||
//f3 internals={x=0} externals=null
|
||||
function f3(x) {
|
||||
//f3$f3_2 internals={} externals={x=0}
|
||||
function f3_2(undefined) {
|
||||
return x === undefined;
|
||||
}
|
||||
return f3_2(17);
|
||||
}
|
||||
|
||||
//f4 internals={x=0} externals=null
|
||||
function f4(x) {
|
||||
//f4$f4_2 internals={} externals={x=0}
|
||||
function f4_2() {
|
||||
var undefined = 17;
|
||||
return x === undefined;
|
||||
}
|
||||
return f4_2();
|
||||
}
|
||||
|
||||
//f5 internals={x=0, undefined=0} externals=null
|
||||
function f5(x) {
|
||||
var undefined = 17;
|
||||
//f5$f5_2 internals={} externals={x=0, undefined=0}
|
||||
function f5_2() {
|
||||
return x === undefined;
|
||||
}
|
||||
return f5_2();
|
||||
}
|
||||
|
||||
print(" 1: " + f1(17) + " === false");
|
||||
print(" 2: " + f2(17) + " === false");
|
||||
print(" 3: " + f3(17) + " === true");
|
||||
print(" 4: " + f4(17) + " === true");
|
||||
print(" 5: " + f5(17) + " === true");
|
||||
|
||||
//recompile
|
||||
print(" 6: " + f1("17") + " === false");
|
||||
print(" 7: " + f2("17") + " === false");
|
||||
print(" 8: " + f3("17") + " === false");
|
||||
print(" 9: " + f4("17") + " === false");
|
||||
print("10: " + f5("17") + " === false");
|
||||
|
||||
//g1 internals={} externals={undefined=0}
|
||||
function g1(x) {
|
||||
return x !== undefined;
|
||||
}
|
||||
|
||||
//g2 internals={} externals=null
|
||||
function g2(x, undefined) {
|
||||
return x !== undefined;
|
||||
}
|
||||
|
||||
//g3 internals={x=0} externals=null
|
||||
function g3(x) {
|
||||
//g3$g3_2 internals={} externals={x=0}
|
||||
function g3_2(undefined) {
|
||||
return x !== undefined;
|
||||
}
|
||||
return g3_2(17);
|
||||
}
|
||||
|
||||
//g4 internals={x=0} externals=null
|
||||
function g4(x) {
|
||||
//f4$f4_2 internals={} externals={x=0}
|
||||
function g4_2() {
|
||||
var undefined = 17;
|
||||
return x !== undefined;
|
||||
}
|
||||
return g4_2();
|
||||
}
|
||||
|
||||
//g5 internals={x=0, undefined=0} externals=null
|
||||
function g5(x) {
|
||||
var undefined = 17;
|
||||
//g5$g5_2 internals={} externals={x=0, undefined=0}
|
||||
function g5_2() {
|
||||
return x !== undefined;
|
||||
}
|
||||
return g5_2();
|
||||
}
|
||||
|
||||
print("11: " + g1(17) + " === true");
|
||||
print("12: " + g2(17) + " === true");
|
||||
print("13: " + g3(17) + " === false");
|
||||
print("14: " + g4(17) + " === false");
|
||||
print("15: " + g5(17) + " === false");
|
||||
|
||||
//recompile
|
||||
print("16: " + g1("17") + " === true");
|
||||
print("17: " + g2("17") + " === true");
|
||||
print("18: " + g3("17") + " === true");
|
||||
print("19: " + g4("17") + " === true");
|
||||
print("20: " + g5("17") + " === true");
|
||||
|
||||
20
nashorn/test/script/basic/JDK-8038945.js.EXPECTED
Normal file
20
nashorn/test/script/basic/JDK-8038945.js.EXPECTED
Normal file
@ -0,0 +1,20 @@
|
||||
1: false === false
|
||||
2: false === false
|
||||
3: true === true
|
||||
4: true === true
|
||||
5: true === true
|
||||
6: false === false
|
||||
7: false === false
|
||||
8: false === false
|
||||
9: false === false
|
||||
10: false === false
|
||||
11: true === true
|
||||
12: true === true
|
||||
13: false === false
|
||||
14: false === false
|
||||
15: false === false
|
||||
16: true === true
|
||||
17: true === true
|
||||
18: true === true
|
||||
19: true === true
|
||||
20: true === true
|
||||
Loading…
x
Reference in New Issue
Block a user