- return false;
- }
-
- bool checkStructureElimination(const StructureSet& structureSet, Node* child1)
- {
- for (unsigned i = m_indexInBlock; i--;) {
- Node* node = m_currentBlock->at(i);
- if (node == child1)
- break;
-
- switch (node->op()) {
- case CheckStructure:
- if (node->child1() == child1
- && structureSet.isSupersetOf(node->structureSet()))
- return true;
- break;
-
- case StructureTransitionWatchpoint:
- if (node->child1() == child1
- && structureSet.contains(node->structure()))
- return true;
- break;
-
- case PutStructure:
- if (node->child1() == child1
- && structureSet.contains(node->structureTransitionData().newStructure))
- return true;
- if (structureSet.contains(node->structureTransitionData().previousStructure))
- return false;
- break;
-
- case PutByOffset:
- // Setting a property cannot change the structure.
- break;
-
- case MultiPutByOffset:
- if (node->multiPutByOffsetData().writesStructures())
- return false;
- break;
-
- case PutByValDirect:
- case PutByVal:
- case PutByValAlias:
- if (m_graph.byValIsPure(node)) {
- // If PutByVal speculates that it's accessing an array with an
- // integer index, then it's impossible for it to cause a structure
- // change.
- break;
+
+ LazyNode findReplacement(HeapLocation location)
+ {
+ return m_impureMap.get(location);
+ }
+
+ LazyNode addImpure(HeapLocation location, LazyNode node)
+ {
+ auto result = m_impureMap.add(location, node);
+ if (result.isNewEntry)
+ return nullptr;
+ return result.iterator->value;
+ }
+
+ private:
+ HashMap<PureValue, Node*> m_pureMap;
+ HashMap<HeapLocation, LazyNode> m_impureMap;
+ };
+
+ template<typename Maps>
+ class BlockCSE {
+ public:
+ BlockCSE(Graph& graph)
+ : m_graph(graph)
+ , m_insertionSet(graph)
+ {
+ }
+
+ bool run(BasicBlock* block)
+ {
+ m_maps.clear();
+ m_changed = false;
+ m_block = block;
+
+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
+ m_node = block->at(nodeIndex);
+ m_graph.performSubstitution(m_node);
+
+ if (m_node->op() == Identity) {
+ m_node->replaceWith(m_node->child1().node());
+ m_changed = true;
+ } else {
+ // This rule only makes sense for local CSE, since in SSA form we have already
+ // factored the bounds check out of the PutByVal. It's kind of gross, but we
+ // still have reason to believe that PutByValAlias is a good optimization and
+ // that it's better to do it with a single node rather than separating out the
+ // CheckInBounds.
+ if (m_node->op() == PutByVal || m_node->op() == PutByValDirect) {
+ HeapLocation heap;
+
+ Node* base = m_graph.varArgChild(m_node, 0).node();
+ Node* index = m_graph.varArgChild(m_node, 1).node();
+
+ ArrayMode mode = m_node->arrayMode();
+ switch (mode.type()) {
+ case Array::Int32:
+ if (!mode.isInBounds())
+ break;
+ heap = HeapLocation(
+ IndexedPropertyLoc, IndexedInt32Properties, base, index);
+ break;
+
+ case Array::Double:
+ if (!mode.isInBounds())
+ break;
+ heap = HeapLocation(
+ IndexedPropertyLoc, IndexedDoubleProperties, base, index);
+ break;
+
+ case Array::Contiguous:
+ if (!mode.isInBounds())
+ break;
+ heap = HeapLocation(
+ IndexedPropertyLoc, IndexedContiguousProperties, base, index);
+ break;
+
+ case Array::Int8Array:
+ case Array::Int16Array:
+ case Array::Int32Array:
+ case Array::Uint8Array:
+ case Array::Uint8ClampedArray:
+ case Array::Uint16Array:
+ case Array::Uint32Array:
+ case Array::Float32Array:
+ case Array::Float64Array:
+ if (!mode.isInBounds())
+ break;
+ heap = HeapLocation(
+ IndexedPropertyLoc, TypedArrayProperties, base, index);
+ break;
+
+ default:
+ break;
+ }
+
+ if (!!heap && m_maps.findReplacement(heap))
+ m_node->setOp(PutByValAlias);
+ }
+
+ clobberize(m_graph, m_node, *this);