Title: [230143] trunk
Revision
230143
Author
fpi...@apple.com
Date
2018-04-01 10:08:39 -0700 (Sun, 01 Apr 2018)

Log Message

JSC crash in JIT code with for-of loop and Array/Set iterators
https://bugs.webkit.org/show_bug.cgi?id=183174

Reviewed by Saam Barati.

JSTests:

* microbenchmarks/hoist-get-by-offset-tower-with-inferred-types.js: Added. This test shows that fixing the bug didn't break hoisting of GetByOffset with inferred types. I confirmed that if I did break it, this test slows down by >7x.
(foo):
* stress/hoist-get-by-offset-with-control-dependent-inferred-type.js: Added. This test shows that the bug is fixed.
(f):

Source/_javascript_Core:

* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute): Fix the bug by making GetByOffset and friends verify that they are getting the type proof they want at the desired hoisting site.

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (230142 => 230143)


--- trunk/JSTests/ChangeLog	2018-04-01 16:47:59 UTC (rev 230142)
+++ trunk/JSTests/ChangeLog	2018-04-01 17:08:39 UTC (rev 230143)
@@ -1,3 +1,15 @@
+2018-03-31  Filip Pizlo  <fpi...@apple.com>
+
+        JSC crash in JIT code with for-of loop and Array/Set iterators
+        https://bugs.webkit.org/show_bug.cgi?id=183174
+
+        Reviewed by Saam Barati.
+
+        * microbenchmarks/hoist-get-by-offset-tower-with-inferred-types.js: Added. This test shows that fixing the bug didn't break hoisting of GetByOffset with inferred types. I confirmed that if I did break it, this test slows down by >7x.
+        (foo):
+        * stress/hoist-get-by-offset-with-control-dependent-inferred-type.js: Added. This test shows that the bug is fixed.
+        (f):
+
 2018-03-30  JF Bastien  <jfbast...@apple.com>
 
         WebAssembly: support DataView compilation

Added: trunk/JSTests/microbenchmarks/hoist-get-by-offset-tower-with-inferred-types.js (0 => 230143)


--- trunk/JSTests/microbenchmarks/hoist-get-by-offset-tower-with-inferred-types.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/hoist-get-by-offset-tower-with-inferred-types.js	2018-04-01 17:08:39 UTC (rev 230143)
@@ -0,0 +1,19 @@
+function foo(o)
+{
+    var result = 0;
+    for (var i = 0; i < 100; ++i)
+        result += o.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z;
+    return result;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 1000; ++i) {
+    var o = {f:{g:{h:{i:{j:{k:{l:{m:{n:{o:{p:{q:{r:{s:{t:{u:{v:{w:{x:{y:{z:42}}}}}}}}}}}}}}}}}}}}};
+    for (var j = 0; j < 100; ++j) {
+        var result = foo(o);
+        if (result != 4200)
+            throw "Bad result in loop: " + result;
+    }
+}
+

Added: trunk/JSTests/stress/hoist-get-by-offset-with-control-dependent-inferred-type.js (0 => 230143)


--- trunk/JSTests/stress/hoist-get-by-offset-with-control-dependent-inferred-type.js	                        (rev 0)
+++ trunk/JSTests/stress/hoist-get-by-offset-with-control-dependent-inferred-type.js	2018-04-01 17:08:39 UTC (rev 230143)
@@ -0,0 +1,14 @@
+function f() {
+    var a = Array(100).fill(0);
+    var ta = new Set(a.map((v,k)=>k));
+    var xs = [a, ta];
+    var q = 0;
+    var t = Date.now();
+    for (var i = 0; i < 100000; ++i) {
+        for (var x of xs[i&1]) q+=x;
+    }
+    return [Date.now()-t,q];
+}
+noInline(f);
+f();
+

Modified: trunk/Source/_javascript_Core/ChangeLog (230142 => 230143)


--- trunk/Source/_javascript_Core/ChangeLog	2018-04-01 16:47:59 UTC (rev 230142)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-04-01 17:08:39 UTC (rev 230143)
@@ -1,3 +1,13 @@
+2018-03-31  Filip Pizlo  <fpi...@apple.com>
+
+        JSC crash in JIT code with for-of loop and Array/Set iterators
+        https://bugs.webkit.org/show_bug.cgi?id=183174
+
+        Reviewed by Saam Barati.
+
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute): Fix the bug by making GetByOffset and friends verify that they are getting the type proof they want at the desired hoisting site.
+
 2018-03-30  Filip Pizlo  <fpi...@apple.com>
 
         Strings and Vectors shouldn't do index masking

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (230142 => 230143)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-04-01 16:47:59 UTC (rev 230142)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-04-01 17:08:39 UTC (rev 230143)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -504,9 +504,33 @@
     case GetByOffset:
     case GetGetterSetterByOffset:
     case PutByOffset: {
-        PropertyOffset offset = node->storageAccessData().offset;
+        StorageAccessData& data = ""
+        PropertyOffset offset = data.offset;
+        UniquedStringImpl* uid = graph.identifiers()[data.identifierNumber];
 
-        if (state.structureClobberState() == StructuresAreWatched) {
+        InferredType::Descriptor inferredType;
+        switch (node->op()) {
+        case GetByOffset:
+        case GetGetterSetterByOffset:
+            inferredType = data.inferredType;
+            break;
+        case PutByOffset:
+            // PutByOffset knows about inferred types because it's the enforcer of that type rather
+            // than the consumer of that type. Therefore, PutByOffset expects TOP for the purpose of
+            // safe-to-execute in the sense that it will be happy with anything as general as TOP
+            // (so any type).
+            inferredType = InferredType::Top;
+            break;
+        default:
+            DFG_CRASH(graph, node, "Bad opcode");
+            break;
+        }
+
+        // Graph::isSafeToLoad() is all about proofs derived from PropertyConditions. Those don't
+        // know anything about inferred types. But if we have a proof derived from watching a
+        // structure that has a type proof, then the next case below will deal with it.
+        if (state.structureClobberState() == StructuresAreWatched
+            && inferredType.kind() == InferredType::Top) {
             if (JSObject* knownBase = node->child1()->dynamicCastConstant<JSObject*>(graph.m_vm)) {
                 if (graph.isSafeToLoad(knownBase, offset))
                     return true;
@@ -517,8 +541,15 @@
         if (value.isInfinite())
             return false;
         for (unsigned i = value.size(); i--;) {
-            if (!value[i]->isValidOffset(offset))
+            Structure* thisStructure = value[i].get();
+            if (!thisStructure->isValidOffset(offset))
                 return false;
+            if (inferredType.kind() != InferredType::Top) {
+                InferredType::Descriptor thisInferredType =
+                    graph.inferredTypeForProperty(thisStructure, uid);
+                if (!inferredType.subsumes(thisInferredType))
+                    return false;
+            }
         }
         return true;
     }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to