# HG changeset patch # User lagergren # Date 1396361558 -7200 # Node ID 9833d3ceed5b67862f2615433377f4a734b81f01 # Parent da070553a8e1c2b5cf0e8d5fb22dbe8c4e16c8a4 8038945: Simplify strict undefined checks Reviewed-by: jlaskey, hannesw diff -r da070553a8e1 -r 9833d3ceed5b nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java --- a/nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java Tue Apr 01 11:19:32 2014 +0200 +++ b/nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java Tue Apr 01 16:12:38 2014 +0200 @@ -86,6 +86,7 @@ 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 @@ * @author Attila Szegedi */ public class CallSiteDescriptorFactory { - private static final WeakHashMap> publicDescs = + private static final WeakHashMap> publicDescs = new WeakHashMap<>(); @@ -134,18 +135,27 @@ static CallSiteDescriptor getCanonicalPublicDescriptor(final CallSiteDescriptor desc) { synchronized(publicDescs) { - final WeakReference ref = publicDescs.get(desc); + final Reference 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 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") { diff -r da070553a8e1 -r 9833d3ceed5b nashorn/src/jdk/nashorn/internal/codegen/Attr.java --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Tue Apr 01 11:19:32 2014 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Tue Apr 01 16:12:38 2014 +0200 @@ -1413,7 +1413,7 @@ 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 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) { diff -r da070553a8e1 -r 9833d3ceed5b nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Apr 01 11:19:32 2014 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Apr 01 16:12:38 2014 +0200 @@ -1991,6 +1991,56 @@ return node instanceof LiteralNode && ((LiteralNode) node).isNull(); } + + private boolean undefinedCheck(final RuntimeNode runtimeNode, final List 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 args) { final Request request = runtimeNode.getRequest(); @@ -2078,7 +2128,7 @@ return false; } - assert args.size() == 2; + assert args.size() == 2 : node; final Type returnType = node.getType(); new OptimisticOperation() { @@ -2135,7 +2185,7 @@ * * TODO - remove this - Access Specializer will always know after Attr/Lower */ - final List args = runtimeNode.getArgs(); + final List args = new ArrayList<>(runtimeNode.getArgs()); if (runtimeNode.isPrimitive() && !runtimeNode.isFinal() && isReducible(runtimeNode.getRequest())) { final Expression lhs = args.get(0); @@ -2186,14 +2236,25 @@ 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 @@ 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); - - method.convert(runtimeNode.getType()); - method.store(runtimeNode.getSymbol()); + }.emit(newRuntimeNode); + + method.convert(newRuntimeNode.getType()); + method.store(newRuntimeNode.getSymbol()); return false; } diff -r da070553a8e1 -r 9833d3ceed5b nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java Tue Apr 01 11:19:32 2014 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java Tue Apr 01 16:12:38 2014 +0200 @@ -477,6 +477,20 @@ 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); } diff -r da070553a8e1 -r 9833d3ceed5b nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Tue Apr 01 11:19:32 2014 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Tue Apr 01 16:12:38 2014 +0200 @@ -30,6 +30,7 @@ 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; diff -r da070553a8e1 -r 9833d3ceed5b nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java --- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue Apr 01 11:19:32 2014 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue Apr 01 16:12:38 2014 +0200 @@ -28,7 +28,6 @@ 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.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 @@ 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 @@ 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; diff -r da070553a8e1 -r 9833d3ceed5b nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java --- a/nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java Tue Apr 01 11:19:32 2014 +0200 +++ b/nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java Tue Apr 01 16:12:38 2014 +0200 @@ -33,6 +33,7 @@ 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.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 @@ private final CompilationEnvironment env; private final Map> fnIdToNestedFunctions = new HashMap<>(); private final Map> externalSymbolDepths = new HashMap<>(); + private final Map> internalSymbols = new HashMap<>(); + + private final static DebugLogger LOG = new DebugLogger("scopedepths"); FindScopeDepths(final Compiler compiler) { super(new LexicalContext()); @@ -123,7 +128,7 @@ 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 iter = lc.getBlocks(block); Block globalBlock = null; while (iter.hasNext()) { @@ -174,7 +179,8 @@ allocatorMap, nestedFunctions, compiler.getSourceURL(), - externalSymbolDepths.get(fnId) + externalSymbolDepths.get(fnId), + internalSymbols.get(fnId) ); if (lc.getOutermostFunction() != newFunctionNode) { @@ -223,15 +229,15 @@ final Map 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 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 @@ } } + 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 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 depths = externalSymbolDepths.get(fnId); @@ -268,7 +286,6 @@ depths = new HashMap<>(); externalSymbolDepths.put(fnId, depths); } - //System.err.println("PUT " + functionNode.getName() + " " + symbol + " " +depthAtStart); depths.put(symbol.getName(), depthAtStart); } } diff -r da070553a8e1 -r 9833d3ceed5b nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Tue Apr 01 11:19:32 2014 +0200 +++ b/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Tue Apr 01 16:12:38 2014 +0200 @@ -29,11 +29,11 @@ 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 @@ 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; @@ -193,6 +195,17 @@ } /** + * 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? * * @param request a request @@ -300,6 +313,8 @@ case LT: case GE: case GT: + case IS_UNDEFINED: + case IS_NOT_UNDEFINED: return true; default: return false; @@ -404,6 +419,19 @@ } /** + * 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 @@ return Collections.unmodifiableList(args); } - private RuntimeNode setArgs(final List 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 args) { if (this.args == args) { return this; } diff -r da070553a8e1 -r 9833d3ceed5b nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java --- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Apr 01 11:19:32 2014 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Apr 01 16:12:38 2014 +0200 @@ -123,6 +123,8 @@ private final Map externalScopeDepths; + private final Set internalSymbols; + private static final int GET_SET_PREFIX_LENGTH = "*et ".length(); /** @@ -135,6 +137,7 @@ * @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 @@ final PropertyMap allocatorMap, final Map nestedFunctions, final String sourceURL, - final Map externalScopeDepths) { + final Map externalScopeDepths, + final Set internalSymbols) { super(functionName(functionNode), Math.min(functionNode.getParameters().size(), MAX_ARITY), @@ -161,8 +165,9 @@ 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; @@ -171,6 +176,19 @@ } /** + * 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 * @return the external symbol table with proto depths diff -r da070553a8e1 -r 9833d3ceed5b nashorn/test/script/basic/JDK-8038945.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8038945.js Tue Apr 01 16:12:38 2014 +0200 @@ -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"); + diff -r da070553a8e1 -r 9833d3ceed5b nashorn/test/script/basic/JDK-8038945.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8038945.js.EXPECTED Tue Apr 01 16:12:38 2014 +0200 @@ -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