Ignore:
Timestamp:
May 18, 2018, 10:29:56 AM (7 years ago)
Author:
[email protected]
Message:

JSC should have InstanceOf inline caching
https://bugs.webkit.org/show_bug.cgi?id=185652

Reviewed by Saam Barati.
JSTests:

  • microbenchmarks/instanceof-always-hit-one.js: Added.
  • microbenchmarks/instanceof-always-hit-two.js: Added.
  • microbenchmarks/instanceof-dynamic.js: Added.
  • microbenchmarks/instanceof-sometimes-hit.js: Added.
  • stress/instanceof-dynamic-proxy-check-structure.js: Added.
  • stress/instanceof-dynamic-proxy-loop.js: Added.
  • stress/instanceof-dynamic-proxy.js: Added.
  • stress/instanceof-hit-one-object-then-another.js: Added.
  • stress/instanceof-hit-two-objects-then-another.js: Added.
  • stress/instanceof-prototype-change.js: Added.
  • stress/instanceof-prototype-change-to-hit.js: Added.
  • stress/instanceof-prototype-change-to-null.js: Added.
  • stress/instanceof-prototype-change-watchpointable.js: Added.

Source/JavaScriptCore:


This adds a polymorphic inline cache for instanceof. It caches hits and misses. It uses the
existing PolymorphicAccess IC machinery along with all of its heuristics. If we ever generate
too many cases, we emit the generic instanceof implementation instead.

All of the JIT tiers use the same InstanceOf IC. It uses the existing JITInlineCacheGenerator
abstraction.

This is a ~40% speed-up on instanceof microbenchmarks. It's a *tiny* (~1%) speed-up on
Octane/boyer. I think I can make that speed-up bigger by inlining the inline cache.

  • API/tests/testapi.mm:

(testObjectiveCAPIMain):

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • b3/B3Effects.h:

(JSC::B3::Effects::forReadOnlyCall):

  • bytecode/AccessCase.cpp:

(JSC::AccessCase::guardedByStructureCheck const):
(JSC::AccessCase::canReplace const):
(JSC::AccessCase::visitWeak const):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generateImpl):

  • bytecode/AccessCase.h:
  • bytecode/InstanceOfAccessCase.cpp: Added.

(JSC::InstanceOfAccessCase::create):
(JSC::InstanceOfAccessCase::dumpImpl const):
(JSC::InstanceOfAccessCase::clone const):
(JSC::InstanceOfAccessCase::~InstanceOfAccessCase):
(JSC::InstanceOfAccessCase::InstanceOfAccessCase):

  • bytecode/InstanceOfAccessCase.h: Added.

(JSC::InstanceOfAccessCase::prototype const):

  • bytecode/ObjectPropertyCondition.h:

(JSC::ObjectPropertyCondition::hasPrototypeWithoutBarrier):
(JSC::ObjectPropertyCondition::hasPrototype):

  • bytecode/ObjectPropertyConditionSet.cpp:

(JSC::generateConditionsForInstanceOf):

  • bytecode/ObjectPropertyConditionSet.h:
  • bytecode/PolymorphicAccess.cpp:

(JSC::PolymorphicAccess::addCases):
(JSC::PolymorphicAccess::regenerate):
(WTF::printInternal):

  • bytecode/PropertyCondition.cpp:

(JSC::PropertyCondition::dumpInContext const):
(JSC::PropertyCondition::isStillValidAssumingImpurePropertyWatchpoint const):
(JSC::PropertyCondition::validityRequiresImpurePropertyWatchpoint const):
(WTF::printInternal):

  • bytecode/PropertyCondition.h:

(JSC::PropertyCondition::absenceWithoutBarrier):
(JSC::PropertyCondition::absenceOfSetEffectWithoutBarrier):
(JSC::PropertyCondition::hasPrototypeWithoutBarrier):
(JSC::PropertyCondition::hasPrototype):
(JSC::PropertyCondition::hasPrototype const):
(JSC::PropertyCondition::prototype const):
(JSC::PropertyCondition::hash const):
(JSC::PropertyCondition::operator== const):

  • bytecode/StructureStubInfo.cpp:

(JSC::StructureStubInfo::StructureStubInfo):
(JSC::StructureStubInfo::reset):

  • bytecode/StructureStubInfo.h:

(JSC::StructureStubInfo::considerCaching):

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGInlineCacheWrapper.h:
  • dfg/DFGInlineCacheWrapperInlines.h:

(JSC::DFG::InlineCacheWrapper<GeneratorType>::finalize):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::link):

  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::addInstanceOf):

  • dfg/DFGOperations.cpp:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::usedRegisters):
(JSC::DFG::SpeculativeJIT::compileInstanceOfForCells):
(JSC::DFG::SpeculativeJIT::compileInstanceOf):
(JSC::DFG::SpeculativeJIT::compileInstanceOfForObject): Deleted.

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedGetByIdWithThis):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileAssertNotEmpty):
(JSC::FTL::DFG::LowerDFGToB3::compilePutById):
(JSC::FTL::DFG::LowerDFGToB3::compileNumberIsInteger):
(JSC::FTL::DFG::LowerDFGToB3::compileIn):
(JSC::FTL::DFG::LowerDFGToB3::compileInstanceOf):
(JSC::FTL::DFG::LowerDFGToB3::getById):
(JSC::FTL::DFG::LowerDFGToB3::getByIdWithThis):

  • jit/ICStats.h:
  • jit/JIT.cpp:

(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::link):

  • jit/JIT.h:
  • jit/JITInlineCacheGenerator.cpp:

(JSC::JITInlineCacheGenerator::JITInlineCacheGenerator):
(JSC::JITInlineCacheGenerator::finalize):
(JSC::JITByIdGenerator::JITByIdGenerator):
(JSC::JITByIdGenerator::finalize):
(JSC::JITInstanceOfGenerator::JITInstanceOfGenerator):
(JSC::JITInstanceOfGenerator::generateFastPath):
(JSC::JITInstanceOfGenerator::finalize):

  • jit/JITInlineCacheGenerator.h:

(JSC::JITInlineCacheGenerator::reportSlowPathCall):
(JSC::JITInlineCacheGenerator::slowPathBegin const):
(JSC::JITInstanceOfGenerator::JITInstanceOfGenerator):
(JSC::finalizeInlineCaches):
(JSC::JITByIdGenerator::reportSlowPathCall): Deleted.
(JSC::JITByIdGenerator::slowPathBegin const): Deleted.

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_instanceof):
(JSC::JIT::emitSlow_op_instanceof):

  • jit/JITOperations.cpp:
  • jit/JITOperations.h:
  • jit/JITPropertyAccess.cpp:

(JSC::JIT::privateCompileGetByValWithCachedId):
(JSC::JIT::privateCompilePutByValWithCachedId):

  • jit/RegisterSet.cpp:

(JSC::RegisterSet::stubUnavailableRegisters):

  • jit/Repatch.cpp:

(JSC::tryCacheIn):
(JSC::tryCacheInstanceOf):
(JSC::repatchInstanceOf):
(JSC::resetPatchableJump):
(JSC::resetIn):
(JSC::resetInstanceOf):

  • jit/Repatch.h:
  • runtime/Options.h:
  • runtime/Structure.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/PropertyCondition.cpp

    r223161 r231961  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4444    }
    4545   
    46     out.print(m_kind, " of ", m_uid);
    4746    switch (m_kind) {
    4847    case Presence:
    49         out.print(" at ", offset(), " with attributes ", attributes());
     48        out.print(m_kind, " of ", m_uid, " at ", offset(), " with attributes ", attributes());
    5049        return;
    5150    case Absence:
    5251    case AbsenceOfSetEffect:
    53         out.print(" with prototype ", inContext(JSValue(prototype()), context));
     52        out.print(m_kind, " of ", m_uid, " with prototype ", inContext(JSValue(prototype()), context));
    5453        return;
    5554    case Equivalence:
    56         out.print(" with ", inContext(requiredValue(), context));
     55        out.print(m_kind, " of ", m_uid, " with ", inContext(requiredValue(), context));
     56        return;
     57    case HasPrototype:
     58        out.print(m_kind, " with prototype ", inContext(JSValue(prototype()), context));
    5759        return;
    5860    }
     
    7981        return false;
    8082    }
    81    
    82     if (!structure->propertyAccessesAreCacheable()) {
    83         if (PropertyConditionInternal::verbose)
    84             dataLog("Invalid because accesses are not cacheable.\n");
    85         return false;
     83
     84    switch (m_kind) {
     85    case Presence:
     86    case Absence:
     87    case AbsenceOfSetEffect:
     88    case Equivalence:
     89        if (!structure->propertyAccessesAreCacheable()) {
     90            if (PropertyConditionInternal::verbose)
     91                dataLog("Invalid because property accesses are not cacheable.\n");
     92            return false;
     93        }
     94        break;
     95       
     96    case HasPrototype:
     97        if (!structure->prototypeQueriesAreCacheable()) {
     98            if (PropertyConditionInternal::verbose)
     99                dataLog("Invalid because prototype queries are not cacheable.\n");
     100            return false;
     101        }
     102        break;
    86103    }
    87104   
     
    175192    }
    176193       
     194    case HasPrototype: {
     195        if (structure->hasPolyProto()) {
     196            // FIXME: I think this is too conservative. We can probably prove this if
     197            // we have the base. Anyways, we should make this work when integrating
     198            // OPC and poly proto.
     199            // https://bugs.webkit.org/show_bug.cgi?id=177339
     200            return false;
     201        }
     202
     203        if (structure->storedPrototypeObject() != prototype()) {
     204            if (PropertyConditionInternal::verbose) {
     205                dataLog(
     206                    "Invalid because the prototype is ", structure->storedPrototype(), " even though "
     207                    "it should have been ", JSValue(prototype()), "\n");
     208            }
     209            return false;
     210        }
     211       
     212        return true;
     213    }
     214       
    177215    case Equivalence: {
    178216        if (!base || base->structure() != structure) {
     
    227265    case Equivalence:
    228266        return structure->needImpurePropertyWatchpoint();
    229     default:
    230         return false;
    231     }
     267    case AbsenceOfSetEffect:
     268    case HasPrototype:
     269        return false;
     270    }
     271   
     272    RELEASE_ASSERT_NOT_REACHED();
     273    return false;
    232274}
    233275
     
    376418        out.print("Equivalence");
    377419        return;
     420    case JSC::PropertyCondition::HasPrototype:
     421        out.print("HasPrototype");
     422        return;
    378423    }
    379424    RELEASE_ASSERT_NOT_REACHED();
Note: See TracChangeset for help on using the changeset viewer.