⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 201363 in webkit


Ignore:
Timestamp:
May 24, 2016, 4:49:57 PM (10 years ago)
Author:
keith_miller@apple.com
Message:

LLInt should be able to cache prototype loads for values in GetById
https://bugs.webkit.org/show_bug.cgi?id=158032

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This patch adds prototype value caching to the LLInt for op_get_by_id.
Two previously unused words in the op_get_by_id bytecode have been
repurposed to hold extra information for the cache. The first is a
counter that records the number of get_by_ids that hit a cacheable value
on a prototype. When the counter is decremented from one to zero we
attempt to cache the prototype load, which will be discussed further
below. The second word is used to hold the prototype object when we have
started caching.

When the counter is decremented to zero we first attempt to generate and
watch the property conditions needed to ensure the validity of prototype
load. If the watchpoints are successfully created and installed we
replace the op_get_by_id opcode with the new op_get_by_id_proto_load
opcode, which tells the LLInt to use the cache prototype object for the
load rather than the base value.

Prior to this patch there was not LLInt specific data onCodeBlocks.
Since the CodeBlock needs to own the Watchpoints for the cache, a weak
map from each base structure to a bag of Watchpoints created for that
structure by some op_get_by_id has been added to the CodeBlock. During
GC, if we find that the a structure in the map has not been marked we
free the associated bag on the CodeBlock.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/BytecodeList.json:
  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::printGetByIdOp):
(JSC::CodeBlock::printGetByIdCacheStatus):
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::finalizeLLIntInlineCaches):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::llintGetByIdWatchpointMap):
(JSC::clearLLIntGetByIdCache):

  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::computeFromLLInt):

  • bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp: Added.

(JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint):
(JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::install):
(JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::fireInternal):

  • bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h: Added.
  • bytecode/ObjectPropertyConditionSet.cpp:

(JSC::ObjectPropertyConditionSet::isValidAndWatchable):

  • bytecode/ObjectPropertyConditionSet.h:
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitGetById):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::setupGetByIdPrototypeCache):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LLIntSlowPaths.h:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/Options.h:
  • tests/stress/llint-get-by-id-cache-prototype-load-from-dictionary.js: Added.

(test):

Source/WTF:

Add move constructors/initializers to Bags.

  • wtf/Bag.h:

(WTF::Bag::Bag):
(WTF::Bag::operator=):

Location:
trunk/Source
Files:
3 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r201239 r201363  
    203203    bytecode/InlineCallFrameSet.cpp
    204204    bytecode/JumpTable.cpp
     205    bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp
    205206    bytecode/LazyOperandValueProfile.cpp
    206207    bytecode/MethodOfGettingAValueProfile.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r201361 r201363  
     12016-05-24  Keith Miller  <keith_miller@apple.com>
     2
     3        LLInt should be able to cache prototype loads for values in GetById
     4        https://bugs.webkit.org/show_bug.cgi?id=158032
     5
     6        Reviewed by Filip Pizlo.
     7
     8        This patch adds prototype value caching to the LLInt for op_get_by_id.
     9        Two previously unused words in the op_get_by_id bytecode have been
     10        repurposed to hold extra information for the cache. The first is a
     11        counter that records the number of get_by_ids that hit a cacheable value
     12        on a prototype. When the counter is decremented from one to zero we
     13        attempt to cache the prototype load, which will be discussed further
     14        below. The second word is used to hold the prototype object when we have
     15        started caching.
     16
     17        When the counter is decremented to zero we first attempt to generate and
     18        watch the property conditions needed to ensure the validity of prototype
     19        load. If the watchpoints are successfully created and installed we
     20        replace the op_get_by_id opcode with the new op_get_by_id_proto_load
     21        opcode, which tells the LLInt to use the cache prototype object for the
     22        load rather than the base value.
     23
     24        Prior to this patch there was not LLInt specific data onCodeBlocks.
     25        Since the CodeBlock needs to own the Watchpoints for the cache, a weak
     26        map from each base structure to a bag of Watchpoints created for that
     27        structure by some op_get_by_id has been added to the CodeBlock. During
     28        GC, if we find that the a structure in the map has not been marked we
     29        free the associated bag on the CodeBlock.
     30
     31        * JavaScriptCore.xcodeproj/project.pbxproj:
     32        * bytecode/BytecodeList.json:
     33        * bytecode/BytecodeUseDef.h:
     34        (JSC::computeUsesForBytecodeOffset):
     35        (JSC::computeDefsForBytecodeOffset):
     36        * bytecode/CodeBlock.cpp:
     37        (JSC::CodeBlock::printGetByIdOp):
     38        (JSC::CodeBlock::printGetByIdCacheStatus):
     39        (JSC::CodeBlock::dumpBytecode):
     40        (JSC::CodeBlock::finalizeLLIntInlineCaches):
     41        * bytecode/CodeBlock.h:
     42        (JSC::CodeBlock::llintGetByIdWatchpointMap):
     43        (JSC::clearLLIntGetByIdCache):
     44        * bytecode/GetByIdStatus.cpp:
     45        (JSC::GetByIdStatus::computeFromLLInt):
     46        * bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp: Added.
     47        (JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint):
     48        (JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::install):
     49        (JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::fireInternal):
     50        * bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h: Added.
     51        * bytecode/ObjectPropertyConditionSet.cpp:
     52        (JSC::ObjectPropertyConditionSet::isValidAndWatchable):
     53        * bytecode/ObjectPropertyConditionSet.h:
     54        * bytecompiler/BytecodeGenerator.cpp:
     55        (JSC::BytecodeGenerator::emitGetById):
     56        * dfg/DFGByteCodeParser.cpp:
     57        (JSC::DFG::ByteCodeParser::parseBlock):
     58        * dfg/DFGCapabilities.cpp:
     59        (JSC::DFG::capabilityLevel):
     60        * jit/JIT.cpp:
     61        (JSC::JIT::privateCompileMainPass):
     62        (JSC::JIT::privateCompileSlowCases):
     63        * llint/LLIntSlowPaths.cpp:
     64        (JSC::LLInt::setupGetByIdPrototypeCache):
     65        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
     66        * llint/LLIntSlowPaths.h:
     67        * llint/LowLevelInterpreter32_64.asm:
     68        * llint/LowLevelInterpreter64.asm:
     69        * runtime/Options.h:
     70        * tests/stress/llint-get-by-id-cache-prototype-load-from-dictionary.js: Added.
     71        (test):
     72
    1732016-05-24  Keith Miller  <keith_miller@apple.com>
    274
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r201239 r201363  
    11821182                53917E7B1B7906FA000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */; };
    11831183                53F6BF6D1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F6BF6C1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1184                53FA2AE11CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FA2AE01CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1185                53FA2AE31CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */; };
    11841186                5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; };
    11851187                5DBB151B131D0B310056AD36 /* testapi.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 14D857740A4696C80032146C /* testapi.js */; };
     
    33223324                53F256E11B87E28000B4B768 /* JSTypedArrayViewPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTypedArrayViewPrototype.cpp; sourceTree = "<group>"; };
    33233325                53F6BF6C1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InternalFunctionAllocationProfile.h; sourceTree = "<group>"; };
     3326                53FA2AE01CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntPrototypeLoadAdaptiveStructureWatchpoint.h; sourceTree = "<group>"; };
     3327                53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp; sourceTree = "<group>"; };
    33243328                593D43CCA0BBE06D89C59707 /* MapDataInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapDataInlines.h; sourceTree = "<group>"; };
    33253329                5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libedit.dylib; path = /usr/lib/libedit.dylib; sourceTree = "<absolute>"; };
     
    65766580                                0FB5467614F59AD1002C2989 /* LazyOperandValueProfile.h */,
    65776581                                0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */,
     6582                                53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */,
     6583                                53FA2AE01CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h */,
    65786584                                0FB5467C14F5CFD3002C2989 /* MethodOfGettingAValueProfile.cpp */,
    65796585                                0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */,
     
    79117917                                BC18C4550E16F5CD00B34460 /* PropertySlot.h in Headers */,
    79127918                                0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */,
     7919                                53FA2AE11CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h in Headers */,
    79137920                                BC18C4560E16F5CD00B34460 /* Protect.h in Headers */,
    79147921                                1474C33B16AA2D950062F01D /* PrototypeMap.h in Headers */,
     
    86368643                                65C0285C1717966800351E35 /* ARMv7DOpcode.cpp in Sources */,
    86378644                                0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */,
     8645                                53FA2AE31CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp in Sources */,
    86388646                                A7A8AF3417ADB5F3005AB174 /* ArrayBuffer.cpp in Sources */,
    86398647                                0FFC99D4184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp in Sources */,
  • trunk/Source/JavaScriptCore/bytecode/BytecodeList.json

    r201239 r201363  
    5959            { "name" : "op_is_function", "length" : 3 },
    6060            { "name" : "op_in", "length" : 4 },
    61             { "name" : "op_try_get_by_id", "length" : 4 },
     61            { "name" : "op_get_array_length", "length" : 9 },
    6262            { "name" : "op_get_by_id", "length" : 9  },
     63            { "name" : "op_get_by_id_proto_load", "length" : 9 },
    6364            { "name" : "op_get_by_id_with_this", "length" : 5 },
    6465            { "name" : "op_get_by_val_with_this", "length" : 5 },
    65             { "name" : "op_get_array_length", "length" : 9 },
     66            { "name" : "op_try_get_by_id", "length" : 4 },
    6667            { "name" : "op_put_by_id", "length" : 9 },
    6768            { "name" : "op_put_by_id_with_this", "length" : 5 },
  • trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h

    r201239 r201363  
    159159    case op_try_get_by_id:
    160160    case op_get_by_id:
     161    case op_get_by_id_proto_load:
    161162    case op_get_array_length:
    162163    case op_typeof:
     
    393394    case op_try_get_by_id:
    394395    case op_get_by_id:
     396    case op_get_by_id_proto_load:
    395397    case op_get_by_id_with_this:
    396398    case op_get_by_val_with_this:
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r201359 r201363  
    5151#include "JSModuleEnvironment.h"
    5252#include "LLIntEntrypoint.h"
     53#include "LLIntPrototypeLoadAdaptiveStructureWatchpoint.h"
    5354#include "LowLevelInterpreter.h"
    5455#include "JSCInlines.h"
     
    346347        op = "get_by_id";
    347348        break;
     349    case op_get_by_id_proto_load:
     350        op = "get_by_id_proto_load";
     351        break;
    348352    case op_get_array_length:
    349353        op = "array_length";
     
    406410        dumpStructure(out, "struct", structure, ident);
    407411        out.printf(")");
     412        if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_get_by_id_proto_load)
     413            out.printf(" proto(%p)", instruction[6].u.pointer);
    408414    }
    409415
     
    11131119        }
    11141120        case op_get_by_id:
     1121        case op_get_by_id_proto_load:
    11151122        case op_get_array_length: {
    11161123            printGetByIdOp(out, exec, location, it);
     
    27992806        Instruction* curInstruction = &instructions()[propertyAccessInstructions[i]];
    28002807        switch (interpreter->getOpcodeID(curInstruction[0].u.opcode)) {
    2801         case op_get_by_id: {
     2808        case op_get_by_id:
     2809        case op_get_by_id_proto_load: {
    28022810            StructureID oldStructureID = curInstruction[4].u.structureID;
    28032811            if (!oldStructureID || Heap::isMarked(m_vm->heap.structureIDTable().get(oldStructureID)))
     
    28052813            if (Options::verboseOSR())
    28062814                dataLogF("Clearing LLInt property access.\n");
    2807             curInstruction[4].u.structureID = 0;
    2808             curInstruction[5].u.operand = 0;
     2815            clearLLIntGetByIdCache(curInstruction);
    28092816            break;
    28102817        }
     
    28792886        }
    28802887    }
     2888
     2889    // We can't just remove all the sets when we clear the caches since we might have created a watchpoint set
     2890    // then cleared the cache without GCing in between.
     2891    m_llintGetByIdWatchpointMap.removeIf([](const StructureWatchpointMap::KeyValuePairType& pair) -> bool {
     2892        return !Heap::isMarked(pair.key);
     2893    });
    28812894
    28822895    for (unsigned i = 0; i < m_llintCallLinkInfos.size(); ++i) {
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r201180 r201363  
    5757#include "JumpTable.h"
    5858#include "LLIntCallLinkInfo.h"
     59#include "LLIntPrototypeLoadAdaptiveStructureWatchpoint.h"
    5960#include "LazyOperandValueProfile.h"
    6061#include "ObjectAllocationProfile.h"
     
    678679        return m_llintExecuteCounter;
    679680    }
     681
     682    typedef HashMap<Structure*, Bag<LLIntPrototypeLoadAdaptiveStructureWatchpoint>> StructureWatchpointMap;
     683    StructureWatchpointMap& llintGetByIdWatchpointMap() { return m_llintGetByIdWatchpointMap; }
    680684
    681685    // Functions for controlling when tiered compilation kicks in. This
     
    10201024    RefCountedArray<LLIntCallLinkInfo> m_llintCallLinkInfos;
    10211025    SentinelLinkedList<LLIntCallLinkInfo, BasicRawSentinelNode<LLIntCallLinkInfo>> m_incomingLLIntCalls;
     1026    StructureWatchpointMap m_llintGetByIdWatchpointMap;
    10221027    RefPtr<JITCode> m_jitCode;
    10231028#if ENABLE(JIT)
     
    13101315#endif
    13111316
     1317inline void clearLLIntGetByIdCache(Instruction* instruction)
     1318{
     1319    instruction[0].u.opcode = LLInt::getOpcode(op_get_by_id);
     1320    instruction[4].u.pointer = nullptr;
     1321    instruction[5].u.pointer = nullptr;
     1322    instruction[6].u.pointer = nullptr;
     1323}
     1324
    13121325inline Register& ExecState::r(int index)
    13131326{
  • trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp

    r199382 r201363  
    7676   
    7777    Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex;
    78    
    79     if (instruction[0].u.opcode == LLInt::getOpcode(op_get_array_length) || instruction[0].u.opcode == LLInt::getOpcode(op_try_get_by_id))
     78
     79    Opcode opcode = instruction[0].u.opcode;
     80
     81    // FIXME: We should not just bail if we see a try_get_by_id or a get_by_id_proto_load.
     82    // https://bugs.webkit.org/show_bug.cgi?id=158039
     83    if (opcode == LLInt::getOpcode(op_get_array_length) || opcode == LLInt::getOpcode(op_try_get_by_id) || opcode == LLInt::getOpcode(op_get_by_id_proto_load))
    8084        return GetByIdStatus(NoInformation, false);
    8185
  • trunk/Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp

    r197531 r201363  
    168168}
    169169
     170bool ObjectPropertyConditionSet::isValidAndWatchable() const
     171{
     172    if (!isValid())
     173        return false;
     174
     175    for (ObjectPropertyCondition condition : m_data->vector) {
     176        if (!condition.isWatchable())
     177            return false;
     178    }
     179    return true;
     180}
     181
    170182namespace {
    171183
     
    255267        // treated as a dictionary.
    256268        if (structure->isDictionary()) {
    257             if (concurrency == MainThread)
     269            if (concurrency == MainThread) {
     270                if (verbose)
     271                    dataLog("Flattening ", pointerDump(structure));
    258272                structure->flattenDictionaryStructure(vm, object);
    259             else {
     273            } else {
    260274                if (verbose)
    261275                    dataLog("Cannot flatten dictionary when not on main thread, so invalid.\n");
  • trunk/Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.h

    r197531 r201363  
    6868        return !m_data || !m_data->vector.isEmpty();
    6969    }
     70
     71    bool isValidAndWatchable() const;
    7072   
    7173    bool isEmpty() const
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r201239 r201363  
    24322432    instructions().append(0);
    24332433    instructions().append(0);
    2434     instructions().append(0);
     2434    instructions().append(Options::prototypeHitCountForLLIntCaching());
    24352435    instructions().append(profile);
    24362436    return dst;
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r201239 r201363  
    40824082
    40834083        case op_get_by_id:
     4084        case op_get_by_id_proto_load:
    40844085        case op_get_array_length: {
    40854086            SpeculatedType prediction = getPrediction();
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp

    r201239 r201363  
    155155    case op_try_get_by_id:
    156156    case op_get_by_id:
     157    case op_get_by_id_proto_load:
    157158    case op_get_by_id_with_this:
    158159    case op_get_by_val_with_this:
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r201239 r201363  
    241241        DEFINE_OP(op_try_get_by_id)
    242242        case op_get_array_length:
     243        case op_get_by_id_proto_load:
    243244        DEFINE_OP(op_get_by_id)
    244245        DEFINE_OP(op_get_by_id_with_this)
     
    423424        DEFINE_SLOWCASE_OP(op_try_get_by_id)
    424425        case op_get_array_length:
     426        case op_get_by_id_proto_load:
    425427        DEFINE_SLOWCASE_OP(op_get_by_id)
    426428        DEFINE_SLOWCASE_OP(op_get_by_val)
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r201239 r201363  
    5353#include "LowLevelInterpreter.h"
    5454#include "ObjectConstructor.h"
     55#include "ObjectPropertyConditionSet.h"
    5556#include "ProtoCallFrame.h"
    5657#include "ShadowChicken.h"
     
    581582}
    582583
     584static void setupGetByIdPrototypeCache(ExecState* exec, VM& vm, Instruction* pc, JSCell* baseCell, PropertySlot& slot, const Identifier& ident)
     585{
     586    CodeBlock* codeBlock = exec->codeBlock();
     587    Structure* structure = baseCell->structure();
     588
     589    if (structure->typeInfo().prohibitsPropertyCaching() || structure->isDictionary())
     590        return;
     591
     592    ObjectPropertyConditionSet conditions = generateConditionsForPrototypePropertyHit(vm, codeBlock, exec, structure, slot.slotBase(), ident.impl());
     593
     594    if (!conditions.isValid())
     595        return;
     596
     597    PropertyOffset offset = invalidOffset;
     598    CodeBlock::StructureWatchpointMap& watchpointMap = codeBlock->llintGetByIdWatchpointMap();
     599    auto result = watchpointMap.add(structure, Bag<LLIntPrototypeLoadAdaptiveStructureWatchpoint>());
     600    for (ObjectPropertyCondition condition : conditions) {
     601        if (!condition.isWatchable())
     602            return;
     603        if (condition.condition().kind() == PropertyCondition::Presence)
     604            offset = condition.condition().offset();
     605        result.iterator->value.add(condition, pc)->install();
     606    }
     607    ASSERT(offset != invalidOffset);
     608
     609    ConcurrentJITLocker locker(codeBlock->m_lock);
     610
     611    pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_proto_load);
     612    pc[4].u.structureID = structure->id();
     613    pc[5].u.operand = offset;
     614    // We know that this pointer will remain valid because it is the prototype of some structure, s,
     615    // watchpointed above. If any object with structure s were to change prototypes then the conditions
     616    // for this cache would fail and this value will never be used again.
     617    pc[6].u.pointer = slot.slotBase();
     618}
     619
     620
    583621LLINT_SLOW_PATH_DECL(slow_path_get_by_id)
    584622{
     
    595633    if (!LLINT_ALWAYS_ACCESS_SLOW
    596634        && baseValue.isCell()
    597         && slot.isCacheable()
    598         && slot.slotBase() == baseValue
    599635        && slot.isCacheableValue()) {
    600        
     636
    601637        JSCell* baseCell = baseValue.asCell();
    602638        Structure* structure = baseCell->structure();
     639        if (slot.slotBase() == baseValue) {
     640            // Start out by clearing out the old cache.
     641            pc[0].u.opcode = LLInt::getOpcode(op_get_by_id);
     642            pc[4].u.pointer = nullptr; // old structure
     643            pc[5].u.pointer = nullptr; // offset
     644
     645            // Prevent the prototype cache from ever happening.
     646            pc[7].u.operand = 0;
    603647       
    604         // Start out by clearing out the old cache.
    605         pc[0].u.opcode = LLInt::getOpcode(op_get_by_id);
    606         pc[4].u.pointer = nullptr; // old structure
    607         pc[5].u.pointer = nullptr; // offset
    608        
    609         if (!structure->isUncacheableDictionary()
    610             && !structure->typeInfo().prohibitsPropertyCaching()
    611             && !structure->typeInfo().newImpurePropertyFiresWatchpoints()) {
    612             vm.heap.writeBarrier(codeBlock);
    613            
    614             ConcurrentJITLocker locker(codeBlock->m_lock);
    615 
    616             pc[4].u.structureID = structure->id();
    617             pc[5].u.operand = slot.cachedOffset();
     648            if (structure->propertyAccessesAreCacheable()) {
     649                vm.heap.writeBarrier(codeBlock);
     650               
     651                ConcurrentJITLocker locker(codeBlock->m_lock);
     652
     653                pc[4].u.structureID = structure->id();
     654                pc[5].u.operand = slot.cachedOffset();
     655            }
     656        } else if (UNLIKELY(pc[7].u.operand)) {
     657            ASSERT(slot.slotBase() != baseValue);
     658
     659            if (!(--pc[7].u.operand))
     660                setupGetByIdPrototypeCache(exec, vm, pc, baseCell, slot, ident);
    618661        }
    619     }
    620 
    621     if (!LLINT_ALWAYS_ACCESS_SLOW
     662    } else if (!LLINT_ALWAYS_ACCESS_SLOW
    622663        && isJSArray(baseValue)
    623664        && ident == exec->propertyNames().length) {
     
    626667        arrayProfile->observeStructure(baseValue.asCell()->structure());
    627668        pc[4].u.arrayProfile = arrayProfile;
     669
     670        // Prevent the prototype cache from ever happening.
     671        pc[7].u.operand = 0;
    628672    }
    629673
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h

    r201239 r201363  
    7272LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_try_get_by_id);
    7373LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id);
     74LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_proto_load);
    7475LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_arguments_length);
    7576LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id);
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r200981 r201363  
    13351335
    13361336# We only do monomorphic get_by_id caching for now, and we do not modify the
    1337 # opcode. We do, however, allow for the cache to change anytime if fails, since
    1338 # ping-ponging is free. At best we get lucky and the get_by_id will continue
     1337# opcode for own properties. We also allow for the cache to change anytime it fails,
     1338# since ping-ponging is free. At best we get lucky and the get_by_id will continue
    13391339# to take fast path on the new cache. At worst we take slow path, which is what
    1340 # we would have been doing anyway.
     1340# we would have been doing anyway. For prototype properties, we will attempt to
     1341# convert opcode into a get_by_id_proto_load after a execution counter hits zero.
    13411342
    13421343_llint_op_get_by_id:
     
    13551356
    13561357.opGetByIdSlow:
     1358    callSlowPath(_llint_slow_path_get_by_id)
     1359    dispatch(9)
     1360
     1361
     1362
     1363_llint_op_get_by_id_proto_load:
     1364    traceExecution()
     1365    loadi 8[PC], t0
     1366    loadi 16[PC], t1
     1367    loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdProtoSlow)
     1368    loadi 20[PC], t2
     1369    bineq JSCell::m_structureID[t3], t1, .opGetByIdProtoSlow
     1370    loadpFromInstruction(6, t3)
     1371    loadPropertyAtVariableOffset(t2, t3, t0, t1)
     1372    loadi 4[PC], t2
     1373    storei t0, TagOffset[cfr, t2, 8]
     1374    storei t1, PayloadOffset[cfr, t2, 8]
     1375    valueProfile(t0, t1, 32, t2)
     1376    dispatch(9)
     1377
     1378.opGetByIdProtoSlow:
    13571379    callSlowPath(_llint_slow_path_get_by_id)
    13581380    dispatch(9)
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r201335 r201363  
    12331233
    12341234
     1235_llint_op_get_by_id_proto_load:
     1236    traceExecution()
     1237    loadisFromInstruction(2, t0)
     1238    loadConstantOrVariableCell(t0, t3, .opGetByIdProtoSlow)
     1239    loadi JSCell::m_structureID[t3], t1
     1240    loadisFromInstruction(4, t2)
     1241    bineq t2, t1, .opGetByIdProtoSlow
     1242    loadisFromInstruction(5, t1)
     1243    loadpFromInstruction(6, t3)
     1244    loadisFromInstruction(1, t2)
     1245    loadPropertyAtVariableOffset(t1, t3, t0)
     1246    storeq t0, [cfr, t2, 8]
     1247    valueProfile(t0, 8, t1)
     1248    dispatch(9)
     1249
     1250.opGetByIdProtoSlow:
     1251    callSlowPath(_llint_slow_path_get_by_id)
     1252    dispatch(9)
     1253
     1254
    12351255_llint_op_get_array_length:
    12361256    traceExecution()
  • trunk/Source/JavaScriptCore/runtime/Options.h

    r201361 r201363  
    363363    v(bool, useICStats, false, Normal, nullptr) \
    364364    \
     365    v(unsigned, prototypeHitCountForLLIntCaching, 2, Normal, "Number of prototype property hits before caching a prototype in the LLInt. A count of 0 means never cache.") \
     366    \
    365367    v(bool, dumpModuleRecord, false, Normal, nullptr) \
    366368    v(bool, dumpModuleLoadingState, false, Normal, nullptr) \
  • trunk/Source/WTF/ChangeLog

    r201333 r201363  
     12016-05-24  Keith Miller  <keith_miller@apple.com>
     2
     3        LLInt should be able to cache prototype loads for values in GetById
     4        https://bugs.webkit.org/show_bug.cgi?id=158032
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Add move constructors/initializers to Bags.
     9
     10        * wtf/Bag.h:
     11        (WTF::Bag::Bag):
     12        (WTF::Bag::operator=):
     13
    1142016-05-24  Chris Dumez  <cdumez@apple.com>
    215
  • trunk/Source/WTF/wtf/Bag.h

    r195339 r201363  
    4949public:
    5050    Bag()
    51         : m_head(nullptr)
    5251    {
     52    }
     53
     54    Bag(Bag<T>&& other)
     55    {
     56        ASSERT(!m_head);
     57        m_head = other.m_head;
     58        other.m_head = nullptr;
     59    }
     60
     61    Bag& operator=(Bag<T>&& other)
     62    {
     63        m_head = other.m_head;
     64        other.m_head = nullptr;
     65        return *this;
    5366    }
    5467   
     
    122135   
    123136private:
    124     Node* m_head;
     137    Node* m_head { nullptr };
    125138};
    126139
Note: See TracChangeset for help on using the changeset viewer.