Ignore:
Timestamp:
Jan 8, 2020, 10:07:29 PM (5 years ago)
Author:
[email protected]
Message:

[JSC] Introduce JSArrayIterator
https://bugs.webkit.org/show_bug.cgi?id=204043

Reviewed by Yusuke Suzuki.

JSTests:

  • stress/array-iterator-materialize-at-osr-exit.js: Added.

(shouldBe):
(test):

  • stress/array-iterator-materialize-one-path.js: Added.

(shouldBe):
(test):

  • stress/array-iterator-materialize.js: Added.

(shouldBe):
(test):

  • stress/array-iterator-sinking.js: Added.

(shouldBe):
(test):

  • stress/array-iterators-next-error-messages.js:

(catch):

  • stress/array-iterators-next-with-call.js:
  • stress/for-of-iteration.js: Added.

(shouldBe):
(test1):
(test2):
(test3):

  • stress/typedarray-functions-with-neutered.js:

(checkProtoFunc):

Source/JavaScriptCore:

This patch introduces JSArrayIterator that changes the iterator object
from a JSFinalObject to an InternalFieldsObject. This makes accessing it
much easier from C++ code and makes the iterator object smaller. It also
means that the JS code for the next function is much simpler and can *almost*
be inlined without shenanigans.

As part of this patch the keys/values/entries functions have been converted to
C++ with intrinsics since that's slightly more efficient in the LLInt/Baseline.

Lastly, this patch also add a custom ISOSubspace for JSArrayIterator objects.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • builtins/ArrayIteratorPrototype.js:

(next):
(globalPrivate.arrayIteratorNextHelper):
(globalPrivate.arrayIteratorValueNext): Deleted.
(globalPrivate.arrayIteratorKeyNext): Deleted.
(globalPrivate.arrayIteratorKeyValueNext): Deleted.

  • builtins/ArrayPrototype.js:

(globalPrivate.ArrayIterator): Deleted.
(values): Deleted.
(keys): Deleted.
(entries): Deleted.

  • builtins/TypedArrayPrototype.js:

(values): Deleted.
(keys): Deleted.
(entries): Deleted.

  • bytecode/BytecodeIntrinsicRegistry.cpp:

(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):

  • bytecode/BytecodeIntrinsicRegistry.h:
  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::emitIsArrayIterator):

  • bytecompiler/NodesCodegen.cpp:

(JSC::arrayIteratorInternalFieldIndex):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_getArrayIteratorInternalField):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_putArrayIteratorInternalField):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isGenerator): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isAsyncGenerator): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isJSArray): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isPromise): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isProxyObject): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isRegExpObject): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isObject): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isDerivedArray): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isMap): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isSet): Deleted.
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isUndefinedOrNull): Deleted.

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleIntrinsicCall):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGClobbersExitState.cpp:

(JSC::DFG::clobbersExitState):

  • dfg/DFGConstantFoldingPhase.cpp:

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

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGGraph.cpp:

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

  • dfg/DFGHeapLocation.cpp:

(WTF::printInternal):

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

(JSC::DFG::Node::convertToPhantomNewObject):
(JSC::DFG::Node::convertToPhantomNewArrayIterator):
(JSC::DFG::Node::convertToPhantomCreateActivation):
(JSC::DFG::Node::hasStructure):
(JSC::DFG::Node::hasObjectMaterializationData):
(JSC::DFG::Node::isPhantomAllocation):

  • dfg/DFGNodeType.h:
  • dfg/DFGObjectAllocationSinkingPhase.cpp:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGPromotedHeapLocation.cpp:

(WTF::printInternal):

  • dfg/DFGPromotedHeapLocation.h:

(JSC::DFG::PromotedLocationDescriptor::neededForMaterialization const):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileCheckNeutered):
(JSC::DFG::SpeculativeJIT::compileToObjectOrCallObjectConstructor):
(JSC::DFG::SpeculativeJIT::compileNewInternalFieldObject):
(JSC::DFG::SpeculativeJIT::compileNewArrayIterator):

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

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGStoreBarrierInsertionPhase.cpp:
  • dfg/DFGTypeCheckHoistingPhase.cpp:

(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):

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

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileToObjectOrCallObjectConstructor):
(JSC::FTL::DFG::LowerDFGToB3::compileCheckArray):
(JSC::FTL::DFG::LowerDFGToB3::compileCheckNeutered):
(JSC::FTL::DFG::LowerDFGToB3::compileNewInternalFieldObject):
(JSC::FTL::DFG::LowerDFGToB3::compileNewArrayIterator):
(JSC::FTL::DFG::LowerDFGToB3::compileCreateInternalFieldObject):
(JSC::FTL::DFG::LowerDFGToB3::compileMaterializeNewInternalFieldObjectImpl):
(JSC::FTL::DFG::LowerDFGToB3::compileMaterializeNewInternalFieldObject):

  • ftl/FTLOperations.cpp:

(JSC::FTL::operationPopulateObjectInOSR):
(JSC::FTL::operationMaterializeObjectInOSR):

  • inspector/JSInjectedScriptHost.cpp:

(Inspector::JSInjectedScriptHost::subtype):
(Inspector::JSInjectedScriptHost::getInternalProperties):
(Inspector::cloneArrayIteratorObject):
(Inspector::JSInjectedScriptHost::iteratorEntries):

  • runtime/ArrayPrototype.cpp:

(JSC::ArrayPrototype::finishCreation):
(JSC::createArrayIteratorObject):
(JSC::arrayProtoFuncValues):
(JSC::arrayProtoFuncEntries):
(JSC::arrayProtoFuncKeys):

  • runtime/CommonIdentifiers.h:
  • runtime/Intrinsic.cpp:

(JSC::intrinsicName):

  • runtime/Intrinsic.h:
  • runtime/IterationKind.h:

(): Deleted.

  • runtime/JSArrayIterator.cpp: Added.

(JSC::JSArrayIterator::create):
(JSC::JSArrayIterator::createWithInitialValues):
(JSC::JSArrayIterator::createStructure):
(JSC::JSArrayIterator::JSArrayIterator):
(JSC::JSArrayIterator::finishCreation):
(JSC::JSArrayIterator::visitChildren):

  • runtime/JSArrayIterator.h: Added.
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::arrayIteratorPrototype const):
(JSC::JSGlobalObject::arrayIteratorStructure const):

  • runtime/JSMapIterator.h:
  • runtime/JSSetIterator.h:
  • runtime/JSType.cpp:

(WTF::printInternal):

  • runtime/JSType.h:
  • runtime/JSTypedArrayViewPrototype.cpp:

(JSC::createTypedArrayIteratorObject):
(JSC::typedArrayViewProtoFuncValues):
(JSC::typedArrayProtoViewFuncEntries):
(JSC::typedArrayViewProtoFuncKeys):
(JSC::JSTypedArrayViewPrototype::finishCreation):

  • runtime/VM.cpp:
  • runtime/VM.h:

Source/WebCore:

JSDOMIterator should just use the JSC IterationKind enum. Also,
update other files for the enum member name changes.

  • bindings/js/JSDOMIterator.h:

(WebCore::IteratorTraits>::asJS):

  • bindings/js/SerializedScriptValue.cpp:

(WebCore::CloneSerializer::serialize):

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateIterableDefinition):

  • bindings/scripts/test/JS/JSTestInterface.cpp:

(WebCore::jsTestInterfacePrototypeFunctionEntriesCaller):
(WebCore::jsTestInterfacePrototypeFunctionKeysCaller):
(WebCore::jsTestInterfacePrototypeFunctionValuesCaller):

  • bindings/scripts/test/JS/JSTestIterable.cpp:

(WebCore::jsTestIterablePrototypeFunctionEntriesCaller):
(WebCore::jsTestIterablePrototypeFunctionKeysCaller):
(WebCore::jsTestIterablePrototypeFunctionValuesCaller):

  • bindings/scripts/test/JS/JSTestNode.cpp:

(WebCore::jsTestNodePrototypeFunctionEntriesCaller):
(WebCore::jsTestNodePrototypeFunctionKeysCaller):
(WebCore::jsTestNodePrototypeFunctionValuesCaller):

LayoutTests:

Change the labels of iteration kinds to match what JS refers to them as.

  • inspector/model/remote-object/iterator-expected.txt:
  • inspector/model/remote-object/iterator-large-expected.txt:
  • inspector/model/remote-object/iterators-mutated-expected.txt:
File:
1 edited

Legend:

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

    r254087 r254252  
    4141#include "DFGSSACalculator.h"
    4242#include "DFGValidate.h"
     43#include "JSArrayIterator.h"
    4344#include "JSCInlines.h"
    4445#include <wtf/StdList.h>
     
    141142    // replace any use of those pointers by the corresponding
    142143    // materialization
    143     enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction, AsyncGeneratorFunction, RegExpObject };
     144    enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction, AsyncGeneratorFunction, InternalFieldObject, RegExpObject };
    144145
    145146    using Fields = HashMap<PromotedLocationDescriptor, Node*>;
     
    246247    }
    247248
     249    bool isInternalFieldObjectAllocation() const
     250    {
     251        return m_kind == Kind::InternalFieldObject;
     252    }
     253
    248254    bool isRegExpObjectAllocation() const
    249255    {
     
    290296        case Kind::AsyncFunction:
    291297            out.print("AsyncFunction");
     298            break;
     299
     300        case Kind::InternalFieldObject:
     301            out.print("InternalFieldObject");
    292302            break;
    293303
     
    816826    }
    817827
     828    template<typename InternalFieldClass>
     829    Allocation* handleInternalFieldClass(Node* node, HashMap<PromotedLocationDescriptor, LazyNode>& writes)
     830    {
     831        Allocation* result = &m_heap.newAllocation(node, Allocation::Kind::InternalFieldObject);
     832        writes.add(StructurePLoc, LazyNode(m_graph.freeze(node->structure().get())));
     833        auto initialValues = InternalFieldClass::initialValues();
     834        static_assert(initialValues.size() == InternalFieldClass::numberOfInternalFields);       
     835        for (unsigned index = 0; index < initialValues.size(); ++index)
     836            writes.add(PromotedLocationDescriptor(InternalFieldObjectPLoc, index), LazyNode(m_graph.freeze(initialValues[index])));
     837
     838        return result;
     839    }
     840
    818841    template<typename WriteFunctor, typename ResolveFunctor>
    819842    void handleNode(
     
    857880            writes.add(FunctionExecutablePLoc, LazyNode(node->cellOperand()));
    858881            writes.add(FunctionActivationPLoc, LazyNode(node->child1().node()));
     882            break;
     883        }
     884
     885        case NewArrayIterator: {
     886            target = handleInternalFieldClass<JSArrayIterator>(node, writes);
    859887            break;
    860888        }
     
    10691097            }
    10701098            break;
     1099
     1100        case GetInternalField: {
     1101            target = m_heap.onlyLocalAllocation(node->child1().node());
     1102            if (target && target->isInternalFieldObjectAllocation())
     1103                exactRead = PromotedLocationDescriptor(InternalFieldObjectPLoc, node->internalFieldIndex());
     1104            else
     1105                m_heap.escape(node->child1().node());
     1106            break;
     1107        }
     1108
     1109        case PutInternalField: {
     1110            target = m_heap.onlyLocalAllocation(node->child1().node());
     1111            if (target && target->isInternalFieldObjectAllocation())
     1112                writes.add(PromotedLocationDescriptor(InternalFieldObjectPLoc, node->internalFieldIndex()), LazyNode(node->child2().node()));
     1113            else {
     1114                m_heap.escape(node->child1().node());
     1115                m_heap.escape(node->child2().node());
     1116            }
     1117            break;
     1118        }
    10711119
    10721120        case Check:
     
    15621610        }
    15631611
     1612        case Allocation::Kind::InternalFieldObject: {
     1613            ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add();
     1614            return m_graph.addNode(
     1615                allocation.identifier()->prediction(), Node::VarArg, MaterializeNewInternalFieldObject,
     1616                where->origin.withSemantic(
     1617                    allocation.identifier()->origin.semantic),
     1618                OpInfo(allocation.identifier()->structure()), OpInfo(data), 0, 0);
     1619        }
     1620
    15641621        case Allocation::Kind::Activation: {
    15651622            ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add();
     
    19472004                    case NewAsyncFunction:
    19482005                        node->convertToPhantomNewAsyncFunction();
     2006                        break;
     2007
     2008                    case NewArrayIterator:
     2009                        node->convertToPhantomNewArrayIterator();
    19492010                        break;
    19502011
     
    22252286        }
    22262287
     2288        case MaterializeNewInternalFieldObject: {
     2289            ObjectMaterializationData& data = node->objectMaterializationData();
     2290
     2291            unsigned firstChild = m_graph.m_varArgChildren.size();
     2292
     2293            Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);
     2294
     2295            PromotedHeapLocation structure(StructurePLoc, allocation.identifier());
     2296            ASSERT(locations.contains(structure));
     2297            m_graph.m_varArgChildren.append(Edge(resolve(block, structure), KnownCellUse));
     2298
     2299            for (PromotedHeapLocation location : locations) {
     2300                switch (location.kind()) {
     2301                case StructurePLoc: {
     2302                    ASSERT(location == structure);
     2303                    break;
     2304                }
     2305
     2306                case InternalFieldObjectPLoc: {
     2307                    ASSERT(location.base() == allocation.identifier());
     2308                    data.m_properties.append(location.descriptor());
     2309                    Node* value = resolve(block, location);
     2310                    if (m_sinkCandidates.contains(value))
     2311                        m_graph.m_varArgChildren.append(m_bottom);
     2312                    else
     2313                        m_graph.m_varArgChildren.append(value);
     2314                    break;
     2315                }
     2316
     2317                default:
     2318                    DFG_CRASH(m_graph, node, "Bad location kind");
     2319                }
     2320            }
     2321
     2322            node->children = AdjacencyList(
     2323                AdjacencyList::Variable,
     2324                firstChild, m_graph.m_varArgChildren.size() - firstChild);
     2325            break;
     2326        }
     2327
    22272328        case NewRegexp: {
    22282329            Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);
     
    23562457        }
    23572458
     2459        case InternalFieldObjectPLoc: {
     2460            return m_graph.addNode(
     2461                PutInternalField,
     2462                origin.takeValidExit(canExit),
     2463                OpInfo(location.info()),
     2464                Edge(base, KnownCellUse),
     2465                value->defaultEdge());
     2466        }
     2467
    23582468        case RegExpObjectLastIndexPLoc: {
    23592469            return m_graph.addNode(
Note: See TracChangeset for help on using the changeset viewer.