Changeset 199342 in webkit


Ignore:
Timestamp:
Apr 12, 2016 1:25:48 AM (8 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] addStaticGlobals should emit SymbolTableEntry watchpoints to encourage constant folding in DFG
https://bugs.webkit.org/show_bug.cgi?id=155110

Reviewed by Saam Barati.

Source/JavaScriptCore:

addStaticGlobals does not emit SymbolTableEntry watchpoints for the added entries.
So, all the global variable lookups pointing to these static globals are not converted
into constants in DFGBytecodeGenerator: this fact leaves these lookups as GetGlobalVar.
Such thing avoids constant folding chance and emits CheckCell for @privateFunction inlining.
This operation is pure overhead.

Static globals are not configurable, and they are typically non-writable.
So they are constants in almost all the cases.

This patch initializes watchpoints for these static globals.
These watchpoints allow DFG to convert these nodes into constants in DFG BytecodeParser.
These watchpoints includes many builtin operations and undefined.

The microbenchmark, many-foreach-calls shows 5 - 7% improvement since it removes unnecessary CheckCell.

  • bytecode/VariableWriteFireDetail.h:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::addGlobalVar):
(JSC::JSGlobalObject::addStaticGlobals):

  • runtime/JSSymbolTableObject.h:

(JSC::symbolTablePutTouchWatchpointSet):
(JSC::symbolTablePutInvalidateWatchpointSet):
(JSC::symbolTablePut):
(JSC::symbolTablePutWithAttributesTouchWatchpointSet): Deleted.

  • runtime/SymbolTable.h:

(JSC::SymbolTableEntry::SymbolTableEntry):
(JSC::SymbolTableEntry::operator=):
(JSC::SymbolTableEntry::swap):

Source/WebCore:

  • bindings/js/JSDOMWindowBase.cpp:

(WebCore::JSDOMWindowBase::updateDocument):

Location:
trunk/Source
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r199339 r199342  
     12016-04-12  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] addStaticGlobals should emit SymbolTableEntry watchpoints to encourage constant folding in DFG
     4        https://bugs.webkit.org/show_bug.cgi?id=155110
     5
     6        Reviewed by Saam Barati.
     7
     8        `addStaticGlobals` does not emit SymbolTableEntry watchpoints for the added entries.
     9        So, all the global variable lookups pointing to these static globals are not converted
     10        into constants in DFGBytecodeGenerator: this fact leaves these lookups as GetGlobalVar.
     11        Such thing avoids constant folding chance and emits CheckCell for @privateFunction inlining.
     12        This operation is pure overhead.
     13
     14        Static globals are not configurable, and they are typically non-writable.
     15        So they are constants in almost all the cases.
     16
     17        This patch initializes watchpoints for these static globals.
     18        These watchpoints allow DFG to convert these nodes into constants in DFG BytecodeParser.
     19        These watchpoints includes many builtin operations and `undefined`.
     20
     21        The microbenchmark, many-foreach-calls shows 5 - 7% improvement since it removes unnecessary CheckCell.
     22
     23        * bytecode/VariableWriteFireDetail.h:
     24        * runtime/JSGlobalObject.cpp:
     25        (JSC::JSGlobalObject::addGlobalVar):
     26        (JSC::JSGlobalObject::addStaticGlobals):
     27        * runtime/JSSymbolTableObject.h:
     28        (JSC::symbolTablePutTouchWatchpointSet):
     29        (JSC::symbolTablePutInvalidateWatchpointSet):
     30        (JSC::symbolTablePut):
     31        (JSC::symbolTablePutWithAttributesTouchWatchpointSet): Deleted.
     32        * runtime/SymbolTable.h:
     33        (JSC::SymbolTableEntry::SymbolTableEntry):
     34        (JSC::SymbolTableEntry::operator=):
     35        (JSC::SymbolTableEntry::swap):
     36
    1372016-04-12  Alex Christensen  <achristensen@webkit.org>
    238
  • trunk/Source/JavaScriptCore/bytecode/VariableWriteFireDetail.h

    r197563 r199342  
    4242    }
    4343   
    44     void dump(PrintStream&) const override;
     44    JS_EXPORT_PRIVATE void dump(PrintStream&) const override;
    4545   
    4646    JS_EXPORT_PRIVATE static void touch(WatchpointSet*, JSObject*, const PropertyName&);
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r199164 r199342  
    680680    SymbolTableEntry newEntry(VarOffset(offset), 0);
    681681    newEntry.prepareToWatch();
    682     symbolTable()->add(locker, ident.impl(), newEntry);
     682    symbolTable()->add(locker, ident.impl(), WTFMove(newEntry));
    683683   
    684684    ScopeOffset offsetForAssert = addVariables(1, jsUndefined());
     
    980980        ASSERT(global.attributes & DontDelete);
    981981       
    982         ScopeOffset offset;
     982        WatchpointSet* watchpointSet = nullptr;
     983        WriteBarrierBase<Unknown>* variable = nullptr;
    983984        {
    984985            ConcurrentJITLocker locker(symbolTable()->m_lock);
    985             offset = symbolTable()->takeNextScopeOffset(locker);
     986            ScopeOffset offset = symbolTable()->takeNextScopeOffset(locker);
    986987            RELEASE_ASSERT(offset = startOffset + i);
    987988            SymbolTableEntry newEntry(VarOffset(offset), global.attributes);
    988             symbolTable()->add(locker, global.identifier.impl(), newEntry);
     989            newEntry.prepareToWatch();
     990            watchpointSet = newEntry.watchpointSet();
     991            symbolTable()->add(locker, global.identifier.impl(), WTFMove(newEntry));
     992            variable = &variableAt(offset);
    989993        }
    990         variableAt(offset).set(vm(), this, global.value);
     994        symbolTablePutTouchWatchpointSet(vm(), this, global.identifier, global.value, variable, watchpointSet);
    991995    }
    992996}
  • trunk/Source/JavaScriptCore/runtime/JSSymbolTableObject.h

    r198023 r199342  
    142142}
    143143
     144template<typename SymbolTableObjectType>
     145ALWAYS_INLINE void symbolTablePutTouchWatchpointSet(VM& vm, SymbolTableObjectType* object, PropertyName propertyName, JSValue value, WriteBarrierBase<Unknown>* reg, WatchpointSet* set)
     146{
     147    reg->set(vm, object, value);
     148    if (set)
     149        VariableWriteFireDetail::touch(set, object, propertyName);
     150}
     151
     152template<typename SymbolTableObjectType>
     153ALWAYS_INLINE void symbolTablePutInvalidateWatchpointSet(VM& vm, SymbolTableObjectType* object, PropertyName propertyName, JSValue value, WriteBarrierBase<Unknown>* reg, WatchpointSet* set)
     154{
     155    reg->set(vm, object, value);
     156    if (set)
     157        set->invalidate(VariableWriteFireDetail(object, propertyName)); // Don't mess around - if we had found this statically, we would have invalidated it.
     158}
     159
    144160enum class SymbolTablePutMode {
    145     WithAttributes,
    146     WithoutAttributes
     161    Touch,
     162    Invalidate
    147163};
    148164
    149165template<SymbolTablePutMode symbolTablePutMode, typename SymbolTableObjectType>
    150 inline bool symbolTablePut(
    151     SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes,
    152     bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors, WatchpointSet*& set, bool& putResult)
    153 {
    154     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object));
    155 
     166inline bool symbolTablePut(SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors, bool& putResult)
     167{
    156168    VM& vm = exec->vm();
    157169
     170    WatchpointSet* set = nullptr;
    158171    WriteBarrierBase<Unknown>* reg;
    159172    {
     
    182195
    183196        set = iter->value.watchpointSet();
    184         if (symbolTablePutMode == SymbolTablePutMode::WithAttributes)
    185             iter->value.setAttributes(attributes);
    186197        reg = &object->variableAt(offset);
    187198    }
     
    189200    // the right for barriers to be able to trigger GC. And I don't want to hold VM
    190201    // locks while GC'ing.
    191     reg->set(vm, object, value);
     202    if (symbolTablePutMode == SymbolTablePutMode::Invalidate)
     203        symbolTablePutInvalidateWatchpointSet(exec->vm(), object, propertyName, value, reg, set);
     204    else
     205        symbolTablePutTouchWatchpointSet(exec->vm(), object, propertyName, value, reg, set);
    192206    putResult = true;
    193207    return true;
     
    199213    bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors, bool& putResult)
    200214{
    201     WatchpointSet* set = nullptr;
    202     unsigned attributes = 0;
    203     bool result = symbolTablePut<SymbolTablePutMode::WithoutAttributes>(object, exec, propertyName, value, attributes, shouldThrowReadOnlyError, ignoreReadOnlyErrors, set, putResult);
    204     if (set)
    205         VariableWriteFireDetail::touch(set, object, propertyName);
    206     return result;
     215    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object));
     216    return symbolTablePut<SymbolTablePutMode::Touch>(object, exec, propertyName, value, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
    207217}
    208218
     
    212222    bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors, bool& putResult)
    213223{
    214     WatchpointSet* set = nullptr;
    215     unsigned attributes = 0;
    216     bool result = symbolTablePut<SymbolTablePutMode::WithoutAttributes>(object, exec, propertyName, value, attributes, shouldThrowReadOnlyError, ignoreReadOnlyErrors, set, putResult);
    217     if (set)
    218         set->invalidate(VariableWriteFireDetail(object, propertyName)); // Don't mess around - if we had found this statically, we would have invalidated it.
    219     return result;
    220 }
    221 
    222 template<typename SymbolTableObjectType>
    223 inline bool symbolTablePutWithAttributesTouchWatchpointSet(
    224     SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName,
    225     JSValue value, unsigned attributes, bool& putResult)
    226 {
    227     WatchpointSet* set = nullptr;
    228     bool shouldThrowReadOnlyError = false;
    229     bool ignoreReadOnlyErrors = true;
    230     bool result = symbolTablePut<SymbolTablePutMode::WithAttributes>(object, exec, propertyName, value, attributes, shouldThrowReadOnlyError, ignoreReadOnlyErrors, set, putResult);
    231     if (set)
    232         VariableWriteFireDetail::touch(set, object, propertyName);
    233     return result;
     224    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object));
     225    return symbolTablePut<SymbolTablePutMode::Invalidate>(object, exec, propertyName, value, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
    234226}
    235227
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.h

    r196808 r199342  
    200200    }
    201201   
     202    SymbolTableEntry(SymbolTableEntry&& other)
     203        : m_bits(SlimFlag)
     204    {
     205        swap(other);
     206    }
     207
     208    SymbolTableEntry& operator=(SymbolTableEntry&& other)
     209    {
     210        swap(other);
     211        return *this;
     212    }
     213
     214    void swap(SymbolTableEntry& other)
     215    {
     216        std::swap(m_bits, other.m_bits);
     217    }
     218
    202219    bool isNull() const
    203220    {
     
    553570    }
    554571   
    555     void add(const ConcurrentJITLocker&, UniquedStringImpl* key, const SymbolTableEntry& entry)
     572    template<typename Entry>
     573    void add(const ConcurrentJITLocker&, UniquedStringImpl* key, Entry&& entry)
    556574    {
    557575        RELEASE_ASSERT(!m_localToEntry);
    558576        didUseVarOffset(entry.varOffset());
    559         Map::AddResult result = m_map.add(key, entry);
     577        Map::AddResult result = m_map.add(key, std::forward<Entry>(entry));
    560578        ASSERT_UNUSED(result, result.isNewEntry);
    561579    }
    562580   
    563     void add(UniquedStringImpl* key, const SymbolTableEntry& entry)
     581    template<typename Entry>
     582    void add(UniquedStringImpl* key, Entry&& entry)
    564583    {
    565584        ConcurrentJITLocker locker(m_lock);
    566         add(locker, key, entry);
    567     }
    568    
    569     void set(const ConcurrentJITLocker&, UniquedStringImpl* key, const SymbolTableEntry& entry)
     585        add(locker, key, std::forward<Entry>(entry));
     586    }
     587   
     588    template<typename Entry>
     589    void set(const ConcurrentJITLocker&, UniquedStringImpl* key, Entry&& entry)
    570590    {
    571591        RELEASE_ASSERT(!m_localToEntry);
    572592        didUseVarOffset(entry.varOffset());
    573         m_map.set(key, entry);
    574     }
    575    
    576     void set(UniquedStringImpl* key, const SymbolTableEntry& entry)
     593        m_map.set(key, std::forward<Entry>(entry));
     594    }
     595   
     596    template<typename Entry>
     597    void set(UniquedStringImpl* key, Entry&& entry)
    577598    {
    578599        ConcurrentJITLocker locker(m_lock);
    579         set(locker, key, entry);
     600        set(locker, key, std::forward<Entry>(entry));
    580601    }
    581602   
  • trunk/Source/WebCore/ChangeLog

    r199341 r199342  
     12016-04-12  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] addStaticGlobals should emit SymbolTableEntry watchpoints to encourage constant folding in DFG
     4        https://bugs.webkit.org/show_bug.cgi?id=155110
     5
     6        Reviewed by Saam Barati.
     7
     8        * bindings/js/JSDOMWindowBase.cpp:
     9        (WebCore::JSDOMWindowBase::updateDocument):
     10
    1112016-04-12  Sergio Villar Senin  <svillar@igalia.com>
    212
  • trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp

    r198932 r199342  
    102102void JSDOMWindowBase::updateDocument()
    103103{
     104    // Since "document" property is defined as { configurable: false, writable: false, enumerable: true },
     105    // users cannot change its attributes further.
     106    // Reaching here, the attributes of "document" property should be never changed.
    104107    ASSERT(m_wrapped->document());
    105108    ExecState* exec = globalExec();
     109    bool shouldThrowReadOnlyError = false;
     110    bool ignoreReadOnlyErrors = true;
    106111    bool putResult = false;
    107     symbolTablePutWithAttributesTouchWatchpointSet(this, exec, exec->vm().propertyNames->document, toJS(exec, this, m_wrapped->document()), DontDelete | ReadOnly, putResult);
     112    symbolTablePutTouchWatchpointSet(this, exec, exec->vm().propertyNames->document, toJS(exec, this, m_wrapped->document()), shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
    108113}
    109114
Note: See TracChangeset for help on using the changeset viewer.