8039044: Expand undefined intrinsics for all commutative combinators of scrict undefined checks
authorlagergren
Wed, 02 Apr 2014 10:52:39 +0200
changeset 24736 4e7eba3d014b
parent 24735 9833d3ceed5b
child 24737 4e15e10f771f
child 24738 be2026c9717c
8039044: Expand undefined intrinsics for all commutative combinators of scrict undefined checks Reviewed-by: jlaskey, hannesw
nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
nashorn/test/script/basic/JDK-8038945.js
nashorn/test/script/basic/JDK-8038945.js.EXPECTED
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Apr 01 16:12:38 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Apr 02 10:52:39 2014 +0200
@@ -74,6 +74,7 @@
 import java.util.RandomAccess;
 import java.util.Set;
 import java.util.TreeMap;
+
 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode;
@@ -2002,16 +2003,32 @@
         final Expression lhs = args.get(0);
         final Expression rhs = args.get(1);
 
-        if (!rhs.getSymbol().isScope()) {
+        final Symbol lhsSymbol = lhs.getSymbol();
+        final Symbol rhsSymbol = rhs.getSymbol();
+
+        final Symbol undefinedSymbol = "undefined".equals(lhsSymbol.getName()) ? lhsSymbol : rhsSymbol;
+        final Expression expr = undefinedSymbol == lhsSymbol ? rhs : lhs;
+
+        if (!undefinedSymbol.isScope()) {
             return false; //disallow undefined as local var or parameter
         }
 
+        if (lhsSymbol == undefinedSymbol && lhs.getType().isPrimitive()) {
+            //we load the undefined first. never mind, because this will deoptimize anyway
+            return false;
+        }
+
+        if (compiler.getCompilationEnvironment().isCompileRestOf()) {
+            return false;
+        }
+
         //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;
@@ -2019,11 +2036,11 @@
             data = data.getParent();
         }
 
-        load(lhs);
-        if (lhs.getType().isPrimitive()) {
+        load(expr);
+
+        if (expr.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");
@@ -2036,8 +2053,9 @@
             method.label(isUndefined);
             method.load(request == Request.IS_UNDEFINED);
             method.label(end);
-            method.store(runtimeNode.getSymbol());
         }
+
+        method.store(runtimeNode.getSymbol());
         return true;
     }
 
@@ -2139,7 +2157,6 @@
                 load(args.get(0));
                 load(args.get(1));
 
-
                 //if the request is a comparison, i.e. one that can be reversed
                 //it keeps its semantic, but make sure that the object comes in
                 //last
--- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Tue Apr 01 16:12:38 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Wed Apr 02 10:52:39 2014 +0200
@@ -85,7 +85,7 @@
     }
 
     private static Node createIsUndefined(final Expression parent, final Expression lhs, final Expression rhs, final Request request) {
-        if ("undefined".equals(rhs.getSymbol().getName())) {
+        if ("undefined".equals(lhs.getSymbol().getName()) || "undefined".equals(rhs.getSymbol().getName())) {
             return new RuntimeNode(parent, request, lhs, rhs);
         }
         return parent;
--- a/nashorn/test/script/basic/JDK-8038945.js	Tue Apr 01 16:12:38 2014 +0200
+++ b/nashorn/test/script/basic/JDK-8038945.js	Wed Apr 02 10:52:39 2014 +0200
@@ -135,3 +135,106 @@
 print("19: " + g4("17") + " === true");
 print("20: " + g5("17") + " === true");
 
+//h1 internals={} externals={undefined=0}
+function h1(x) {
+    return undefined === x;
+}
+
+//h2 internals={} externals=null
+function h2(x, undefined) {
+    return undefined === x;
+}
+
+//h3 internals={x=0} externals=null
+function h3(x) {
+    //h3$f3_2 internals={} externals={x=0}
+    function h3_2(undefined) {
+	return undefined === x;
+    }
+    return h3_2(17);
+}
+
+//h4 internals={x=0} externals=null
+function h4(x) {
+    //h4$h4_2 internals={} externals={x=0}
+    function h4_2() {
+	var undefined = 17;
+	return undefined === x;
+    }
+    return h4_2();
+}
+
+//h5 internals={x=0, undefined=0} externals=null
+function h5(x) {
+    var undefined = 17;
+    //h5$h5_2 internals={} externals={x=0, undefined=0}
+    function h5_2() {
+	return undefined === x;
+    }
+    return h5_2();
+}
+
+print("21: " + h1(17) + " === false");
+print("22: " + h2(17) + " === false");
+print("23: " + h3(17) + " === true");
+print("24: " + h4(17) + " === true");
+print("25: " + h5(17) + " === true");
+
+//recompile
+print("26: " + h1("17") + " === false");
+print("27: " + h2("17") + " === false");
+print("28: " + h3("17") + " === false");
+print("29: " + h4("17") + " === false");
+print("30: " + h5("17") + " === false");
+
+//i1 internals={} externals={undefined=0}
+function i1(x) {
+    return undefined !== x;
+}
+
+//i2 internals={} externals=null
+function i2(x, undefined) {
+    return undefined !== x;
+}
+
+//i3 internals={x=0} externals=null
+function i3(x) {
+    //i3$f3_2 internals={} externals={x=0}
+    function i3_2(undefined) {
+	return undefined !== x;
+    }
+    return i3_2(17);
+}
+
+//i4 internals={x=0} externals=null
+function i4(x) {
+    //i4$i4_2 internals={} externals={x=0}
+    function i4_2() {
+	var undefined = 17;
+	return undefined !== x;
+    }
+    return i4_2();
+}
+
+//h5 internals={x=0, undefined=0} externals=null
+function i5(x) {
+    var undefined = 17;
+    //i5$i5_2 internals={} externals={x=0, undefined=0}
+    function i5_2() {
+	return undefined !== x;
+    }
+    return i5_2();
+}
+
+print("31: " + i1(17) + " === true");
+print("32: " + i2(17) + " === true");
+print("33: " + i3(17) + " === false");
+print("34: " + i4(17) + " === false");
+print("35: " + i5(17) + " === false");
+
+//recompile
+print("36: " + i1("17") + " === true");
+print("37: " + i2("17") + " === true");
+print("38: " + i3("17") + " === true");
+print("39: " + i4("17") + " === true");
+print("40: " + i5("17") + " === true");
--- a/nashorn/test/script/basic/JDK-8038945.js.EXPECTED	Tue Apr 01 16:12:38 2014 +0200
+++ b/nashorn/test/script/basic/JDK-8038945.js.EXPECTED	Wed Apr 02 10:52:39 2014 +0200
@@ -18,3 +18,23 @@
 18: true === true
 19: true === true
 20: true === true
+21: false === false
+22: false === false
+23: true === true
+24: true === true
+25: true === true
+26: false === false
+27: false === false
+28: false === false
+29: false === false
+30: false === false
+31: true === true
+32: true === true
+33: false === false
+34: false === false
+35: false === false
+36: true === true
+37: true === true
+38: true === true
+39: true === true
+40: true === true