Ignore:
Timestamp:
Nov 19, 2019, 9:53:38 PM (6 years ago)
Author:
[email protected]
Message:

GetByVal should use polymorphic access and hook into a status object
https://bugs.webkit.org/show_bug.cgi?id=202767

Reviewed by Keith Miller.

This patch puts get_by_val in our normal IC caching infrastructure. This means
building it on top of StructureStubInfo and PolymorphicAccess. For this to
work, AccessCase now supports all the array load variants that we used to have
fast paths for. For identifier based variants, it we just fall back to the
code we've already implemented, but only after doing a runtime check that
the identifier matches the expected identifier. This allows us to reuse all
the IC infrastructure we have for get_by_id.

Our compilation strategy is that the baseline JIT always emits a get_by_val
IC. If that IC goes to the slow path, the DFG/FTL won't also emit the same IC,
since it's probable that we're seeing a megamorphic switch over strings. This
was needed to keep this patch neutral on Speedometer 2. It's likely there is
room to improve this heuristic: https://bugs.webkit.org/show_bug.cgi?id=204336

This now allows us to have inline caches which contain array loads, and uses
of different identifiers. They just show up as different access cases inside
polymorphic access.

This patch is a progression on various microbenchmarks, especially those with
uses of a fixed set of multiple identifiers. It's neutral on JetStream 2 and
Speedometer 2.

This patch also hooks in get_by_val ICs to our ICStatus infrastructure. This
is going to pave the way to allow us to eagerly throw away baseline code, since
when we go for an FTL compile, we will be able to use the IC status from the
prior compile without relying on baseline specific data structures.

There are a few interesting tidbits in this patch that are worth
highlighting.

  • Unlike get_by_id, when we take an IC snapshot for a get_by_val

IC, we're not guaranteed the various identifiers in question will outlive
the compile (get_by_id ensures this since they're in the constant pool of
CodeBlock). For get_by_val, the Identifiers in question are dynamic fields
of AccessCase, and AccessCase may get destroyed as we're compiling concurrently.
Also, String's reference counting isn't thread safe, so we can't just ref it.
Instead, we use a Box<Identifier> inside AccessCase. This allows us to safely
ref the Box without refing the underlying String. We're not worried about the
Box being destroyed while we're doing this, since we're holding a lock while
taking an IC snapshot inside GetByStatus.

  • We no longer hold onto the actual JS symbol object in the inline cache.

This is what we used to do for inlining by val infos. Instead, this patch
extends the CheckStringIdent node to be able to handle symbols as well. This
patch also renames CheckStringIdent to CheckIdent.

This patch also renames various IC related helpers from GetById* to GetBy*,
since they can both be used by get_by_val and get_by_id.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • bytecode/AccessCase.cpp:

(JSC::AccessCase::AccessCase):
(JSC::AccessCase::create):
(JSC::AccessCase::fromStructureStubInfo):
(JSC::AccessCase::commit):
(JSC::AccessCase::guardedByStructureCheck const):
(JSC::AccessCase::guardedByStructureCheckSkippingConstantIdentifierCheck const):
(JSC::AccessCase::requiresIdentifierNameMatch const):
(JSC::AccessCase::requiresInt32PropertyCheck const):
(JSC::AccessCase::needsScratchFPR const):
(JSC::AccessCase::forEachDependentCell const):
(JSC::AccessCase::doesCalls const):
(JSC::AccessCase::canReplace const):
(JSC::AccessCase::dump const):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generate):
(JSC::AccessCase::generateImpl):
(JSC::AccessCase::toTypedArrayType):
(JSC::AccessCase::checkConsistency):

  • bytecode/AccessCase.h:

(JSC::AccessCase::uid const):
(JSC::AccessCase::identifier const):
(JSC::AccessCase::checkConsistency):
(JSC::AccessCase::AccessCase):

  • bytecode/GetByIdStatus.cpp: Removed.
  • bytecode/GetByIdStatus.h: Removed.
  • bytecode/GetByIdVariant.cpp:

(JSC::GetByIdVariant::GetByIdVariant):
(JSC::GetByIdVariant::operator=):
(JSC::GetByIdVariant::attemptToMerge):

  • bytecode/GetByIdVariant.h:

(JSC::GetByIdVariant::domAttribute const):
(JSC::GetByIdVariant::identifier const):

  • bytecode/GetByStatus.cpp: Copied from Source/JavaScriptCore/bytecode/GetByIdStatus.cpp.

(JSC::GetByStatus::appendVariant):
(JSC::GetByStatus::computeFromLLInt):
(JSC::GetByStatus::computeFor):
(JSC::GetByStatus::GetByStatus):
(JSC::GetByStatus::computeForStubInfoWithoutExitSiteFeedback):
(JSC::GetByStatus::makesCalls const):
(JSC::GetByStatus::slowVersion const):
(JSC::GetByStatus::merge):
(JSC::GetByStatus::filter):
(JSC::GetByStatus::markIfCheap):
(JSC::GetByStatus::finalize):
(JSC::GetByStatus::singleIdentifier const):
(JSC::GetByStatus::dump const):
(JSC::GetByIdStatus::appendVariant): Deleted.
(JSC::GetByIdStatus::computeFromLLInt): Deleted.
(JSC::GetByIdStatus::computeFor): Deleted.
(JSC::GetByIdStatus::computeForStubInfo): Deleted.
(JSC::GetByIdStatus::GetByIdStatus): Deleted.
(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback): Deleted.
(JSC::GetByIdStatus::makesCalls const): Deleted.
(JSC::GetByIdStatus::slowVersion const): Deleted.
(JSC::GetByIdStatus::merge): Deleted.
(JSC::GetByIdStatus::filter): Deleted.
(JSC::GetByIdStatus::markIfCheap): Deleted.
(JSC::GetByIdStatus::finalize): Deleted.
(JSC::GetByIdStatus::dump const): Deleted.

  • bytecode/GetByStatus.h: Copied from Source/JavaScriptCore/bytecode/GetByIdStatus.h.

(JSC::GetByStatus::GetByStatus):
(JSC::GetByStatus::moduleNamespaceObject const):
(JSC::GetByStatus::moduleEnvironment const):
(JSC::GetByStatus::scopeOffset const):
(JSC::GetByIdStatus::GetByIdStatus): Deleted.
(JSC::GetByIdStatus::state const): Deleted.
(JSC::GetByIdStatus::isSet const): Deleted.
(JSC::GetByIdStatus::operator bool const): Deleted.
(JSC::GetByIdStatus::isSimple const): Deleted.
(JSC::GetByIdStatus::isCustom const): Deleted.
(JSC::GetByIdStatus::isModuleNamespace const): Deleted.
(JSC::GetByIdStatus::numVariants const): Deleted.
(JSC::GetByIdStatus::variants const): Deleted.
(JSC::GetByIdStatus::at const): Deleted.
(JSC::GetByIdStatus::operator[] const): Deleted.
(JSC::GetByIdStatus::takesSlowPath const): Deleted.
(JSC::GetByIdStatus::wasSeenInJIT const): Deleted.
(JSC::GetByIdStatus::moduleNamespaceObject const): Deleted.
(JSC::GetByIdStatus::moduleEnvironment const): Deleted.
(JSC::GetByIdStatus::scopeOffset const): Deleted.

  • bytecode/GetterSetterAccessCase.cpp:

(JSC::GetterSetterAccessCase::GetterSetterAccessCase):
(JSC::GetterSetterAccessCase::create):

  • bytecode/GetterSetterAccessCase.h:
  • bytecode/ICStatusMap.h:
  • bytecode/InByIdStatus.cpp:

(JSC::InByIdStatus::computeForStubInfoWithoutExitSiteFeedback):

  • bytecode/InlineAccess.cpp:

(JSC::InlineAccess::generateSelfPropertyAccess):
(JSC::InlineAccess::canGenerateSelfPropertyReplace):
(JSC::InlineAccess::generateSelfPropertyReplace):
(JSC::InlineAccess::isCacheableArrayLength):
(JSC::InlineAccess::generateArrayLength):
(JSC::InlineAccess::isCacheableStringLength):
(JSC::InlineAccess::generateStringLength):
(JSC::InlineAccess::generateSelfInAccess):

  • bytecode/InstanceOfAccessCase.cpp:

(JSC::InstanceOfAccessCase::InstanceOfAccessCase):

  • bytecode/InstanceOfStatus.cpp:

(JSC::InstanceOfStatus::computeForStubInfo):

  • bytecode/IntrinsicGetterAccessCase.cpp:

(JSC::IntrinsicGetterAccessCase::IntrinsicGetterAccessCase):
(JSC::IntrinsicGetterAccessCase::create):

  • bytecode/IntrinsicGetterAccessCase.h:
  • bytecode/ModuleNamespaceAccessCase.cpp:

(JSC::ModuleNamespaceAccessCase::ModuleNamespaceAccessCase):
(JSC::ModuleNamespaceAccessCase::create):

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

(JSC::AccessGenerationState::preserveLiveRegistersToStackForCall):
(JSC::PolymorphicAccess::addCases):
(JSC::PolymorphicAccess::addCase):
(JSC::PolymorphicAccess::commit):
(JSC::PolymorphicAccess::regenerate):
(WTF::printInternal):

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

(JSC::ProxyableAccessCase::ProxyableAccessCase):
(JSC::ProxyableAccessCase::create):

  • bytecode/ProxyableAccessCase.h:
  • bytecode/PutByIdStatus.cpp:

(JSC::PutByIdStatus::computeForStubInfo):

  • bytecode/RecordedStatuses.cpp:

(JSC::RecordedStatuses::addGetByStatus):
(JSC::RecordedStatuses::addGetByIdStatus): Deleted.

  • bytecode/RecordedStatuses.h:
  • bytecode/StructureStubInfo.cpp:

(JSC::StructureStubInfo::StructureStubInfo):
(JSC::StructureStubInfo::initGetByIdSelf):
(JSC::StructureStubInfo::initArrayLength):
(JSC::StructureStubInfo::initStringLength):
(JSC::StructureStubInfo::initPutByIdReplace):
(JSC::StructureStubInfo::initInByIdSelf):
(JSC::StructureStubInfo::deref):
(JSC::StructureStubInfo::aboutToDie):
(JSC::StructureStubInfo::addAccessCase):
(JSC::StructureStubInfo::reset):
(JSC::StructureStubInfo::visitWeakReferences):
(JSC::StructureStubInfo::propagateTransitions):
(JSC::StructureStubInfo::summary const):
(JSC::StructureStubInfo::containsPC const):
(JSC::StructureStubInfo::setCacheType):
(JSC::StructureStubInfo::checkConsistency):

  • bytecode/StructureStubInfo.h:

(JSC::StructureStubInfo::getByIdSelfIdentifier):
(JSC::StructureStubInfo::thisValueIsInThisGPR const):
(JSC::StructureStubInfo::checkConsistency):
(JSC::StructureStubInfo::cacheType const):
(JSC::appropriateOptimizingGetByIdFunction):
(JSC::appropriateGenericGetByIdFunction):

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGArgumentsEliminationPhase.cpp:
  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleDOMJITGetter):
(JSC::DFG::ByteCodeParser::handleModuleNamespaceLoad):
(JSC::DFG::ByteCodeParser::load):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::parseGetById):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::handlePutByVal):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGClobbersExitState.cpp:

(JSC::DFG::clobbersExitState):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):

  • dfg/DFGDesiredIdentifiers.cpp:

(JSC::DFG::DesiredIdentifiers::processCodeBlockIdentifiersIfNeeded):
(JSC::DFG::DesiredIdentifiers::ensure):
(JSC::DFG::DesiredIdentifiers::at const):
(JSC::DFG::DesiredIdentifiers::reallyAdd):

  • dfg/DFGDesiredIdentifiers.h:
  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):

  • dfg/DFGGraph.h:
  • dfg/DFGInPlaceAbstractState.cpp:
  • dfg/DFGJITCompiler.cpp:

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

  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::addGetByVal):

  • dfg/DFGMayExit.cpp:
  • dfg/DFGNode.h:

(JSC::DFG::Node::hasUidOperand):
(JSC::DFG::Node::hasGetByStatus):
(JSC::DFG::Node::getByStatus):
(JSC::DFG::Node::hasGetByIdStatus): Deleted.
(JSC::DFG::Node::getByIdStatus): Deleted.

  • dfg/DFGNodeType.h:
  • dfg/DFGObjectAllocationSinkingPhase.cpp:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileGetById):
(JSC::DFG::SpeculativeJIT::compileCheckIdent):
(JSC::DFG::SpeculativeJIT::compileCheckStringIdent): Deleted.

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

(JSC::DFG::SpeculativeJIT::cachedGetByIdWithThis):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::cachedGetByIdWithThis):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGVarargsForwardingPhase.cpp:
  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCheckIdent):
(JSC::FTL::DFG::LowerDFGToB3::compileGetById):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
(JSC::FTL::DFG::LowerDFGToB3::getByIdWithThis):
(JSC::FTL::DFG::LowerDFGToB3::compileCheckStringIdent): Deleted.

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

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

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

(JSC::garbageStubInfo):
(JSC::JITGetByIdWithThisGenerator::JITGetByIdWithThisGenerator):
(JSC::JITInstanceOfGenerator::JITInstanceOfGenerator):
(JSC::JITGetByValGenerator::JITGetByValGenerator):
(JSC::JITGetByValGenerator::generateFastPath):
(JSC::JITGetByValGenerator::finalize):

  • jit/JITInlineCacheGenerator.h:

(JSC::JITGetByValGenerator::JITGetByValGenerator):
(JSC::JITGetByValGenerator::slowPathJump const):

  • jit/JITInlines.h:

(JSC::JIT::emitDoubleGetByVal): Deleted.
(JSC::JIT::emitContiguousGetByVal): Deleted.
(JSC::JIT::emitArrayStorageGetByVal): Deleted.

  • jit/JITOperations.cpp:

(JSC::getByVal):
(JSC::tryGetByValOptimize): Deleted.

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

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_try_get_by_id):
(JSC::JIT::emit_op_get_by_id_direct):
(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emit_op_get_by_id_with_this):
(JSC::JIT::emitGetByValWithCachedId): Deleted.
(JSC::JIT::privateCompileGetByVal): Deleted.
(JSC::JIT::privateCompileGetByValWithCachedId): Deleted.
(JSC::JIT::emitDirectArgumentsGetByVal): Deleted.
(JSC::JIT::emitScopedArgumentsGetByVal): Deleted.
(JSC::JIT::emitIntTypedArrayGetByVal): Deleted.
(JSC::JIT::emitFloatTypedArrayGetByVal): Deleted.

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_try_get_by_id):
(JSC::JIT::emit_op_get_by_id_direct):
(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emit_op_get_by_id_with_this):
(JSC::JIT::emitGetByValWithCachedId): Deleted.

  • jit/Repatch.cpp:

(JSC::appropriateOptimizingGetByFunction):
(JSC::appropriateGetByFunction):
(JSC::tryCacheGetBy):
(JSC::repatchGetBy):
(JSC::tryCacheArrayGetByVal):
(JSC::repatchArrayGetByVal):
(JSC::tryCachePutByID):
(JSC::tryCacheInByID):
(JSC::tryCacheInstanceOf):
(JSC::resetGetBy):
(JSC::appropriateOptimizingGetByIdFunction): Deleted.
(JSC::appropriateGetByIdFunction): Deleted.
(JSC::tryCacheGetByID): Deleted.
(JSC::repatchGetByID): Deleted.
(JSC::resetGetByID): Deleted.

  • jit/Repatch.h:
  • llint/LowLevelInterpreter.h:
  • runtime/DOMAnnotation.h:
  • runtime/JSCJSValue.cpp:

(JSC::JSValue::dumpInContextAssumingStructure const):

  • runtime/Structure.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r252422 r252684  
    206206    CodeBlock* codeBlock = callFrame->codeBlock();
    207207    if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()) && !slot.isTaintedByOpaqueObject() && (slot.isCacheableValue() || slot.isCacheableGetter() || slot.isUnset()))
    208         repatchGetByID(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByIDKind::Try);
     208        repatchGetBy(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByKind::Try);
    209209
    210210    return JSValue::encode(slot.getPureResult());
     
    262262    CodeBlock* codeBlock = callFrame->codeBlock();
    263263    if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()))
    264         repatchGetByID(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByIDKind::Direct);
     264        repatchGetBy(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByKind::Direct);
    265265
    266266    RELEASE_AND_RETURN(scope, JSValue::encode(found ? slot.getValue(globalObject, ident) : jsUndefined()));
     
    322322        CodeBlock* codeBlock = callFrame->codeBlock();
    323323        if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()))
    324             repatchGetByID(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByIDKind::Normal);
     324            repatchGetBy(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByKind::Normal);
    325325        return found ? slot.getValue(globalObject, ident) : jsUndefined();
    326326    }));
     
    379379        CodeBlock* codeBlock = callFrame->codeBlock();
    380380        if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()))
    381             repatchGetByID(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByIDKind::WithThis);
     381            repatchGetBy(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByKind::WithThis);
    382382        return found ? slot.getValue(globalObject, ident) : jsUndefined();
    383383    }));
     
    19201920}
    19211921
    1922 static JSValue getByVal(JSGlobalObject* globalObject, CallFrame* callFrame, JSValue baseValue, JSValue subscript, ByValInfo* byValInfo, ReturnAddressPtr returnAddress)
     1922ALWAYS_INLINE static JSValue getByVal(JSGlobalObject* globalObject, CallFrame* callFrame, ArrayProfile* arrayProfile, JSValue baseValue, JSValue subscript)
    19231923{
    19241924    UNUSED_PARAM(callFrame);
     
    19341934                if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomString.get())) {
    19351935                    ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
    1936                     if (byValInfo->stubInfo && byValInfo->cachedId.impl() != existingAtomString)
    1937                         byValInfo->tookSlowPath = true;
    19381936                    return result;
    19391937                }
     
    19431941
    19441942    if (subscript.isInt32()) {
    1945         ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
    1946         byValInfo->tookSlowPath = true;
    1947 
    19481943        int32_t i = subscript.asInt32();
    19491944        if (isJSString(baseValue)) {
    1950             if (i >= 0 && asString(baseValue)->canGetIndex(i)) {
    1951                 ctiPatchCallByReturnAddress(returnAddress, operationGetByValString);
     1945            if (i >= 0 && asString(baseValue)->canGetIndex(i))
    19521946                RELEASE_AND_RETURN(scope, asString(baseValue)->getIndex(globalObject, i));
    1953             }
    1954             byValInfo->arrayProfile->setOutOfBounds();
     1947            if (arrayProfile)
     1948                arrayProfile->setOutOfBounds();
    19551949        } else if (baseValue.isObject()) {
    19561950            JSObject* object = asObject(baseValue);
     
    19711965                // out-of-bounds.
    19721966                // https://bugs.webkit.org/show_bug.cgi?id=149886
    1973                 byValInfo->arrayProfile->setOutOfBounds();
     1967                if (arrayProfile)
     1968                    arrayProfile->setOutOfBounds();
    19741969            }
    19751970        }
     
    19851980
    19861981    ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
    1987     if (byValInfo->stubInfo && (!isStringOrSymbol(subscript) || byValInfo->cachedId != property))
    1988         byValInfo->tookSlowPath = true;
    1989 
    19901982    RELEASE_AND_RETURN(scope, baseValue.get(globalObject, property));
    19911983}
    19921984
    1993 static OptimizationResult tryGetByValOptimize(JSGlobalObject* globalObject, CallFrame* callFrame, JSValue baseValue, JSValue subscript, ByValInfo* byValInfo, ReturnAddressPtr returnAddress)
    1994 {
    1995     // See if it's worth optimizing this at all.
    1996     OptimizationResult optimizationResult = OptimizationResult::NotOptimized;
    1997 
    1998     VM& vm = globalObject->vm();
    1999     auto scope = DECLARE_THROW_SCOPE(vm);
    2000 
    2001     if (baseValue.isObject() && subscript.isInt32()) {
    2002         JSObject* object = asObject(baseValue);
    2003 
    2004         ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
    2005         ASSERT(!byValInfo->stubRoutine);
    2006 
    2007         if (hasOptimizableIndexing(object->structure(vm))) {
    2008             // Attempt to optimize.
    2009             Structure* structure = object->structure(vm);
    2010             JITArrayMode arrayMode = jitArrayModeForStructure(structure);
    2011             if (arrayMode != byValInfo->arrayMode) {
    2012                 // If we reached this case, we got an interesting array mode we did not expect when we compiled.
    2013                 // Let's update the profile to do better next time.
    2014                 CodeBlock* codeBlock = callFrame->codeBlock();
    2015                 ConcurrentJSLocker locker(codeBlock->m_lock);
    2016                 byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
    2017 
    2018                 JIT::compileGetByVal(locker, vm, codeBlock, byValInfo, returnAddress, arrayMode);
    2019                 optimizationResult = OptimizationResult::Optimized;
    2020             }
    2021         }
    2022 
    2023         // If we failed to patch and we have some object that intercepts indexed get, then don't even wait until 10 times.
    2024         if (optimizationResult != OptimizationResult::Optimized && object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero())
    2025             optimizationResult = OptimizationResult::GiveUp;
    2026     }
    2027 
    2028     if (baseValue.isObject() && isStringOrSymbol(subscript)) {
    2029         const Identifier propertyName = subscript.toPropertyKey(globalObject);
    2030         RETURN_IF_EXCEPTION(scope, OptimizationResult::GiveUp);
    2031         if (subscript.isSymbol() || !parseIndex(propertyName)) {
    2032             ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
    2033             ASSERT(!byValInfo->stubRoutine);
    2034             if (byValInfo->seen) {
    2035                 if (byValInfo->cachedId == propertyName) {
    2036                     JIT::compileGetByValWithCachedId(vm, callFrame->codeBlock(), byValInfo, returnAddress, propertyName);
    2037                     optimizationResult = OptimizationResult::Optimized;
    2038                 } else {
    2039                     // Seem like a generic property access site.
    2040                     optimizationResult = OptimizationResult::GiveUp;
    2041                 }
    2042             } else {
    2043                 CodeBlock* codeBlock = callFrame->codeBlock();
    2044                 ConcurrentJSLocker locker(codeBlock->m_lock);
    2045                 byValInfo->seen = true;
    2046                 byValInfo->cachedId = propertyName;
    2047                 if (subscript.isSymbol())
    2048                     byValInfo->cachedSymbol.set(vm, codeBlock, asSymbol(subscript));
    2049                 optimizationResult = OptimizationResult::SeenOnce;
    2050             }
    2051         }
    2052     }
    2053 
    2054     if (optimizationResult != OptimizationResult::Optimized && optimizationResult != OptimizationResult::SeenOnce) {
    2055         // If we take slow path more than 10 times without patching then make sure we
    2056         // never make that mistake again. For cases where we see non-index-intercepting
    2057         // objects, this gives 10 iterations worth of opportunity for us to observe
    2058         // that the get_by_val may be polymorphic. We count up slowPathCount even if
    2059         // the result is GiveUp.
    2060         if (++byValInfo->slowPathCount >= 10)
    2061             optimizationResult = OptimizationResult::GiveUp;
    2062     }
    2063 
    2064     return optimizationResult;
    2065 }
    2066 
    20671985extern "C" {
    20681986
    2069 EncodedJSValue JIT_OPERATION operationGetByValGeneric(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
     1987EncodedJSValue JIT_OPERATION operationGetByValGeneric(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, ArrayProfile* profile, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
    20701988{
    20711989    VM& vm = globalObject->vm();
     
    20751993    JSValue subscript = JSValue::decode(encodedSubscript);
    20761994
    2077     JSValue result = getByVal(globalObject, callFrame, baseValue, subscript, byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS));
    2078     return JSValue::encode(result);
    2079 }
    2080 
    2081 EncodedJSValue JIT_OPERATION operationGetByValOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
     1995    stubInfo->tookSlowPath = true;
     1996
     1997    return JSValue::encode(getByVal(globalObject, callFrame, profile, baseValue, subscript));
     1998}
     1999
     2000EncodedJSValue JIT_OPERATION operationGetByValOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, ArrayProfile* profile, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
    20822001{
    20832002    VM& vm = globalObject->vm();
     
    20882007    JSValue baseValue = JSValue::decode(encodedBase);
    20892008    JSValue subscript = JSValue::decode(encodedSubscript);
    2090     ReturnAddressPtr returnAddress = ReturnAddressPtr(OUR_RETURN_ADDRESS);
    2091     OptimizationResult result = tryGetByValOptimize(globalObject, callFrame, baseValue, subscript, byValInfo, returnAddress);
    2092     RETURN_IF_EXCEPTION(scope, { });
    2093     if (result == OptimizationResult::GiveUp) {
    2094         // Don't ever try to optimize.
    2095         byValInfo->tookSlowPath = true;
    2096         ctiPatchCallByReturnAddress(returnAddress, operationGetByValGeneric);
    2097     }
    2098 
    2099     RELEASE_AND_RETURN(scope, JSValue::encode(getByVal(globalObject, callFrame, baseValue, subscript, byValInfo, returnAddress)));
     2009
     2010    if (baseValue.isCell() && subscript.isInt32()) {
     2011        if (stubInfo->considerCaching(vm, callFrame->codeBlock(), baseValue.structureOrNull()))
     2012            repatchArrayGetByVal(globalObject, callFrame->codeBlock(), baseValue, subscript, *stubInfo);
     2013    }
     2014
     2015    if (baseValue.isCell() && isStringOrSymbol(subscript)) {
     2016        const Identifier propertyName = subscript.toPropertyKey(globalObject);
     2017        RETURN_IF_EXCEPTION(scope, encodedJSValue());
     2018        if (subscript.isSymbol() || !parseIndex(propertyName)) {
     2019            scope.release();
     2020            return JSValue::encode(baseValue.getPropertySlot(globalObject, propertyName, [&] (bool found, PropertySlot& slot) -> JSValue {
     2021                LOG_IC((ICEvent::OperationGetByValOptimize, baseValue.classInfoOrNull(vm), propertyName, baseValue == slot.slotBase()));
     2022               
     2023                CodeBlock* codeBlock = callFrame->codeBlock();
     2024                if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()))
     2025                    repatchGetBy(globalObject, codeBlock, baseValue, propertyName, slot, *stubInfo, GetByKind::NormalByVal);
     2026                return found ? slot.getValue(globalObject, propertyName) : jsUndefined();
     2027            }));
     2028        }
     2029    }
     2030
     2031    RELEASE_AND_RETURN(scope, JSValue::encode(getByVal(globalObject, callFrame, profile, baseValue, subscript)));
    21002032}
    21012033
     
    21692101}
    21702102   
    2171 EncodedJSValue JIT_OPERATION operationGetByValString(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
    2172 {
    2173     VM& vm = globalObject->vm();
    2174     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
    2175     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
    2176     auto scope = DECLARE_THROW_SCOPE(vm);
    2177     JSValue baseValue = JSValue::decode(encodedBase);
    2178     JSValue subscript = JSValue::decode(encodedSubscript);
    2179    
    2180     JSValue result;
    2181     if (LIKELY(subscript.isUInt32())) {
    2182         uint32_t i = subscript.asUInt32();
    2183         if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
    2184             RELEASE_AND_RETURN(scope, JSValue::encode(asString(baseValue)->getIndex(globalObject, i)));
    2185 
    2186         result = baseValue.get(globalObject, i);
    2187         RETURN_IF_EXCEPTION(scope, encodedJSValue());
    2188         if (!isJSString(baseValue)) {
    2189             ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
    2190             auto getByValFunction = byValInfo->stubRoutine ? operationGetByValGeneric : operationGetByValOptimize;
    2191             ctiPatchCallByReturnAddress(ReturnAddressPtr(OUR_RETURN_ADDRESS), getByValFunction);
    2192         }
    2193     } else {
    2194         baseValue.requireObjectCoercible(globalObject);
    2195         RETURN_IF_EXCEPTION(scope, encodedJSValue());
    2196         auto property = subscript.toPropertyKey(globalObject);
    2197         RETURN_IF_EXCEPTION(scope, encodedJSValue());
    2198         scope.release();
    2199         result = baseValue.get(globalObject, property);
    2200     }
    2201 
    2202     return JSValue::encode(result);
    2203 }
    2204 
    22052103static bool deleteById(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, JSValue base, UniquedStringImpl* uid)
    22062104{
Note: See TracChangeset for help on using the changeset viewer.