Ignore:
Timestamp:
Jul 24, 2013, 8:58:47 PM (12 years ago)
Author:
[email protected]
Message:

fourthTier: value profiles and array profiles should be thread-safe enough to be accessible in a concurrent compilation thread
https://bugs.webkit.org/show_bug.cgi?id=114906

Source/JavaScriptCore:

Reviewed by Oliver Hunt.

This introduces thread safety to value profiles, array profiles, and
array allocation profiles.

We already have three separate operations that happen on profiles:
(1) writing, which the JIT, LLInt, and OSR exit do; (2) updating,
which happens during GC, from OSR entry slow-paths, and in the DFG;
and (3) reading, which happens in the DFG. For example, the JIT/LLInt
and OSR exit write to ValueProfile::m_buckets, which gets synthesized
into ValueProfile::m_prediction (and other fields) during update, and
the latter gets read by the DFG. Note that (2) must also happen in
the DFG since only the DFG knows which code blocks it will inline,
and those blocks' profiles may not have otherwise been updated via
any other mechanism.

I refer to these three operations as writing, updating, and reading.

Consequently, both profile updating and profile reading may happen
asynchronously, if the JIT is asynchronous.

The locking protocol for profiles works as follows:

  • Writing does not require locking, but is only allowed on the main thread. We require that these fields can be stored atomically by the profiling code, even without locks. For value profiles, this only works on 64-bit platforms, currently. For array profiles, which consist of multiple separate fields, this means that an asynchronous update of the profile may see slight inconsistencies (like a structure that doesn't quite match the array modes bits), but these should be harmless: at worst, the DFG will specialize too much and we'll have OSR exits.
  • Updating a value profile requires holding a lock, but must assume that the fields written by the profiling code in JIT/LLInt may be written to without locking.
  • Reading a value profile requires holding a lock.

The one major exception to these rules is the ArrayAllocationProfile,
which requires no locking. We do this because it's used so often and
in places where we don't necessarily have access to the owning
CodeBlock, so if we did want it to be locked it would have to have
its own lock. Also, I believe that it is sound to just make this
profile racy and not worry about locking at all. All that was needed
were some changes to ensure that we explicitly read some raced-over
fields only once.

Two additional interesting things in this change:

  • To make it easy to see which profile methods require locking, they take a const CodeBlockLocker& as an argument. I saw this idiom for identifying which methods require which locks to be held being used in LLVM, and I quite like it.
  • Lazy operand value profiles, which are created lazily and at any time, require the CodeBlockLock to be held when they are being created. Writes to them are lockless and main-thread-only, but as with other profiles, updates and reads require locking.
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/ArrayAllocationProfile.cpp:

(JSC::ArrayAllocationProfile::updateIndexingType):

  • bytecode/ArrayAllocationProfile.h:

(JSC::ArrayAllocationProfile::selectIndexingType):

  • bytecode/ArrayProfile.cpp:

(JSC::ArrayProfile::computeUpdatedPrediction):
(JSC::ArrayProfile::briefDescription):

  • bytecode/ArrayProfile.h:

(ArrayProfile):
(JSC::ArrayProfile::expectedStructure):
(JSC::ArrayProfile::structureIsPolymorphic):
(JSC::ArrayProfile::hasDefiniteStructure):
(JSC::ArrayProfile::observedArrayModes):
(JSC::ArrayProfile::mayInterceptIndexedAccesses):
(JSC::ArrayProfile::mayStoreToHole):
(JSC::ArrayProfile::outOfBounds):
(JSC::ArrayProfile::usesOriginalArrayStructures):

  • bytecode/CallLinkStatus.cpp:

(JSC::CallLinkStatus::computeFor):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpValueProfiling):
(JSC::CodeBlock::dumpArrayProfiling):
(JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
(JSC::CodeBlock::updateAllArrayPredictions):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::valueProfilePredictionForBytecodeOffset):
(JSC::CodeBlock::updateAllPredictionsAndCheckIfShouldOptimizeNow):
(CodeBlock):

  • bytecode/CodeBlockLock.h: Added.

(JSC):

  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::computeFor):

  • bytecode/LazyOperandValueProfile.cpp:

(JSC::CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions):
(JSC::CompressedLazyOperandValueProfileHolder::add):
(JSC::LazyOperandValueProfileParser::LazyOperandValueProfileParser):
(JSC::LazyOperandValueProfileParser::~LazyOperandValueProfileParser):
(JSC):
(JSC::LazyOperandValueProfileParser::initialize):
(JSC::LazyOperandValueProfileParser::prediction):

  • bytecode/LazyOperandValueProfile.h:

(CompressedLazyOperandValueProfileHolder):
(LazyOperandValueProfileParser):

  • bytecode/MethodOfGettingAValueProfile.cpp:

(JSC::MethodOfGettingAValueProfile::getSpecFailBucket):

  • bytecode/PutByIdStatus.cpp:

(JSC::PutByIdStatus::computeFor):

  • bytecode/ResolveGlobalStatus.cpp:

(JSC::ResolveGlobalStatus::computeFor):

  • bytecode/ValueProfile.h:

(JSC::ValueProfileBase::briefDescription):
(ValueProfileBase):
(JSC::ValueProfileBase::computeUpdatedPrediction):

  • dfg/DFGArrayMode.cpp:

(JSC::DFG::ArrayMode::fromObserved):

  • dfg/DFGArrayMode.h:

(ArrayMode):
(JSC::DFG::ArrayMode::withProfile):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::injectLazyOperandSpeculation):
(JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
(JSC::DFG::ByteCodeParser::getArrayMode):
(JSC::DFG::ByteCodeParser::getArrayModeAndEmitChecks):
(JSC::DFG::ByteCodeParser::parseResolveOperations):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGOSRExitPreparation.cpp:

(JSC::DFG::prepareCodeOriginForOSRExit):

  • dfg/DFGPredictionInjectionPhase.cpp:

(JSC::DFG::PredictionInjectionPhase::run):

  • jit/JITInlines.h:

(JSC::JIT::chooseArrayMode):

  • jit/JITStubs.cpp:

(JSC::tryCachePutByID):
(JSC::tryCacheGetByID):
(JSC::DEFINE_STUB_FUNCTION):
(JSC::lazyLinkFor):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):
(JSC::LLInt::setUpCall):

  • profiler/ProfilerBytecodeSequence.cpp:

(JSC::Profiler::BytecodeSequence::BytecodeSequence):

  • runtime/JSScope.cpp:

(JSC::JSScope::resolveContainingScopeInternal):
(JSC::JSScope::resolvePut):

Source/WTF:

Reviewed by Oliver Hunt.

Add ability to abstract whether or not the CodeBlock requires locking at all,
since some platforms may not support the byte spin-locking and/or may not want
to, if they turn off concurrent JIT.

  • WTF.xcodeproj/project.pbxproj:
  • wtf/ByteSpinLock.h:
  • wtf/NoLock.h: Added.

(WTF):
(NoLock):
(WTF::NoLock::lock):
(WTF::NoLock::unlock):
(WTF::NoLock::isHeld):

  • wtf/Platform.h:
File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/CodeBlockLock.h

    r153122 r153123  
    11/*
    2  * Copyright (C) 2012 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #include "config.h"
    27 #include "ArrayAllocationProfile.h"
     26#ifndef CodeBlockLock_h
     27#define CodeBlockLock_h
    2828
    29 #include "Operations.h"
     29#include <wtf/ByteSpinLock.h>
     30#include <wtf/NoLock.h>
    3031
    3132namespace JSC {
    3233
    33 void ArrayAllocationProfile::updateIndexingType()
    34 {
    35     if (!m_lastArray)
    36         return;
    37     m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, m_lastArray->structure()->indexingType());
    38     m_lastArray = 0;
    39 }
     34#if ENABLE(CONCURRENT_JIT)
     35typedef ByteSpinLock CodeBlockLock;
     36typedef ByteSpinLocker CodeBlockLocker;
     37#else
     38typedef NoLock CodeBlockLock;
     39typedef NoLockLocker CodeBlockLocker;
     40#endif
    4041
    4142} // namespace JSC
    4243
     44#endif // CodeBlockLock_h
     45
Note: See TracChangeset for help on using the changeset viewer.