Title: [225342] trunk
Revision
225342
Author
[email protected]
Date
2017-11-30 12:48:53 -0800 (Thu, 30 Nov 2017)

Log Message

[DFG][FTL] operationHasIndexedProperty does not consider negative int32_t
https://bugs.webkit.org/show_bug.cgi?id=180190

Reviewed by Mark Lam.

JSTests:

* stress/operation-in-may-have-negative-int32-array-storage.js: Added.
(shouldBe):
(test1):
* stress/operation-in-may-have-negative-int32-contiguous-array.js: Added.
(shouldBe):
(test1):
* stress/operation-in-may-have-negative-int32-double-array.js: Added.
(shouldBe):
(test1):
* stress/operation-in-may-have-negative-int32-generic-array.js: Added.
(shouldBe):
(test1):
* stress/operation-in-may-have-negative-int32-int32-array.js: Added.
(shouldBe):
(test1):
* stress/operation-in-may-have-negative-int32.js: Added.
(shouldBe):
(test2):
* stress/operation-in-negative-int32-cast.js: Added.
(shouldBe):
(test1):

Source/_javascript_Core:

If DFG HasIndexedProperty node observes negative index, it goes to a slow
path by calling operationHasIndexedProperty. The problem is that
operationHasIndexedProperty does not account negative index. Negative index
was used as uint32 array index.

In this patch we add a path for negative index in operationHasIndexedProperty.
And rename it to operationHasIndexedPropertyByInt to make intension clear.
We also move operationHasIndexedPropertyByInt from JITOperations to DFGOperations
since it is only used in DFG and FTL.

While fixing this bug, we found that our op_in does not record OutOfBound feedback.
This causes repeated OSR exit and significantly regresses the performance. We opened
a bug to track this issue[1].

[1]: https://bugs.webkit.org/show_bug.cgi?id=180192

* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileHasIndexedProperty):
* jit/JITOperations.cpp:
* jit/JITOperations.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (225341 => 225342)


--- trunk/JSTests/ChangeLog	2017-11-30 20:40:04 UTC (rev 225341)
+++ trunk/JSTests/ChangeLog	2017-11-30 20:48:53 UTC (rev 225342)
@@ -1,3 +1,32 @@
+2017-11-30  Yusuke Suzuki  <[email protected]>
+
+        [DFG][FTL] operationHasIndexedProperty does not consider negative int32_t
+        https://bugs.webkit.org/show_bug.cgi?id=180190
+
+        Reviewed by Mark Lam.
+
+        * stress/operation-in-may-have-negative-int32-array-storage.js: Added.
+        (shouldBe):
+        (test1):
+        * stress/operation-in-may-have-negative-int32-contiguous-array.js: Added.
+        (shouldBe):
+        (test1):
+        * stress/operation-in-may-have-negative-int32-double-array.js: Added.
+        (shouldBe):
+        (test1):
+        * stress/operation-in-may-have-negative-int32-generic-array.js: Added.
+        (shouldBe):
+        (test1):
+        * stress/operation-in-may-have-negative-int32-int32-array.js: Added.
+        (shouldBe):
+        (test1):
+        * stress/operation-in-may-have-negative-int32.js: Added.
+        (shouldBe):
+        (test2):
+        * stress/operation-in-negative-int32-cast.js: Added.
+        (shouldBe):
+        (test1):
+
 2017-11-28  JF Bastien  <[email protected]>
 
         Strict and sloppy functions shouldn't share structure

Added: trunk/JSTests/stress/operation-in-may-have-negative-int32-array-storage.js (0 => 225342)


--- trunk/JSTests/stress/operation-in-may-have-negative-int32-array-storage.js	                        (rev 0)
+++ trunk/JSTests/stress/operation-in-may-have-negative-int32-array-storage.js	2017-11-30 20:48:53 UTC (rev 225342)
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var k = -1;
+var o1 = [20];
+o1[k] = 42;
+ensureArrayStorage(o1);
+
+function test1(o)
+{
+    return k in o;
+}
+noInline(test1);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test1(o1), true);

Added: trunk/JSTests/stress/operation-in-may-have-negative-int32-contiguous-array.js (0 => 225342)


--- trunk/JSTests/stress/operation-in-may-have-negative-int32-contiguous-array.js	                        (rev 0)
+++ trunk/JSTests/stress/operation-in-may-have-negative-int32-contiguous-array.js	2017-11-30 20:48:53 UTC (rev 225342)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var k = -1;
+var o1 = ["Cocoa"];
+o1[k] = 42;
+
+function test1(o)
+{
+    return k in o;
+}
+noInline(test1);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test1(o1), true);

Added: trunk/JSTests/stress/operation-in-may-have-negative-int32-double-array.js (0 => 225342)


--- trunk/JSTests/stress/operation-in-may-have-negative-int32-double-array.js	                        (rev 0)
+++ trunk/JSTests/stress/operation-in-may-have-negative-int32-double-array.js	2017-11-30 20:48:53 UTC (rev 225342)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var k = -1;
+var o1 = [42.5];
+o1[k] = 300.2;
+
+function test1(o)
+{
+    return k in o;
+}
+noInline(test1);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test1(o1), true);

Added: trunk/JSTests/stress/operation-in-may-have-negative-int32-generic-array.js (0 => 225342)


--- trunk/JSTests/stress/operation-in-may-have-negative-int32-generic-array.js	                        (rev 0)
+++ trunk/JSTests/stress/operation-in-may-have-negative-int32-generic-array.js	2017-11-30 20:48:53 UTC (rev 225342)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var k = -1;
+var o1 = [];
+o1[k] = 42;
+
+function test1(o)
+{
+    return k in o;
+}
+noInline(test1);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test1(o1), true);

Added: trunk/JSTests/stress/operation-in-may-have-negative-int32-int32-array.js (0 => 225342)


--- trunk/JSTests/stress/operation-in-may-have-negative-int32-int32-array.js	                        (rev 0)
+++ trunk/JSTests/stress/operation-in-may-have-negative-int32-int32-array.js	2017-11-30 20:48:53 UTC (rev 225342)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var k = -1;
+var o1 = [20];
+o1[k] = 42;
+
+function test1(o)
+{
+    return k in o;
+}
+noInline(test1);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test1(o1), true);

Added: trunk/JSTests/stress/operation-in-may-have-negative-int32.js (0 => 225342)


--- trunk/JSTests/stress/operation-in-may-have-negative-int32.js	                        (rev 0)
+++ trunk/JSTests/stress/operation-in-may-have-negative-int32.js	2017-11-30 20:48:53 UTC (rev 225342)
@@ -0,0 +1,32 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var k = -1;
+var o1 = {};
+o1[k] = true;
+var o2 = {};
+
+function test1(o)
+{
+    return k in o;
+}
+noInline(test1);
+
+function test2(o)
+{
+    return k in o;
+}
+noInline(test2);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test1(o1), true);
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test1(o2), false);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test2(o2), false);
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test2(o1), true);

Added: trunk/JSTests/stress/operation-in-negative-int32-cast.js (0 => 225342)


--- trunk/JSTests/stress/operation-in-negative-int32-cast.js	                        (rev 0)
+++ trunk/JSTests/stress/operation-in-negative-int32-cast.js	2017-11-30 20:48:53 UTC (rev 225342)
@@ -0,0 +1,20 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var INT32_MIN = -2147483648;
+var INT32_MIN_IN_UINT32 = 0x80000000;
+var o1 = [];
+o1[INT32_MIN_IN_UINT32] = true;
+ensureArrayStorage(o1);
+
+function test1(o, key)
+{
+    return key in o;
+}
+noInline(test1);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(test1(o1, INT32_MIN), false);

Modified: trunk/Source/_javascript_Core/ChangeLog (225341 => 225342)


--- trunk/Source/_javascript_Core/ChangeLog	2017-11-30 20:40:04 UTC (rev 225341)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-11-30 20:48:53 UTC (rev 225342)
@@ -1,3 +1,37 @@
+2017-11-30  Yusuke Suzuki  <[email protected]>
+
+        [DFG][FTL] operationHasIndexedProperty does not consider negative int32_t
+        https://bugs.webkit.org/show_bug.cgi?id=180190
+
+        Reviewed by Mark Lam.
+
+        If DFG HasIndexedProperty node observes negative index, it goes to a slow
+        path by calling operationHasIndexedProperty. The problem is that
+        operationHasIndexedProperty does not account negative index. Negative index
+        was used as uint32 array index.
+
+        In this patch we add a path for negative index in operationHasIndexedProperty.
+        And rename it to operationHasIndexedPropertyByInt to make intension clear.
+        We also move operationHasIndexedPropertyByInt from JITOperations to DFGOperations
+        since it is only used in DFG and FTL.
+
+        While fixing this bug, we found that our op_in does not record OutOfBound feedback.
+        This causes repeated OSR exit and significantly regresses the performance. We opened
+        a bug to track this issue[1].
+
+        [1]: https://bugs.webkit.org/show_bug.cgi?id=180192
+
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileHasIndexedProperty):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+
 2017-11-30  Michael Saboff  <[email protected]>
 
         Allow JSC command line tool to accept UTF8

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (225341 => 225342)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2017-11-30 20:40:04 UTC (rev 225341)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2017-11-30 20:48:53 UTC (rev 225342)
@@ -634,7 +634,7 @@
     NativeCallFrameTracer tracer(vm, exec);
     
     if (index < 0) {
-        // Go the slowest way possible becase negative indices don't use indexed storage.
+        // Go the slowest way possible because negative indices don't use indexed storage.
         return JSValue::encode(JSValue(base).get(exec, Identifier::from(exec, index)));
     }
 
@@ -1808,6 +1808,18 @@
     return reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm));
 }
 
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyByInt(ExecState* exec, JSCell* baseCell, int32_t subscript, int32_t internalMethodType)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    JSObject* object = baseCell->toObject(exec, exec->lexicalGlobalObject());
+    if (UNLIKELY(subscript < 0)) {
+        // Go the slowest way possible because negative indices don't use indexed storage.
+        return JSValue::encode(jsBoolean(object->hasPropertyGeneric(exec, Identifier::from(exec, subscript), static_cast<PropertySlot::InternalMethodType>(internalMethodType))));
+    }
+    return JSValue::encode(jsBoolean(object->hasPropertyGeneric(exec, subscript, static_cast<PropertySlot::InternalMethodType>(internalMethodType))));
+}
+
 StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string)
 {
     VM& vm = exec->vm();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (225341 => 225342)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2017-11-30 20:40:04 UTC (rev 225341)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2017-11-30 20:48:53 UTC (rev 225342)
@@ -80,6 +80,7 @@
 EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetPrototypeOf(ExecState*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(ExecState*, JSObject*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyByInt(ExecState*, JSCell*, int32_t, int32_t);
 char* JIT_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL;
 char* JIT_OPERATION operationNewArrayBuffer(ExecState*, Structure*, size_t, size_t) WTF_INTERNAL;
 char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (225341 => 225342)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-11-30 20:40:04 UTC (rev 225341)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-11-30 20:48:53 UTC (rev 225342)
@@ -5271,7 +5271,7 @@
         moveTrueTo(resultPayloadGPR);
         MacroAssembler::Jump done = m_jit.jump();
 
-        addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedProperty, JSValueRegs(resultTagGPR, resultPayloadGPR), baseGPR, indexGPR, static_cast<int32_t>(node->internalMethodType())));
+        addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedPropertyByInt, JSValueRegs(resultTagGPR, resultPayloadGPR), baseGPR, indexGPR, static_cast<int32_t>(node->internalMethodType())));
         
         done.link(&m_jit);
         booleanResult(resultPayloadGPR, node);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (225341 => 225342)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-11-30 20:40:04 UTC (rev 225341)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-11-30 20:48:53 UTC (rev 225342)
@@ -5733,7 +5733,7 @@
         }
         }
 
-        addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedProperty, resultGPR, baseGPR, indexGPR, static_cast<int32_t>(node->internalMethodType())));
+        addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedPropertyByInt, resultGPR, baseGPR, indexGPR, static_cast<int32_t>(node->internalMethodType())));
         
         jsValueResult(resultGPR, node, DataFormatJSBoolean);
         break;

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (225341 => 225342)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-11-30 20:40:04 UTC (rev 225341)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-11-30 20:48:53 UTC (rev 225342)
@@ -9428,7 +9428,7 @@
             m_out.appendTo(slowCase, continuation);
             ValueFromBlock slowResult = m_out.anchor(m_out.equal(
                 m_out.constInt64(JSValue::encode(jsBoolean(true))), 
-                vmCall(Int64, m_out.operation(operationHasIndexedProperty), m_callFrame, base, index, internalMethodType)));
+                vmCall(Int64, m_out.operation(operationHasIndexedPropertyByInt), m_callFrame, base, index, internalMethodType)));
             m_out.jump(continuation);
 
             m_out.appendTo(continuation, lastNext);
@@ -9464,7 +9464,7 @@
             m_out.appendTo(slowCase, continuation);
             ValueFromBlock slowResult = m_out.anchor(m_out.equal(
                 m_out.constInt64(JSValue::encode(jsBoolean(true))), 
-                vmCall(Int64, m_out.operation(operationHasIndexedProperty), m_callFrame, base, index, internalMethodType)));
+                vmCall(Int64, m_out.operation(operationHasIndexedPropertyByInt), m_callFrame, base, index, internalMethodType)));
             m_out.jump(continuation);
             
             m_out.appendTo(continuation, lastNext);

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (225341 => 225342)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2017-11-30 20:40:04 UTC (rev 225341)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2017-11-30 20:48:53 UTC (rev 225342)
@@ -2398,14 +2398,6 @@
     return JSValue::encode(jsBoolean(base->hasPropertyGeneric(exec, asString(propertyName)->toIdentifier(exec), PropertySlot::InternalMethodType::GetOwnProperty)));
 }
 
-EncodedJSValue JIT_OPERATION operationHasIndexedProperty(ExecState* exec, JSCell* baseCell, int32_t subscript, int32_t internalMethodType)
-{
-    VM& vm = exec->vm();
-    NativeCallFrameTracer tracer(&vm, exec);
-    JSObject* object = baseCell->toObject(exec, exec->lexicalGlobalObject());
-    return JSValue::encode(jsBoolean(object->hasPropertyGeneric(exec, subscript, static_cast<PropertySlot::InternalMethodType>(internalMethodType))));
-}
-    
 JSCell* JIT_OPERATION operationGetPropertyEnumerator(ExecState* exec, JSCell* cell)
 {
     VM& vm = exec->vm();

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (225341 => 225342)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2017-11-30 20:40:04 UTC (rev 225341)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2017-11-30 20:48:53 UTC (rev 225342)
@@ -461,7 +461,6 @@
 int32_t JIT_OPERATION operationInstanceOfCustom(ExecState*, EncodedJSValue encodedValue, JSObject* constructor, EncodedJSValue encodedHasInstance) WTF_INTERNAL;
 
 EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState*, EncodedJSValue, JSCell*);
-EncodedJSValue JIT_OPERATION operationHasIndexedProperty(ExecState*, JSCell*, int32_t, int32_t);
 JSCell* JIT_OPERATION operationGetPropertyEnumerator(ExecState*, JSCell*);
 EncodedJSValue JIT_OPERATION operationNextEnumeratorPname(ExecState*, JSCell*, int32_t);
 JSCell* JIT_OPERATION operationToIndexString(ExecState*, int32_t);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to