Changeset 174789 in webkit


Ignore:
Timestamp:
Oct 16, 2014 12:55:14 PM (10 years ago)
Author:
saambarati1@gmail.com
Message:

Have the ProfileType node in the DFG convert to a structure check where it can
https://bugs.webkit.org/show_bug.cgi?id=137596

Reviewed by Filip Pizlo.

TypeSet now keeps track of the live set of Structures it has seen.
It no longer nukes everything during GC. It now only removes unmarked
structures during GC. This modification allows the ProfileType node
to convert into a CheckStructure node safely in the DFG.

This change brings up the conversion rate from ProfileType to Check
or CheckStructrue from ~45% to ~65%. This change also speeds the
type profiler up significantly: consistently between 2x-20x faster.

This patch also does some slight refactoring: a few type profiler
related fields are moved from VM to TypeProfiler.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::CodeBlock):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGNode.h:

(JSC::DFG::Node::convertToCheckStructure):

  • heap/Heap.cpp:

(JSC::Heap::collect):

  • runtime/SymbolTable.cpp:

(JSC::SymbolTable::uniqueIDForVariable):

  • runtime/SymbolTable.h:
  • runtime/TypeLocationCache.cpp:

(JSC::TypeLocationCache::getTypeLocation):

  • runtime/TypeProfiler.cpp:

(JSC::TypeProfiler::TypeProfiler):
(JSC::TypeProfiler::nextTypeLocation):
(JSC::TypeProfiler::invalidateTypeSetCache):
(JSC::TypeProfiler::dumpTypeProfilerData):

  • runtime/TypeProfiler.h:

(JSC::TypeProfiler::getNextUniqueVariableID):

  • runtime/TypeProfilerLog.cpp:

(JSC::TypeProfilerLog::processLogEntries):

  • runtime/TypeSet.cpp:

(JSC::TypeSet::addTypeInformation):
(JSC::TypeSet::invalidateCache):

  • runtime/TypeSet.h:

(JSC::TypeSet::structureSet):

  • runtime/VM.cpp:

(JSC::VM::VM):
(JSC::VM::enableTypeProfiler):
(JSC::VM::disableTypeProfiler):
(JSC::VM::dumpTypeProfilerData):
(JSC::VM::nextTypeLocation): Deleted.
(JSC::VM::invalidateTypeSetCache): Deleted.

  • runtime/VM.h:

(JSC::VM::typeProfiler):
(JSC::VM::getNextUniqueVariableID): Deleted.

  • tests/typeProfiler/dfg-jit-optimizations.js:
Location:
trunk/Source/JavaScriptCore
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r174762 r174789  
     12014-10-16  Saam Barati  <saambarati1@gmail.com>
     2
     3        Have the ProfileType node in the DFG convert to a structure check where it can
     4        https://bugs.webkit.org/show_bug.cgi?id=137596
     5
     6        Reviewed by Filip Pizlo.
     7
     8        TypeSet now keeps track of the live set of Structures it has seen.
     9        It no longer nukes everything during GC. It now only removes unmarked
     10        structures during GC. This modification allows the ProfileType node
     11        to convert into a CheckStructure node safely in the DFG.
     12
     13        This change brings up the conversion rate from ProfileType to Check
     14        or CheckStructrue from ~45% to ~65%. This change also speeds the
     15        type profiler up significantly: consistently between 2x-20x faster.
     16
     17        This patch also does some slight refactoring: a few type profiler
     18        related fields are moved from VM to TypeProfiler.
     19
     20        * bytecode/CodeBlock.cpp:
     21        (JSC::CodeBlock::CodeBlock):
     22        * dfg/DFGFixupPhase.cpp:
     23        (JSC::DFG::FixupPhase::fixupNode):
     24        * dfg/DFGNode.h:
     25        (JSC::DFG::Node::convertToCheckStructure):
     26        * heap/Heap.cpp:
     27        (JSC::Heap::collect):
     28        * runtime/SymbolTable.cpp:
     29        (JSC::SymbolTable::uniqueIDForVariable):
     30        * runtime/SymbolTable.h:
     31        * runtime/TypeLocationCache.cpp:
     32        (JSC::TypeLocationCache::getTypeLocation):
     33        * runtime/TypeProfiler.cpp:
     34        (JSC::TypeProfiler::TypeProfiler):
     35        (JSC::TypeProfiler::nextTypeLocation):
     36        (JSC::TypeProfiler::invalidateTypeSetCache):
     37        (JSC::TypeProfiler::dumpTypeProfilerData):
     38        * runtime/TypeProfiler.h:
     39        (JSC::TypeProfiler::getNextUniqueVariableID):
     40        * runtime/TypeProfilerLog.cpp:
     41        (JSC::TypeProfilerLog::processLogEntries):
     42        * runtime/TypeSet.cpp:
     43        (JSC::TypeSet::addTypeInformation):
     44        (JSC::TypeSet::invalidateCache):
     45        * runtime/TypeSet.h:
     46        (JSC::TypeSet::structureSet):
     47        * runtime/VM.cpp:
     48        (JSC::VM::VM):
     49        (JSC::VM::enableTypeProfiler):
     50        (JSC::VM::disableTypeProfiler):
     51        (JSC::VM::dumpTypeProfilerData):
     52        (JSC::VM::nextTypeLocation): Deleted.
     53        (JSC::VM::invalidateTypeSetCache): Deleted.
     54        * runtime/VM.h:
     55        (JSC::VM::typeProfiler):
     56        (JSC::VM::getNextUniqueVariableID): Deleted.
     57        * tests/typeProfiler/dfg-jit-optimizations.js:
     58
    1592014-10-16  Adrien Destugues  <pulkomandy@gmail.com>
    260
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r174610 r174789  
    20062006
    20072007        case op_profile_type: {
     2008            RELEASE_ASSERT(vm()->typeProfiler());
    20082009            // The format of this instruction is: op_profile_type regToProfile, TypeLocation*, flag, identifier?, resolveType?
    20092010            size_t instructionOffset = i + opLength - 1;
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r174749 r174789  
    11361136                node->convertToCheck();
    11371137                fixEdge<OtherUse>(node->child1());
     1138            } else if (typeSet->doesTypeConformTo(TypeObject)) {
     1139                StructureSet set = typeSet->structureSet();
     1140                if (!set.isEmpty()) {
     1141                    node->convertToCheckStructure(m_graph.addStructureSet(set));
     1142                    fixEdge<CellUse>(node->child1());
     1143                }
    11381144            }
    11391145
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r174167 r174789  
    381381        setOpAndDefaultFlags(Check);
    382382    }
     383
     384    void convertToCheckStructure(StructureSet* set)
     385    {
     386        setOpAndDefaultFlags(CheckStructure);
     387        m_opInfo = bitwise_cast<uintptr_t>(set);
     388    }
    383389   
    384390    void replaceWith(Node* other)
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r173069 r174789  
    983983        DeferGCForAWhile awhile(*this);
    984984        vm()->typeProfilerLog()->processLogEntries(ASCIILiteral("GC"));
    985         vm()->invalidateTypeSetCache();
    986985    }
    987986   
     
    10121011
    10131012    JAVASCRIPTCORE_GC_MARKED();
     1013
     1014    if (vm()->typeProfiler())
     1015        vm()->typeProfiler()->invalidateTypeSetCache();
    10141016
    10151017    reapWeakHandles();
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.cpp

    r172820 r174789  
    3333#include "JSCInlines.h"
    3434#include "SlotVisitorInlines.h"
     35#include "TypeProfiler.h"
    3536#include "VariableWatchpointSetInlines.h"
    3637
     
    212213    GlobalVariableID id = iter->value;
    213214    if (id == TypeProfilerNeedsUniqueIDGeneration) {
    214         id = vm.getNextUniqueVariableID();
     215        id = vm.typeProfiler()->getNextUniqueVariableID();
    215216        m_typeProfilingRareData->m_uniqueIDMap.set(key, id);
    216217        m_typeProfilingRareData->m_uniqueTypeSetMap.set(key, TypeSet::create()); // Make a new global typeset for this corresponding ID.
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.h

    r172820 r174789  
    3232#include "ConcurrentJITLock.h"
    3333#include "JSObject.h"
    34 #include "TypeSet.h"
     34#include "TypeLocation.h"
    3535#include "VariableWatchpointSet.h"
    3636#include <memory>
  • trunk/Source/JavaScriptCore/runtime/TypeLocationCache.cpp

    r172614 r174789  
    2828#include "TypeLocationCache.h"
    2929
     30#include "TypeProfiler.h"
    3031#include "VM.h"
    3132
     
    4243    bool isNewLocation = false;
    4344    if (m_locationMap.find(key) == m_locationMap.end()) {
    44         TypeLocation* location = vm->nextTypeLocation();
     45        ASSERT(vm->typeProfiler());
     46        TypeLocation* location = vm->typeProfiler()->nextTypeLocation();
    4547        location->m_globalVariableID = globalVariableID;
    4648        location->m_sourceID = sourceID;
  • trunk/Source/JavaScriptCore/runtime/TypeProfiler.cpp

    r174167 r174789  
    3333
    3434static const bool verbose = false;
     35
     36TypeProfiler::TypeProfiler()
     37    : m_nextUniqueVariableID(1)
     38{
     39}
    3540
    3641void TypeProfiler::logTypesForTypeLocation(TypeLocation* location)
     
    137142}
    138143
     144TypeLocation* TypeProfiler::nextTypeLocation()
     145{
     146    return m_typeLocationInfo.add();
     147}
     148
     149void TypeProfiler::invalidateTypeSetCache()
     150{
     151    for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
     152        TypeLocation* location = *iter;
     153        location->m_instructionTypeSet->invalidateCache();
     154        if (location->m_globalTypeSet)
     155            location->m_globalTypeSet->invalidateCache();
     156    }
     157}
     158
     159void TypeProfiler::dumpTypeProfilerData()
     160{
     161    for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
     162        TypeLocation* location = *iter;
     163        logTypesForTypeLocation(location);
     164    }
     165}
     166
    139167} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/TypeProfiler.h

    r173505 r174789  
    2929#include "CodeBlock.h"
    3030#include "FunctionHasExecutedCache.h"
     31#include "TypeLocation.h"
    3132#include "TypeLocationCache.h"
     33#include <wtf/Bag.h>
    3234#include <wtf/HashMap.h>
    3335#include <wtf/Vector.h>
     
    3941
    4042namespace JSC {
    41 
    42 class TypeLocation;
    4343
    4444struct QueryKey {
     
    9595class TypeProfiler {
    9696public:
     97    TypeProfiler();
    9798    void logTypesForTypeLocation(TypeLocation*);
    9899    JS_EXPORT_PRIVATE String typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptor, unsigned offset, intptr_t sourceID);
     
    101102    TypeLocationCache* typeLocationCache() { return &m_typeLocationCache; }
    102103    TypeLocation* findLocation(unsigned divot, intptr_t sourceID, TypeProfilerSearchDescriptor);
     104    GlobalVariableID getNextUniqueVariableID() { return m_nextUniqueVariableID++; }
     105    TypeLocation* nextTypeLocation();
     106    void invalidateTypeSetCache();
     107    void dumpTypeProfilerData();
    103108   
    104109private:
     
    109114    typedef HashMap<QueryKey, TypeLocation*> TypeLocationQueryCache;
    110115    TypeLocationQueryCache m_queryCache;
     116    GlobalVariableID m_nextUniqueVariableID;
     117    Bag<TypeLocation> m_typeLocationInfo;
    111118};
    112119
  • trunk/Source/JavaScriptCore/runtime/TypeProfilerLog.cpp

    r172820 r174789  
    6060    double before = currentTimeMS();
    6161    LogEntry* entry = m_logStartPtr;
    62     HashMap<StructureID, RefPtr<StructureShape>> seenShapes;
     62    HashMap<Structure*, RefPtr<StructureShape>> seenShapes;
    6363    while (entry != m_currentLogEntryPtr) {
    6464        StructureID id = entry->structureID;
    6565        RefPtr<StructureShape> shape;
    6666        JSValue value = entry->value;
     67        Structure* structure = 0;
    6768        if (id) {
    68             auto iter = seenShapes.find(id);
     69            structure = Heap::heap(value.asCell())->structureIDTable().get(id);
     70            auto iter = seenShapes.find(structure);
    6971            if (iter == seenShapes.end()) {
    70                 shape = Heap::heap(value.asCell())->structureIDTable().get(entry->structureID)->toStructureShape(value);
    71                 seenShapes.set(id, shape);
     72                shape = structure->toStructureShape(value);
     73                seenShapes.set(structure, shape);
    7274            } else
    7375                shape = iter->value;
     
    7880        location->m_lastSeenType = type;
    7981        if (location->m_globalTypeSet)
    80             location->m_globalTypeSet->addTypeInformation(type, shape, id);
    81         location->m_instructionTypeSet->addTypeInformation(type, shape, id);
     82            location->m_globalTypeSet->addTypeInformation(type, shape, structure);
     83        location->m_instructionTypeSet->addTypeInformation(type, shape, structure);
    8284
    8385        entry++;
  • trunk/Source/JavaScriptCore/runtime/TypeSet.cpp

    r174292 r174789  
    6868}
    6969
    70 void TypeSet::addTypeInformation(RuntimeType type, PassRefPtr<StructureShape> prpNewShape, StructureID id)
     70void TypeSet::addTypeInformation(RuntimeType type, PassRefPtr<StructureShape> prpNewShape, Structure* structure)
    7171{
    7272    RefPtr<StructureShape> newShape = prpNewShape;
    7373    m_seenTypes = m_seenTypes | type;
    7474
    75     if (id && newShape && type != TypeString) {
    76         ASSERT(m_structureIDCache.isValidValue(id));
    77         auto addResult = m_structureIDCache.add(id);
    78         if (addResult.isNewEntry) {
     75    if (structure && newShape && type != TypeString) {
     76        if (!m_structureSet.contains(structure)) {
     77            m_structureSet.add(structure);
    7978            // Make one more pass making sure that:
    80             // - We don't have two instances of the same shape. (Same shapes may have different StructureIDs).
     79            // - We don't have two instances of the same shape. (Same shapes may have different Structures).
    8180            // - We don't have two shapes that share the same prototype chain. If these shapes share the same
    8281            //   prototype chain, they will be merged into one shape.
     
    108107void TypeSet::invalidateCache()
    109108{
    110     m_structureIDCache.clear();
     109    auto keepMarkedStructuresFilter = [] (Structure* structure) -> bool { return Heap::isMarked(structure); };
     110    m_structureSet.genericFilter(keepMarkedStructuresFilter);
    111111}
    112112
  • trunk/Source/JavaScriptCore/runtime/TypeSet.h

    r174292 r174789  
    2727#define TypeSet_h
    2828
    29 #include "StructureIDTable.h"
     29#include "StructureSet.h"
    3030#include <wtf/HashSet.h>
    3131#include <wtf/RefCounted.h>
     
    9898    static PassRefPtr<TypeSet> create() { return adoptRef(new TypeSet); }
    9999    TypeSet();
    100     void addTypeInformation(RuntimeType, PassRefPtr<StructureShape>, StructureID);
     100    void addTypeInformation(RuntimeType, PassRefPtr<StructureShape>, Structure*);
    101101    static RuntimeType getRuntimeTypeForValue(JSValue);
    102102    void invalidateCache();
     
    111111    bool doesTypeConformTo(uint32_t test) const;
    112112    uint32_t seenTypes() const { return m_seenTypes; }
     113    StructureSet structureSet() const { return m_structureSet; };
    113114
    114115private:
    115 
    116116    uint32_t m_seenTypes;
    117117    bool m_isOverflown;
    118118    Vector<RefPtr<StructureShape>> m_structureHistory;
    119     HashSet<StructureID> m_structureIDCache;
     119    StructureSet m_structureSet;
    120120};
    121121
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r173949 r174789  
    192192    , m_enabledProfiler(nullptr)
    193193    , m_builtinExecutables(BuiltinExecutables::create(*this))
    194     , m_nextUniqueVariableID(1)
    195194    , m_typeProfilerEnabledCount(0)
    196195{
     
    899898}
    900899
    901 TypeLocation* VM::nextTypeLocation()
    902 {
    903     RELEASE_ASSERT(!!m_typeLocationInfo);
    904 
    905     return m_typeLocationInfo->add();
    906 }
    907 
    908900bool VM::enableTypeProfiler()
    909901{
     
    912904        m_typeProfiler = std::make_unique<TypeProfiler>();
    913905        m_typeProfilerLog = std::make_unique<TypeProfilerLog>();
    914         m_typeLocationInfo = std::make_unique<Bag<TypeLocation>>();
    915906        needsToRecompile = true;
    916907    }
     
    929920        m_typeProfiler.reset(nullptr);
    930921        m_typeProfilerLog.reset(nullptr);
    931         m_typeLocationInfo.reset(nullptr);
    932922        needsToRecompile = true;
    933923    }
     
    942932
    943933    typeProfilerLog()->processLogEntries(ASCIILiteral("VM Dump Types"));
    944     TypeProfiler* profiler = m_typeProfiler.get();
    945     for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo->begin(); !!iter; ++iter) {
    946         TypeLocation* location = *iter;
    947         profiler->logTypesForTypeLocation(location);
    948     }
    949 }
    950 
    951 void VM::invalidateTypeSetCache()
    952 {
    953     RELEASE_ASSERT(typeProfiler());
    954 
    955     for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo->begin(); !!iter; ++iter) {
    956         TypeLocation* location = *iter;
    957         location->m_instructionTypeSet->invalidateCache();
    958         if (location->m_globalTypeSet)
    959             location->m_globalTypeSet->invalidateCache();
    960     }
     934    typeProfiler()->dumpTypeProfilerData();
    961935}
    962936
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r173304 r174789  
    4747#include "ThunkGenerators.h"
    4848#include "TypedArrayController.h"
    49 #include "TypeLocation.h"
    5049#include "VMEntryRecord.h"
    5150#include "Watchdog.h"
     
    516515    TypeProfilerLog* typeProfilerLog() { return m_typeProfilerLog.get(); }
    517516    TypeProfiler* typeProfiler() { return m_typeProfiler.get(); }
    518     TypeLocation* nextTypeLocation();
    519517    JS_EXPORT_PRIVATE void dumpTypeProfilerData();
    520     void invalidateTypeSetCache();
    521     GlobalVariableID getNextUniqueVariableID() { return m_nextUniqueVariableID++; }
    522518
    523519private:
     
    571567    std::unique_ptr<TypeProfiler> m_typeProfiler;
    572568    std::unique_ptr<TypeProfilerLog> m_typeProfilerLog;
    573     GlobalVariableID m_nextUniqueVariableID;
    574569    unsigned m_typeProfilerEnabledCount;
    575     std::unique_ptr<Bag<TypeLocation>> m_typeLocationInfo;
    576570};
    577571
  • trunk/Source/JavaScriptCore/tests/typeProfiler/dfg-jit-optimizations.js

    r174167 r174789  
    3737    }
    3838}
     39
     40function testStrucure(obj) { return obj; }
     41var obj = {x: 20};
     42tierUpToDFG(testStrucure, obj);
     43var types = findTypeForExpression(testStrucure, "obj");
     44assert(types.instructionTypeSet.structures.length === 1, "variable 'test' should have exactly structure");
     45assert(types.instructionTypeSet.structures[0].fields.length === 1, "variable 'test' should have exactly ONE field");
     46assert(types.instructionTypeSet.structures[0].fields.indexOf("x") !== -1, "variable 'test' should have field 'x'");
     47
     48testStrucure({x:20, y: 40})
     49types = findTypeForExpression(testStrucure, "obj");
     50assert(types.instructionTypeSet.structures.length === 1, "variable 'test' should have still have exactly one structure");
     51assert(types.instructionTypeSet.structures[0].fields.indexOf("x") !== -1, "variable 'test' should have field 'x'");
     52assert(types.instructionTypeSet.structures[0].optionalFields.indexOf("y") !== -1, "variable 'test' should have field optional field 'y'");
Note: See TracChangeset for help on using the changeset viewer.