Title: [225154] trunk
Revision
225154
Author
[email protected]
Date
2017-11-26 23:51:16 -0800 (Sun, 26 Nov 2017)

Log Message

[DFG] Add NormalizeMapKey DFG IR
https://bugs.webkit.org/show_bug.cgi?id=179912

Reviewed by Saam Barati.

JSTests:

* stress/map-untyped-normalize-cse.js: Added.
(shouldBe):
(test):
* stress/map-untyped-normalize.js: Added.
(shouldBe):
(test):
* stress/set-untyped-normalize-cse.js: Added.
(shouldBe):
(set return.set has.set has):
* stress/set-untyped-normalize.js: Added.
(shouldBe):
(set return.set has):

Source/_javascript_Core:

This patch introduces NormalizeMapKey DFG node. It executes what normalizeMapKey does in inlined manner.
By separating this from MapHash and Map/Set related operations, we can perform CSE onto that, and we
do not need to call normalizeMapKey conservatively in DFG operations.
This can reduce slow path case in Untyped GetMapBucket since we can normalize keys in DFG/FTL.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupNormalizeMapKey):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileNormalizeMapKey):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileMapHash):
(JSC::FTL::DFG::LowerDFGToB3::compileNormalizeMapKey):
(JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucket):
* runtime/HashMapImpl.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (225153 => 225154)


--- trunk/JSTests/ChangeLog	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/JSTests/ChangeLog	2017-11-27 07:51:16 UTC (rev 225154)
@@ -1,3 +1,23 @@
+2017-11-21  Yusuke Suzuki  <[email protected]>
+
+        [DFG] Add NormalizeMapKey DFG IR
+        https://bugs.webkit.org/show_bug.cgi?id=179912
+
+        Reviewed by Saam Barati.
+
+        * stress/map-untyped-normalize-cse.js: Added.
+        (shouldBe):
+        (test):
+        * stress/map-untyped-normalize.js: Added.
+        (shouldBe):
+        (test):
+        * stress/set-untyped-normalize-cse.js: Added.
+        (shouldBe):
+        (set return.set has.set has):
+        * stress/set-untyped-normalize.js: Added.
+        (shouldBe):
+        (set return.set has):
+
 2017-11-26  Yusuke Suzuki  <[email protected]>
 
         [FTL] Support DeleteById and DeleteByVal

Added: trunk/JSTests/stress/map-untyped-normalize-cse.js (0 => 225154)


--- trunk/JSTests/stress/map-untyped-normalize-cse.js	                        (rev 0)
+++ trunk/JSTests/stress/map-untyped-normalize-cse.js	2017-11-27 07:51:16 UTC (rev 225154)
@@ -0,0 +1,46 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var keys = [
+    "Cappuccino",
+    -0.0,
+    Symbol("Cocoa"),
+    42,
+    -42,
+    null,
+    undefined,
+    420.5,
+    0xffffffff,
+    0x80000000,
+    -1,
+    -2147483648,
+    {},
+    [],
+    false,
+    true,
+    NaN,
+];
+
+let i = 0;
+let map = new Map();
+for (let key of keys)
+    map.set(key, i++);
+
+function test(map, key)
+{
+    return map.get(key) + map.get(key);
+}
+noInline(test);
+
+for (let i = 0; i < 1e4; ++i) {
+    let j = 0;
+    for (let key of keys) {
+        let result = j + j;
+        j++
+        shouldBe(test(map, key), result);
+    }
+}
+shouldBe(test(map, 0.0), 2);

Added: trunk/JSTests/stress/map-untyped-normalize.js (0 => 225154)


--- trunk/JSTests/stress/map-untyped-normalize.js	                        (rev 0)
+++ trunk/JSTests/stress/map-untyped-normalize.js	2017-11-27 07:51:16 UTC (rev 225154)
@@ -0,0 +1,44 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var keys = [
+    "Cappuccino",
+    -0.0,
+    Symbol("Cocoa"),
+    42,
+    -42,
+    null,
+    undefined,
+    420.5,
+    0xffffffff,
+    0x80000000,
+    -1,
+    -2147483648,
+    {},
+    [],
+    false,
+    true,
+    NaN,
+];
+
+let i = 0;
+let map = new Map();
+for (let key of keys)
+    map.set(key, i++);
+
+function test(map, key)
+{
+    return map.get(key);
+}
+noInline(test);
+
+for (let i = 0; i < 1e4; ++i) {
+    let j = 0;
+    for (let key of keys) {
+        shouldBe(test(map, key), j++);
+    }
+}
+shouldBe(test(map, 0.0), 1);

Added: trunk/JSTests/stress/normalize-map-key-constant-folding.js (0 => 225154)


--- trunk/JSTests/stress/normalize-map-key-constant-folding.js	                        (rev 0)
+++ trunk/JSTests/stress/normalize-map-key-constant-folding.js	2017-11-27 07:51:16 UTC (rev 225154)
@@ -0,0 +1,13 @@
+function test(i)
+{
+    var map = new Map();
+    var key = "Hello";
+    if (i & 0x1)
+        key = 42;
+    map.set(key, 42);
+    return map;
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i)
+    test(i);

Added: trunk/JSTests/stress/set-untyped-normalize-cse.js (0 => 225154)


--- trunk/JSTests/stress/set-untyped-normalize-cse.js	                        (rev 0)
+++ trunk/JSTests/stress/set-untyped-normalize-cse.js	2017-11-27 07:51:16 UTC (rev 225154)
@@ -0,0 +1,44 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var keys = [
+    "Cappuccino",
+    -0.0,
+    Symbol("Cocoa"),
+    42,
+    -42,
+    null,
+    undefined,
+    420.5,
+    0xffffffff,
+    0x80000000,
+    -1,
+    -2147483648,
+    {},
+    [],
+    false,
+    true,
+    NaN,
+];
+
+let i = 0;
+let set = new Set();
+for (let key of keys)
+    set.add(key);
+
+function test(set, key)
+{
+    return set.has(key) + set.has(key);
+}
+noInline(test);
+
+for (let i = 0; i < 1e4; ++i) {
+    let j = 0;
+    for (let key of keys) {
+        shouldBe(test(set, key), 2);
+    }
+}
+shouldBe(test(set, 0.0), 2);

Added: trunk/JSTests/stress/set-untyped-normalize.js (0 => 225154)


--- trunk/JSTests/stress/set-untyped-normalize.js	                        (rev 0)
+++ trunk/JSTests/stress/set-untyped-normalize.js	2017-11-27 07:51:16 UTC (rev 225154)
@@ -0,0 +1,44 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var keys = [
+    "Cappuccino",
+    -0.0,
+    Symbol("Cocoa"),
+    42,
+    -42,
+    null,
+    undefined,
+    420.5,
+    0xffffffff,
+    0x80000000,
+    -1,
+    -2147483648,
+    {},
+    [],
+    false,
+    true,
+    NaN,
+];
+
+let i = 0;
+let set = new Set();
+for (let key of keys)
+    set.add(key);
+
+function test(set, key)
+{
+    return set.has(key);
+}
+noInline(test);
+
+for (let i = 0; i < 1e4; ++i) {
+    let j = 0;
+    for (let key of keys) {
+        shouldBe(test(set, key), true);
+    }
+}
+shouldBe(test(set, 0.0), true);

Modified: trunk/Source/_javascript_Core/ChangeLog (225153 => 225154)


--- trunk/Source/_javascript_Core/ChangeLog	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-11-27 07:51:16 UTC (rev 225154)
@@ -1,3 +1,47 @@
+2017-11-21  Yusuke Suzuki  <[email protected]>
+
+        [DFG] Add NormalizeMapKey DFG IR
+        https://bugs.webkit.org/show_bug.cgi?id=179912
+
+        Reviewed by Saam Barati.
+
+        This patch introduces NormalizeMapKey DFG node. It executes what normalizeMapKey does in inlined manner.
+        By separating this from MapHash and Map/Set related operations, we can perform CSE onto that, and we
+        do not need to call normalizeMapKey conservatively in DFG operations.
+        This can reduce slow path case in Untyped GetMapBucket since we can normalize keys in DFG/FTL.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixupNormalizeMapKey):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileNormalizeMapKey):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileMapHash):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNormalizeMapKey):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucket):
+        * runtime/HashMapImpl.h:
+
 2017-11-26  Yusuke Suzuki  <[email protected]>
 
         [FTL] Support DeleteById and DeleteByVal

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2017-11-27 07:51:16 UTC (rev 225154)
@@ -1099,6 +1099,23 @@
         break;
     }
 
+    case NormalizeMapKey: {
+        if (JSValue key = forNode(node->child1()).value()) {
+            setConstant(node, *m_graph.freeze(normalizeMapKey(key)));
+            break;
+        }
+
+        SpeculatedType typeMaybeNormalized = (SpecFullNumber & ~SpecInt32Only);
+        if (!(forNode(node->child1()).m_type & typeMaybeNormalized)) {
+            m_state.setFoundConstants(true);
+            forNode(node) = forNode(node->child1());
+            break;
+        }
+
+        forNode(node).makeHeapTop();
+        break;
+    }
+
     case StringSlice: {
         forNode(node).setType(m_graph, SpecString);
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -2873,8 +2873,9 @@
         insertChecks();
         Node* map = get(virtualRegisterForArgument(0, registerOffset));
         Node* key = get(virtualRegisterForArgument(1, registerOffset));
-        Node* hash = addToGraph(MapHash, key);
-        Node* bucket = addToGraph(GetMapBucket, Edge(map, MapObjectUse), Edge(key), Edge(hash));
+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
+        Node* bucket = addToGraph(GetMapBucket, Edge(map, MapObjectUse), Edge(normalizedKey), Edge(hash));
         Node* result = addToGraph(LoadValueFromMapBucket, OpInfo(BucketOwnerType::Map), OpInfo(prediction), bucket);
         set(VirtualRegister(resultOperand), result);
         return true;
@@ -2888,9 +2889,10 @@
         insertChecks();
         Node* mapOrSet = get(virtualRegisterForArgument(0, registerOffset));
         Node* key = get(virtualRegisterForArgument(1, registerOffset));
-        Node* hash = addToGraph(MapHash, key);
+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
         UseKind useKind = intrinsic == JSSetHasIntrinsic ? SetObjectUse : MapObjectUse;
-        Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(key), Edge(hash));
+        Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(normalizedKey), Edge(hash));
         JSCell* sentinel = nullptr;
         if (intrinsic == JSMapHasIntrinsic)
             sentinel = m_vm->sentinelMapBucket.get();
@@ -2911,8 +2913,9 @@
         insertChecks();
         Node* base = get(virtualRegisterForArgument(0, registerOffset));
         Node* key = get(virtualRegisterForArgument(1, registerOffset));
-        Node* hash = addToGraph(MapHash, key);
-        addToGraph(SetAdd, base, key, hash);
+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
+        addToGraph(SetAdd, base, normalizedKey, hash);
         set(VirtualRegister(resultOperand), base);
         return true;
     }
@@ -2925,10 +2928,12 @@
         Node* base = get(virtualRegisterForArgument(0, registerOffset));
         Node* key = get(virtualRegisterForArgument(1, registerOffset));
         Node* value = get(virtualRegisterForArgument(2, registerOffset));
-        Node* hash = addToGraph(MapHash, key);
 
+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
+
         addVarArgChild(base);
-        addVarArgChild(key);
+        addVarArgChild(normalizedKey);
         addVarArgChild(value);
         addVarArgChild(hash);
         addToGraph(Node::VarArg, MapSet, OpInfo(0), OpInfo(0));
@@ -2992,8 +2997,9 @@
         insertChecks();
         Node* map = get(virtualRegisterForArgument(0, registerOffset));
         Node* key = get(virtualRegisterForArgument(1, registerOffset));
-        Node* hash = addToGraph(MapHash, key);
-        Node* result = addToGraph(WeakMapGet, OpInfo(), OpInfo(prediction), map, key, hash);
+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
+        Node* result = addToGraph(WeakMapGet, OpInfo(), OpInfo(prediction), map, normalizedKey, hash);
         set(VirtualRegister(resultOperand), result);
         return true;
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2017-11-27 07:51:16 UTC (rev 225154)
@@ -1591,6 +1591,10 @@
         def(PureValue(node));
         return;
 
+    case NormalizeMapKey:
+        def(PureValue(node));
+        return;
+
     case GetMapBucket: {
         Edge& mapEdge = node->child1();
         Edge& keyEdge = node->child2();

Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -635,6 +635,16 @@
                 break;
             }
 
+            case NormalizeMapKey: {
+                SpeculatedType typeMaybeNormalized = (SpecFullNumber & ~SpecInt32Only);
+                if (m_state.forNode(node->child1()).m_type & typeMaybeNormalized)
+                    break;
+
+                node->convertToIdentity();
+                changed = true;
+                break;
+            }
+
             case ParseInt: {
                 AbstractValue& value = m_state.forNode(node->child1());
                 if (!value.m_type || (value.m_type & ~SpecInt32Only))

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -203,6 +203,7 @@
     case CheckTraps:
     case StringFromCharCode:
     case MapHash:
+    case NormalizeMapKey:
     case GetMapBucket:
     case GetMapBucketHead:
     case GetMapBucketNext:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -1940,6 +1940,11 @@
             break;
         }
 
+        case NormalizeMapKey: {
+            fixupNormalizeMapKey(node);
+            break;
+        }
+
         case WeakMapGet: {
             fixEdge<WeakMapObjectUse>(node->child1());
             fixEdge<ObjectUse>(node->child2());
@@ -3203,6 +3208,47 @@
         fixEdge<Int32Use>(node->child2());
     }
 
+    void fixupNormalizeMapKey(Node* node)
+    {
+        if (node->child1()->shouldSpeculateBoolean()) {
+            fixEdge<BooleanUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateInt32()) {
+            fixEdge<Int32Use>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateSymbol()) {
+            fixEdge<SymbolUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateObject()) {
+            fixEdge<ObjectUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateString()) {
+            fixEdge<StringUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateCell()) {
+            fixEdge<CellUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        fixEdge<UntypedUse>(node->child1());
+    }
+
     bool attemptToMakeCallDOM(Node* node)
     {
         if (m_graph.hasExitSite(node->origin.semantic, BadType))

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2017-11-27 07:51:16 UTC (rev 225154)
@@ -435,6 +435,7 @@
     macro(ToIndexString, NodeResultJS) \
     /* Nodes for JSMap and JSSet */ \
     macro(MapHash, NodeResultInt32) \
+    macro(NormalizeMapKey, NodeResultJS) \
     macro(GetMapBucket, NodeResultJS) \
     macro(GetMapBucketHead, NodeResultJS) \
     macro(GetMapBucketNext, NodeResultJS) \

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -2533,7 +2533,7 @@
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
 
-    return jsMapHash(exec, vm, normalizeMapKey(JSValue::decode(input)));
+    return jsMapHash(exec, vm, JSValue::decode(input));
 }
 
 JSCell* JIT_OPERATION operationJSMapFindBucket(ExecState* exec, JSCell* map, EncodedJSValue key, int32_t hash)
@@ -2540,7 +2540,7 @@
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
-    JSMap::BucketType** bucket = jsCast<JSMap*>(map)->findBucket(exec, normalizeMapKey(JSValue::decode(key)), hash);
+    JSMap::BucketType** bucket = jsCast<JSMap*>(map)->findBucket(exec, JSValue::decode(key), hash);
     if (!bucket)
         return vm.sentinelMapBucket.get();
     return *bucket;
@@ -2550,19 +2550,17 @@
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
-    JSSet::BucketType** bucket = jsCast<JSSet*>(map)->findBucket(exec, normalizeMapKey(JSValue::decode(key)), hash);
+    JSSet::BucketType** bucket = jsCast<JSSet*>(map)->findBucket(exec, JSValue::decode(key), hash);
     if (!bucket)
         return vm.sentinelSetBucket.get();
     return *bucket;
 }
 
-// FIXME: Add NormalizeMapKey DFG node.
-// https://bugs.webkit.org/show_bug.cgi?id=179912
 void JIT_OPERATION operationSetAdd(ExecState* exec, JSCell* set, EncodedJSValue key, int32_t hash)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
-    jsCast<JSSet*>(set)->addNormalized(exec, normalizeMapKey(JSValue::decode(key)), JSValue(), hash);
+    jsCast<JSSet*>(set)->addNormalized(exec, JSValue::decode(key), JSValue(), hash);
 }
 
 void JIT_OPERATION operationMapSet(ExecState* exec, JSCell* map, EncodedJSValue key, EncodedJSValue value, int32_t hash)
@@ -2569,7 +2567,7 @@
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
-    jsCast<JSMap*>(map)->addNormalized(exec, normalizeMapKey(JSValue::decode(key)), JSValue::decode(value), hash);
+    jsCast<JSMap*>(map)->addNormalized(exec, JSValue::decode(key), JSValue::decode(value), hash);
 }
 
 EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(ExecState* exec, JSObject* thisObject)

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -462,6 +462,13 @@
             break;
         }
 
+        case NormalizeMapKey: {
+            SpeculatedType prediction = node->child1()->prediction();
+            if (prediction)
+                changed |= mergePrediction(prediction);
+            break;
+        }
+
         default:
             break;
         }
@@ -1024,6 +1031,7 @@
         case GetByVal:
         case ToThis:
         case ToPrimitive: 
+        case NormalizeMapKey:
         case AtomicsAdd:
         case AtomicsAnd:
         case AtomicsCompareExchange:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2017-11-27 07:51:16 UTC (rev 225154)
@@ -416,6 +416,7 @@
     case ResolveScopeForHoistingFuncDeclInEval:
     case ResolveScope:
     case MapHash:
+    case NormalizeMapKey:
     case StringSlice:
     case ToLowerCase:
     case GetMapBucket:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -10737,6 +10737,47 @@
     m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfVectorLength()));
 }
 
+void SpeculativeJIT::compileNormalizeMapKey(Node* node)
+{
+    ASSERT(node->child1().useKind() == UntypedUse);
+    JSValueOperand key(this, node->child1());
+    JSValueRegsTemporary result(this, Reuse, key);
+    GPRTemporary scratch(this);
+    FPRTemporary doubleValue(this);
+    FPRTemporary temp(this);
+
+    JSValueRegs keyRegs = key.jsValueRegs();
+    JSValueRegs resultRegs = result.regs();
+    GPRReg scratchGPR = scratch.gpr();
+    FPRReg doubleValueFPR = doubleValue.fpr();
+    FPRReg tempFPR = temp.fpr();
+
+    CCallHelpers::JumpList passThroughCases;
+
+    passThroughCases.append(m_jit.branchIfNotNumber(keyRegs, scratchGPR));
+    passThroughCases.append(m_jit.branchIfInt32(keyRegs));
+
+#if USE(JSVALUE64)
+    m_jit.unboxDoubleWithoutAssertions(keyRegs.gpr(), scratchGPR, doubleValueFPR);
+#else
+    unboxDouble(keyRegs.tagGPR(), keyRegs.payloadGPR(), doubleValueFPR, tempFPR);
+#endif
+    passThroughCases.append(m_jit.branchDouble(JITCompiler::DoubleNotEqualOrUnordered, doubleValueFPR, doubleValueFPR));
+
+    m_jit.truncateDoubleToInt32(doubleValueFPR, scratchGPR);
+    m_jit.convertInt32ToDouble(scratchGPR, tempFPR);
+    passThroughCases.append(m_jit.branchDouble(JITCompiler::DoubleNotEqual, doubleValueFPR, tempFPR));
+
+    m_jit.boxInt32(scratchGPR, resultRegs);
+    auto done = m_jit.jump();
+
+    passThroughCases.link(&m_jit);
+    m_jit.moveValueRegs(keyRegs, resultRegs);
+
+    done.link(&m_jit);
+    jsValueResult(resultRegs, node);
+}
+
 void SpeculativeJIT::compileGetMapBucketHead(Node* node)
 {
     SpeculateCellOperand map(this, node->child1());

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-11-27 07:51:16 UTC (rev 225154)
@@ -2894,6 +2894,7 @@
     void compileCallDOMGetter(Node*);
     void compileCallDOM(Node*);
     void compileCheckSubClass(Node*);
+    void compileNormalizeMapKey(Node*);
     void compileGetMapBucketHead(Node*);
     void compileGetMapBucketNext(Node*);
     void compileSetAdd(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -4822,6 +4822,11 @@
         break;
     }
 
+    case NormalizeMapKey: {
+        compileNormalizeMapKey(node);
+        break;
+    }
+
     case GetMapBucket: {
         SpeculateCellOperand map(this, node->child1());
         JSValueOperand key(this, node->child2());

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -5072,7 +5072,7 @@
 
         MacroAssembler::JumpList straightHash;
         MacroAssembler::JumpList done;
-        auto isNotCell = m_jit.branchIfNotCell(inputGPR);
+        straightHash.append(m_jit.branchIfNotCell(inputGPR));
         MacroAssembler::JumpList slowPath;
         straightHash.append(m_jit.branch8(MacroAssembler::NotEqual, MacroAssembler::Address(inputGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType)));
         m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR);
@@ -5082,11 +5082,6 @@
         slowPath.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
         done.append(m_jit.jump());
 
-        isNotCell.link(&m_jit);
-        straightHash.append(m_jit.branchIfNotNumber(inputGPR));
-        straightHash.append(m_jit.branchIfInt32(JSValueRegs(inputGPR)));
-        slowPath.append(m_jit.jump());
-
         straightHash.link(&m_jit);
         m_jit.move(inputGPR, resultGPR);
         m_jit.wangsInt64Hash(resultGPR, tempGPR);
@@ -5102,6 +5097,12 @@
         int32Result(resultGPR, node);
         break;
     }
+
+    case NormalizeMapKey: {
+        compileNormalizeMapKey(node);
+        break;
+    }
+
     case GetMapBucket: {
         SpeculateCellOperand map(this, node->child1());
         JSValueOperand key(this, node->child2(), ManualOperandSpeculation);
@@ -5182,7 +5183,8 @@
         }
         case UntypedUse: { 
             done.append(m_jit.branch64(MacroAssembler::Equal, bucketGPR, keyGPR)); // They're definitely the same value, we found the bucket we were looking for!
-            auto _oneIsntCell_ = m_jit.branchIfNotCell(JSValueRegs(bucketGPR));
+            // The input key and bucket's key are already normalized. So if 64-bit compare fails and one is not a cell, they're definitely not equal.
+            loopAround.append(m_jit.branchIfNotCell(JSValueRegs(bucketGPR)));
             // first is a cell here.
             loopAround.append(m_jit.branchIfNotCell(JSValueRegs(keyGPR)));
             // Both are cells here.
@@ -5193,14 +5195,6 @@
                 JITCompiler::Address(keyGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType)));
             // The first is a string, but the second is not, we continue to loop around.
             loopAround.append(m_jit.jump());
-
-            oneIsntCell.link(&m_jit);
-            // We've already done a 64-bit compare at this point, so if one is not a number, they're definitely not equal.
-            loopAround.append(m_jit.branchIfNotNumber(bucketGPR));
-            loopAround.append(m_jit.branchIfNotNumber(keyGPR));
-            // Both are definitely numbers. If we see a double, we go to the slow path.
-            slowPathCases.append(m_jit.branchIfNotInt32(bucketGPR));
-            slowPathCases.append(m_jit.branchIfNotInt32(keyGPR));
             break;
         }
         default:

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -202,6 +202,7 @@
     case HasOwnProperty:
     case IsCellWithType:
     case MapHash:
+    case NormalizeMapKey:
     case GetMapBucket:
     case GetMapBucketHead:
     case GetMapBucketNext:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (225153 => 225154)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-11-27 07:51:16 UTC (rev 225154)
@@ -1043,6 +1043,9 @@
         case MapHash:
             compileMapHash();
             break;
+        case NormalizeMapKey:
+            compileNormalizeMapKey();
+            break;
         case GetMapBucket:
             compileGetMapBucket();
             break;
@@ -8527,16 +8530,14 @@
         LValue value = lowJSValue(m_node->child1());
 
         LBasicBlock isCellCase = m_out.newBlock();
-        LBasicBlock notCell = m_out.newBlock();
         LBasicBlock slowCase = m_out.newBlock();
         LBasicBlock straightHash = m_out.newBlock();
-        LBasicBlock isNumberCase = m_out.newBlock();
         LBasicBlock isStringCase = m_out.newBlock();
         LBasicBlock nonEmptyStringCase = m_out.newBlock();
         LBasicBlock continuation = m_out.newBlock();
 
         m_out.branch(
-            isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(notCell));
+            isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(straightHash));
 
         LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
         LValue isString = m_out.equal(m_out.load8ZeroExt32(value, m_heaps.JSCell_typeInfoType), m_out.constInt32(StringType));
@@ -8548,20 +8549,12 @@
         m_out.branch(
             m_out.equal(stringImpl, m_out.constIntPtr(0)), rarely(slowCase), usually(nonEmptyStringCase));
 
-        m_out.appendTo(nonEmptyStringCase, notCell);
+        m_out.appendTo(nonEmptyStringCase, straightHash);
         LValue hash = m_out.lShr(m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::s_flagCount));
         ValueFromBlock nonEmptyStringHashResult = m_out.anchor(hash);
         m_out.branch(m_out.equal(hash, m_out.constInt32(0)),
             unsure(slowCase), unsure(continuation));
 
-        m_out.appendTo(notCell, isNumberCase);
-        m_out.branch(
-            isNumber(value), unsure(isNumberCase), unsure(straightHash));
-
-        m_out.appendTo(isNumberCase, straightHash);
-        m_out.branch(
-            isInt32(value), unsure(straightHash), unsure(slowCase));
-
         m_out.appendTo(straightHash, slowCase);
         ValueFromBlock fastResult = m_out.anchor(wangsInt64Hash(value));
         m_out.jump(continuation);
@@ -8575,6 +8568,42 @@
         setInt32(m_out.phi(Int32, fastResult, slowResult, nonEmptyStringHashResult));
     }
 
+    void compileNormalizeMapKey()
+    {
+        ASSERT(m_node->child1().useKind() == UntypedUse);
+
+        LBasicBlock isNumberCase = m_out.newBlock();
+        LBasicBlock notInt32NumberCase = m_out.newBlock();
+        LBasicBlock notNaNCase = m_out.newBlock();
+        LBasicBlock convertibleCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        LBasicBlock lastNext = m_out.insertNewBlocksBefore(isNumberCase);
+
+        LValue key = lowJSValue(m_node->child1());
+        ValueFromBlock fastResult = m_out.anchor(key);
+        m_out.branch(isNotNumber(key), unsure(continuation), unsure(isNumberCase));
+
+        m_out.appendTo(isNumberCase, notInt32NumberCase);
+        m_out.branch(isInt32(key), unsure(continuation), unsure(notInt32NumberCase));
+
+        m_out.appendTo(notInt32NumberCase, notNaNCase);
+        LValue doubleValue = unboxDouble(key);
+        m_out.branch(m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue), unsure(continuation), unsure(notNaNCase));
+
+        m_out.appendTo(notNaNCase, convertibleCase);
+        LValue integerValue = m_out.doubleToInt(doubleValue);
+        LValue integerValueConvertedToDouble = m_out.intToDouble(integerValue);
+        m_out.branch(m_out.doubleNotEqualOrUnordered(doubleValue, integerValueConvertedToDouble), unsure(continuation), unsure(convertibleCase));
+
+        m_out.appendTo(convertibleCase, continuation);
+        ValueFromBlock slowResult = m_out.anchor(boxInt32(integerValue));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setJSValue(m_out.phi(Int64, fastResult, slowResult));
+    }
+
     void compileGetMapBucket()
     {
         LBasicBlock loopStart = m_out.newBlock();
@@ -8676,10 +8705,6 @@
             LBasicBlock bucketKeyIsCell = m_out.newBlock();
             LBasicBlock bothAreCells = m_out.newBlock();
             LBasicBlock bucketKeyIsString = m_out.newBlock();
-            LBasicBlock bucketKeyNotCell = m_out.newBlock();
-            LBasicBlock bucketKeyIsNumber = m_out.newBlock();
-            LBasicBlock bothAreNumbers = m_out.newBlock();
-            LBasicBlock bucketKeyIsInt32 = m_out.newBlock();
 
             m_out.branch(m_out.equal(key, bucketKey),
                 unsure(continuation), unsure(notBitEqual));
@@ -8686,7 +8711,7 @@
 
             m_out.appendTo(notBitEqual, bucketKeyIsCell);
             m_out.branch(isCell(bucketKey),
-                unsure(bucketKeyIsCell), unsure(bucketKeyNotCell));
+                unsure(bucketKeyIsCell), unsure(loopAround));
 
             m_out.appendTo(bucketKeyIsCell, bothAreCells);
             m_out.branch(isCell(key),
@@ -8696,25 +8721,9 @@
             m_out.branch(isString(bucketKey),
                 unsure(bucketKeyIsString), unsure(loopAround));
 
-            m_out.appendTo(bucketKeyIsString, bucketKeyNotCell);
+            m_out.appendTo(bucketKeyIsString, loopAround);
             m_out.branch(isString(key),
                 unsure(slowPath), unsure(loopAround));
-
-            m_out.appendTo(bucketKeyNotCell, bucketKeyIsNumber);
-            m_out.branch(isNotNumber(bucketKey),
-                unsure(loopAround), unsure(bucketKeyIsNumber));
-
-            m_out.appendTo(bucketKeyIsNumber, bothAreNumbers);
-            m_out.branch(isNotNumber(key),
-                unsure(loopAround), unsure(bothAreNumbers));
-
-            m_out.appendTo(bothAreNumbers, bucketKeyIsInt32);
-            m_out.branch(isNotInt32(bucketKey),
-                unsure(slowPath), unsure(bucketKeyIsInt32));
-
-            m_out.appendTo(bucketKeyIsInt32, loopAround);
-            m_out.branch(isNotInt32(key),
-                unsure(slowPath), unsure(loopAround));
             break;
         }
         default:

Modified: trunk/Source/_javascript_Core/runtime/HashMapImpl.h (225153 => 225154)


--- trunk/Source/_javascript_Core/runtime/HashMapImpl.h	2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/_javascript_Core/runtime/HashMapImpl.h	2017-11-27 07:51:16 UTC (rev 225154)
@@ -233,6 +233,8 @@
     return sameValue(exec, a, b);
 }
 
+// Note that normalization is inlined in DFG's NormalizeMapKey.
+// Keep in sync with the implementation of DFG and FTL normalization.
 ALWAYS_INLINE JSValue normalizeMapKey(JSValue key)
 {
     if (!key.isNumber())
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to