Ignore:
Timestamp:
Oct 28, 2012, 9:02:08 PM (13 years ago)
Author:
[email protected]
Message:

DFG should be able to emit effectful structure checks
https://bugs.webkit.org/show_bug.cgi?id=99260

Reviewed by Oliver Hunt.

This change allows us to find out if an array access that has gone polymorphic
is operating over known structures - i.e. the primordial array structures of the
global object that the code block containing the array access belongs to. We
term this state "OriginalArray" for short. The fact that the access has gone
polymorphic means that the array profile will not be able to report the set of
structures it had seen - but if it can tell us that all of the structures were
primordial then it just so happens that we can deduce what the structure set
would have been by just querying the code block's global object. This allows us
to emit an ArrayifyToStructure instead of an Arrayify if we find that we need to
do conversions. The fast path of an ArrayifyToStructure is exactly like the fast
path of a CheckStructure and is mostly subject to the same optimizations. It
also burns one fewer registers.

Essentially the notion of OriginalArray is a super cheap way of getting the
array profile to tell us a structure set instead of a singleton structure.
Currently, the array profile can only tell us the structure seen at an array
access if there was exactly one structure. If there were multiple structures, it
won't tell us anything other than the array modes and other auxiliary profiling
data (whether there were stores to holes, for example). With OriginalArray, we
cheaply get a structure set if all of the structures were primordial for the
code block's global object, since in that case the array mode set (ArrayModes)
can directly tell us the structure set. In the future, we might consider adding
complete structure sets to the array profiles, but I suspect that we would hit
diminishing returns if we did so - it would only help if we have array accesses
that are both polymorphic and are cross-global-object accesses (rare) or if the
arrays had named properties or other structure transitions that are unrelated to
indexing type (also rare).

This also does away with Arrayify (and the new ArrayifyToStructure) returning
the butterfly pointer. This turns out to be faster and easier to CSE.

And, this also changes constant folding to be able to eliminate CheckStructure,
ForwardCheckStructure, and ArrayifyToStructure in addition to being able to
transform them into structure transition watchpoints. This is great for
ArrayifyToStructure because then CSE and CFA know that there is no side effect.
Converting CheckStructure and ForwardCheckStructure to also behave this way is
just a matter of elegance.

This has no performance impact right now. It's intended to alleviate some of the
regressions seen in the early implementation of
https://bugs.webkit.org/show_bug.cgi?id=98606.

  • bytecode/ArrayProfile.cpp:

(JSC::ArrayProfile::computeUpdatedPrediction):

  • bytecode/ArrayProfile.h:

(JSC):
(JSC::ArrayProfile::ArrayProfile):
(ArrayProfile):
(JSC::ArrayProfile::usesOriginalArrayStructures):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::updateAllPredictionsAndCountLiveness):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):

  • dfg/DFGArrayMode.cpp:

(JSC::DFG::ArrayMode::fromObserved):
(JSC::DFG::ArrayMode::alreadyChecked):
(JSC::DFG::arrayClassToString):

  • dfg/DFGArrayMode.h:

(JSC::DFG::ArrayMode::withProfile):
(JSC::DFG::ArrayMode::isJSArray):
(ArrayMode):
(JSC::DFG::ArrayMode::isJSArrayWithOriginalStructure):
(JSC::DFG::ArrayMode::supportsLength):
(JSC::DFG::ArrayMode::arrayModesWithIndexingShape):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::getArrayMode):
(JSC::DFG::ByteCodeParser::getArrayModeAndEmitChecks):
(JSC::DFG::ByteCodeParser::handleGetByOffset):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::checkStructureElimination):
(JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
(JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
(JSC::DFG::CSEPhase::checkArrayElimination):
(JSC::DFG::CSEPhase::getScopeRegistersLoadElimination):

  • dfg/DFGConstantFoldingPhase.cpp:

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

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasStructure):
(JSC::DFG::Node::hasArrayMode):
(JSC::DFG::Node::arrayMode):

  • dfg/DFGNodeType.h:

(DFG):

  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode):
(JSC::DFG::SpeculativeJIT::arrayify):

  • dfg/DFGSpeculativeJIT.h:

(SpeculativeJIT):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::isOriginalArrayStructure):

  • runtime/Structure.cpp:

(JSC::Structure::nonPropertyTransition):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp

    r132745 r132759  
    4343        return ArrayMode(Array::SelectUsingPredictions);
    4444    case asArrayModes(NonArrayWithContiguous):
    45         return ArrayMode(Array::Contiguous, Array::NonArray, Array::AsIs).withSpeculation(profile, makeSafe);
     45        return ArrayMode(Array::Contiguous, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
    4646    case asArrayModes(ArrayWithContiguous):
    47         return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withSpeculation(profile, makeSafe);
     47        return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
    4848    case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous):
    49         return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withSpeculation(profile, makeSafe);
     49        return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
    5050    case asArrayModes(NonArrayWithArrayStorage):
    51         return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::AsIs).withSpeculation(profile, makeSafe);
     51        return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
    5252    case asArrayModes(NonArrayWithSlowPutArrayStorage):
    5353    case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage):
    54         return ArrayMode(Array::SlowPutArrayStorage, Array::NonArray, Array::AsIs).withSpeculation(profile, makeSafe);
     54        return ArrayMode(Array::SlowPutArrayStorage, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
    5555    case asArrayModes(ArrayWithArrayStorage):
    56         return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs).withSpeculation(profile, makeSafe);
     56        return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
    5757    case asArrayModes(ArrayWithSlowPutArrayStorage):
    5858    case asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
    59         return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs).withSpeculation(profile, makeSafe);
     59        return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
    6060    case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage):
    61         return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs).withSpeculation(profile, makeSafe);
     61        return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
    6262    case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
    6363    case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
    64         return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withSpeculation(profile, makeSafe);
     64        return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
    6565    case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage):
    66         return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::Convert).withSpeculation(profile, makeSafe);
     66        return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::Convert).withProfile(profile, makeSafe);
    6767    case asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage):
    68         return ArrayMode(Array::ArrayStorage, Array::Array, Array::Convert).withSpeculation(profile, makeSafe);
     68        return ArrayMode(Array::ArrayStorage, Array::Array, Array::Convert).withProfile(profile, makeSafe);
    6969    case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage):
    70         return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::Convert).withSpeculation(profile, makeSafe);
     70        return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::Convert).withProfile(profile, makeSafe);
    7171    case asArrayModes(NonArray) | asArrayModes(NonArrayWithContiguous):
    7272        if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
     
    163163       
    164164    case Array::Contiguous:
    165         if (arrayClass() == Array::Array) {
     165        if (isJSArray()) {
    166166            if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithContiguous)))
    167167                return true;
     
    176176       
    177177    case Array::ArrayStorage:
    178         if (arrayClass() == Array::Array) {
     178        if (isJSArray()) {
    179179            if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage)))
    180180                return true;
     
    189189       
    190190    case Array::SlowPutArrayStorage:
    191         if (arrayClass() == Array::Array) {
     191        if (isJSArray()) {
    192192            if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
    193193                return true;
     
    293293    case Array::Array:
    294294        return "Array";
     295    case Array::OriginalArray:
     296        return "OriginalArray";
    295297    case Array::NonArray:
    296298        return "NonArray";
Note: See TracChangeset for help on using the changeset viewer.