|  | /* | 
|  | * Copyright (C) 2014-2016 Apple Inc. All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | * 1. Redistributions of source code must retain the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer. | 
|  | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer in the | 
|  | *    documentation and/or other materials provided with the distribution. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
|  | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|  | * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
|  | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
|  | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
|  | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
|  | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
|  | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "DFGStructureRegistrationPhase.h" | 
|  |  | 
|  | #if ENABLE(DFG_JIT) | 
|  |  | 
|  | #include "DFGBasicBlockInlines.h" | 
|  | #include "DFGGraph.h" | 
|  | #include "DFGPhase.h" | 
|  | #include "JSCInlines.h" | 
|  |  | 
|  | namespace JSC { namespace DFG { | 
|  |  | 
|  | class StructureRegistrationPhase : public Phase { | 
|  | public: | 
|  | StructureRegistrationPhase(Graph& graph) | 
|  | : Phase(graph, "structure registration") | 
|  | { | 
|  | } | 
|  |  | 
|  | bool run() | 
|  | { | 
|  | // FIXME: This phase shouldn't exist. We should have registered all structures by now, since | 
|  | // we may already have done optimizations that rely on structures having been registered. | 
|  | // Currently, we still have places where we don't register structures prior to this phase, | 
|  | // but structures don't end up being used for optimization prior to this phase. That's a | 
|  | // pretty fragile situation and we should fix it eventually. | 
|  | // https://bugs.webkit.org/show_bug.cgi?id=147889 | 
|  |  | 
|  | // We need to set this before this phase finishes. This phase doesn't do anything | 
|  | // conditioned on this field, except for assertIsRegistered() below. We intend for that | 
|  | // method to behave as if the phase was already finished. So, we set this up here. | 
|  | m_graph.m_structureRegistrationState = AllStructuresAreRegistered; | 
|  |  | 
|  | // These are pretty dumb, but needed to placate subsequent assertions. We don't actually | 
|  | // have to watch these because there is no way to transition away from it, but they are | 
|  | // watchable and so we will assert if they aren't watched. | 
|  | registerStructure(m_graph.m_vm.structureStructure.get()); | 
|  | registerStructure(m_graph.m_vm.stringStructure.get()); | 
|  | registerStructure(m_graph.m_vm.symbolStructure.get()); | 
|  |  | 
|  | for (FrozenValue* value : m_graph.m_frozenValues) | 
|  | assertIsRegistered(value->structure()); | 
|  |  | 
|  | for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { | 
|  | BasicBlock* block = m_graph.block(blockIndex); | 
|  | if (!block) | 
|  | continue; | 
|  |  | 
|  | for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { | 
|  | Node* node = block->at(nodeIndex); | 
|  |  | 
|  | switch (node->op()) { | 
|  | case CheckStructure: | 
|  | assertAreRegistered(node->structureSet()); | 
|  | break; | 
|  |  | 
|  | case NewObject: | 
|  | case ArrayifyToStructure: | 
|  | case NewStringObject: | 
|  | registerStructure(node->structure()); | 
|  | break; | 
|  |  | 
|  | case PutStructure: | 
|  | case AllocatePropertyStorage: | 
|  | case ReallocatePropertyStorage: | 
|  | registerStructure(node->transition()->previous); | 
|  | registerStructure(node->transition()->next); | 
|  | break; | 
|  |  | 
|  | case GetGetterSetterByOffset: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->getterSetterStructure()); | 
|  | break; | 
|  |  | 
|  | case MultiGetByOffset: | 
|  | for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) | 
|  | registerStructures(getCase.set()); | 
|  | break; | 
|  |  | 
|  | case MultiPutByOffset: | 
|  | for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) { | 
|  | PutByIdVariant& variant = node->multiPutByOffsetData().variants[i]; | 
|  | registerStructures(variant.oldStructure()); | 
|  | if (variant.kind() == PutByIdVariant::Transition) | 
|  | registerStructure(variant.newStructure()); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case NewArray: | 
|  | case NewArrayBuffer: | 
|  | case NewArrayWithSize: { | 
|  | JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); | 
|  | registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())); | 
|  | registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage)); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case NewTypedArray: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructureConcurrently(node->typedArrayType())); | 
|  | break; | 
|  |  | 
|  | case ToString: | 
|  | case CallStringConstructor: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->stringObjectStructure()); | 
|  | break; | 
|  |  | 
|  | case CreateActivation: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->activationStructure()); | 
|  | break; | 
|  |  | 
|  | case CreateDirectArguments: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->directArgumentsStructure()); | 
|  | break; | 
|  |  | 
|  | case CreateScopedArguments: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->scopedArgumentsStructure()); | 
|  | break; | 
|  |  | 
|  | case CreateClonedArguments: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->clonedArgumentsStructure()); | 
|  | break; | 
|  |  | 
|  | case NewRegexp: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->regExpStructure()); | 
|  | break; | 
|  | case NewFunction: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->functionStructure()); | 
|  | break; | 
|  | case NewGeneratorFunction: | 
|  | registerStructure(m_graph.globalObjectFor(node->origin.semantic)->generatorFunctionStructure()); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void registerStructures(const StructureSet& set) | 
|  | { | 
|  | for (Structure* structure : set) | 
|  | registerStructure(structure); | 
|  | } | 
|  |  | 
|  | void registerStructure(Structure* structure) | 
|  | { | 
|  | if (structure) | 
|  | m_graph.registerStructure(structure); | 
|  | } | 
|  |  | 
|  | void assertAreRegistered(const StructureSet& set) | 
|  | { | 
|  | for (Structure* structure : set) | 
|  | assertIsRegistered(structure); | 
|  | } | 
|  |  | 
|  | void assertIsRegistered(Structure* structure) | 
|  | { | 
|  | if (structure) | 
|  | m_graph.assertIsRegistered(structure); | 
|  | } | 
|  | }; | 
|  |  | 
|  | bool performStructureRegistration(Graph& graph) | 
|  | { | 
|  | return runPhase<StructureRegistrationPhase>(graph); | 
|  | } | 
|  |  | 
|  | } } // namespace JSC::DFG | 
|  |  | 
|  | #endif // ENABLE(DFG_JIT) | 
|  |  |