Changeset 234066 in webkit


Ignore:
Timestamp:
Jul 20, 2018 2:25:19 PM (6 years ago)
Author:
Yusuke Suzuki
Message:

[DFG] Fold GetByVal if Array is CoW
https://bugs.webkit.org/show_bug.cgi?id=186459

Reviewed by Saam Barati.

JSTests:

  • stress/folding-get-by-val-with-immutable-butterfly-out-of-bounds-foldable.js: Added.

(shouldBe):
(test0):
(test1):
(test2):
(test3):
(test4):
(test5):

  • stress/folding-get-by-val-with-immutable-butterfly-out-of-bounds.js: Added.

(shouldBe):
(test0):
(test1):
(test2):
(test3):
(test4):
(test5):

  • stress/folding-get-by-val-with-immutable-butterfly-with-types.js: Added.

(shouldBe):
(test0):
(test1):
(test2):
(test3):
(test4):
(test5):

  • stress/folding-get-by-val-with-immutable-butterfly.js: Added.

(shouldBe):
(checking):
(test):

Source/JavaScriptCore:

CoW indexing type means that we now tracks the changes in CoW Array by structure. So DFG has a chance to
fold GetByVal if the given array is CoW. This patch folds GetByVal onto the CoW Array. If the structure
is watched and the butterfly is JSImmutableButterfly, we can load the value from this butterfly.

This can be useful since these CoW arrays are used for a storage for constants. Constant-indexed access
to these constant arrays can be folded into an actual constant by this patch.

baseline patched

template_string.es6 4993.9853+-147.5308 824.1685+-44.1839 definitely 6.0594x faster
template_string_tag.es5 67.0822+-2.0100 9.3540+-0.5376 definitely 7.1715x faster

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

Location:
trunk
Files:
4 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r234060 r234066  
     12018-07-20  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DFG] Fold GetByVal if Array is CoW
     4        https://bugs.webkit.org/show_bug.cgi?id=186459
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/folding-get-by-val-with-immutable-butterfly-out-of-bounds-foldable.js: Added.
     9        (shouldBe):
     10        (test0):
     11        (test1):
     12        (test2):
     13        (test3):
     14        (test4):
     15        (test5):
     16        * stress/folding-get-by-val-with-immutable-butterfly-out-of-bounds.js: Added.
     17        (shouldBe):
     18        (test0):
     19        (test1):
     20        (test2):
     21        (test3):
     22        (test4):
     23        (test5):
     24        * stress/folding-get-by-val-with-immutable-butterfly-with-types.js: Added.
     25        (shouldBe):
     26        (test0):
     27        (test1):
     28        (test2):
     29        (test3):
     30        (test4):
     31        (test5):
     32        * stress/folding-get-by-val-with-immutable-butterfly.js: Added.
     33        (shouldBe):
     34        (checking):
     35        (test):
     36
    1372018-07-20  Saam Barati  <sbarati@apple.com>
    238
  • trunk/Source/JavaScriptCore/ChangeLog

    r234065 r234066  
     12018-07-20  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DFG] Fold GetByVal if Array is CoW
     4        https://bugs.webkit.org/show_bug.cgi?id=186459
     5
     6        Reviewed by Saam Barati.
     7
     8        CoW indexing type means that we now tracks the changes in CoW Array by structure. So DFG has a chance to
     9        fold GetByVal if the given array is CoW. This patch folds GetByVal onto the CoW Array. If the structure
     10        is watched and the butterfly is JSImmutableButterfly, we can load the value from this butterfly.
     11
     12        This can be useful since these CoW arrays are used for a storage for constants. Constant-indexed access
     13        to these constant arrays can be folded into an actual constant by this patch.
     14
     15                                           baseline                  patched
     16
     17        template_string.es6          4993.9853+-147.5308   ^    824.1685+-44.1839       ^ definitely 6.0594x faster
     18        template_string_tag.es5        67.0822+-2.0100     ^      9.3540+-0.5376        ^ definitely 7.1715x faster
     19
     20        * dfg/DFGAbstractInterpreterInlines.h:
     21        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     22
    1232018-07-20  Yusuke Suzuki  <utatane.tea@gmail.com>
    224
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r232461 r234066  
    2929
    3030#include "ArrayConstructor.h"
     31#include "ArrayPrototype.h"
    3132#include "DFGAbstractInterpreter.h"
    3233#include "DFGAbstractInterpreterClobberState.h"
     
    3738#include "HashMapImpl.h"
    3839#include "JITOperations.h"
     40#include "JSImmutableButterfly.h"
    3941#include "MathCommon.h"
    4042#include "NumberConstructor.h"
     
    18161818    case AtomicsSub:
    18171819    case AtomicsXor: {
     1820        if (node->op() == GetByVal) {
     1821            auto foldGetByValOnCoWArray = [&] (Edge& arrayEdge, Edge& indexEdge) {
     1822                // FIXME: We can expand this for non x86 environments.
     1823                // https://bugs.webkit.org/show_bug.cgi?id=134641
     1824                if (!isX86())
     1825                    return false;
     1826
     1827                AbstractValue& arrayValue = forNode(arrayEdge);
     1828                if (node->arrayMode().arrayClass() != Array::OriginalCopyOnWriteArray)
     1829                    return false;
     1830
     1831                // Check the structure set is finite. This means that this constant's structure is watched and guaranteed the one of this set.
     1832                // When the structure is changed, this code should be invalidated. This is important since the following code relies on the
     1833                // constant object's is not changed.
     1834                if (!arrayValue.m_structure.isFinite())
     1835                    return false;
     1836
     1837                JSValue arrayConstant = arrayValue.value();
     1838                if (!arrayConstant)
     1839                    return false;
     1840
     1841                JSObject* array = jsDynamicCast<JSObject*>(m_vm, arrayConstant);
     1842                if (!array)
     1843                    return false;
     1844
     1845                JSValue indexConstant = forNode(indexEdge).value();
     1846                if (!indexConstant || !indexConstant.isInt32() || indexConstant.asInt32() < 0)
     1847                    return false;
     1848                uint32_t index = indexConstant.asUInt32();
     1849
     1850                // Check that the early StructureID is not nuked, get the butterfly, and check the late StructureID again.
     1851                // And we check the indexing mode of the structure. If the indexing mode is CoW, the butterfly is
     1852                // definitely JSImmutableButterfly.
     1853                StructureID structureIDEarly = array->structureID();
     1854                if (isNuked(structureIDEarly))
     1855                    return false;
     1856
     1857                WTF::loadLoadFence();
     1858                Butterfly* butterfly = array->butterfly();
     1859
     1860                WTF::loadLoadFence();
     1861                StructureID structureIDLate = array->structureID();
     1862
     1863                if (structureIDEarly != structureIDLate)
     1864                    return false;
     1865
     1866                if (!isCopyOnWrite(m_vm.getStructure(structureIDLate)->indexingMode()))
     1867                    return false;
     1868
     1869                JSImmutableButterfly* immutableButterfly = JSImmutableButterfly::fromButterfly(butterfly);
     1870                if (index < immutableButterfly->length()) {
     1871                    JSValue value = immutableButterfly->get(index);
     1872                    ASSERT(value);
     1873                    if (value.isCell())
     1874                        setConstant(node, *m_graph.freeze(value.asCell()));
     1875                    else
     1876                        setConstant(node, value);
     1877                    return true;
     1878                }
     1879
     1880                if (node->arrayMode().isOutOfBounds()) {
     1881                    JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
     1882                    Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(m_vm);
     1883                    Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(m_vm);
     1884                    if (arrayPrototypeStructure->transitionWatchpointSetIsStillValid()
     1885                        && objectPrototypeStructure->transitionWatchpointSetIsStillValid()
     1886                        && globalObject->arrayPrototypeChainIsSane()) {
     1887                        m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure);
     1888                        m_graph.registerAndWatchStructureTransition(objectPrototypeStructure);
     1889                        didFoldClobberWorld();
     1890                        // Note that Array::Double and Array::Int32 return JSValue if array mode is OutOfBounds.
     1891                        setConstant(node, jsUndefined());
     1892                        return true;
     1893                    }
     1894                }
     1895                return false;
     1896            };
     1897
     1898            if (foldGetByValOnCoWArray(m_graph.child(node, 0), m_graph.child(node, 1)))
     1899                break;
     1900        }
     1901
    18181902        if (node->op() != GetByVal) {
    18191903            unsigned numExtraArgs = numExtraAtomicsArgs(node->op());
Note: See TracChangeset for help on using the changeset viewer.