fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2012 Apple Inc. All rights reserved. |
| 3 | * |
| 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions |
| 6 | * are met: |
| 7 | * 1. Redistributions of source code must retain the above copyright |
| 8 | * notice, this list of conditions and the following disclaimer. |
| 9 | * 2. Redistributions in binary form must reproduce the above copyright |
| 10 | * notice, this list of conditions and the following disclaimer in the |
| 11 | * documentation and/or other materials provided with the distribution. |
| 12 | * |
| 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 | */ |
| 25 | |
| 26 | #include "config.h" |
| 27 | #include "DFGStructureCheckHoistingPhase.h" |
| 28 | |
| 29 | #if ENABLE(DFG_JIT) |
| 30 | |
| 31 | #include "DFGBasicBlock.h" |
| 32 | #include "DFGGraph.h" |
| 33 | #include "DFGInsertionSet.h" |
| 34 | #include "DFGPhase.h" |
fpizlo@apple.com | c6e5add | 2012-12-03 01:59:42 +0000 | [diff] [blame] | 35 | #include "DFGVariableAccessDataDump.h" |
fpizlo@apple.com | a4b4cbe | 2013-01-12 04:47:03 +0000 | [diff] [blame] | 36 | #include "Operations.h" |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 37 | #include <wtf/HashMap.h> |
| 38 | |
| 39 | namespace JSC { namespace DFG { |
| 40 | |
| 41 | enum CheckBallot { VoteOther, VoteStructureCheck }; |
| 42 | |
| 43 | class StructureCheckHoistingPhase : public Phase { |
| 44 | public: |
| 45 | StructureCheckHoistingPhase(Graph& graph) |
| 46 | : Phase(graph, "structure check hoisting") |
| 47 | { |
| 48 | } |
| 49 | |
| 50 | bool run() |
| 51 | { |
| 52 | for (unsigned i = m_graph.m_variableAccessData.size(); i--;) { |
| 53 | VariableAccessData* variable = &m_graph.m_variableAccessData[i]; |
| 54 | if (!variable->isRoot()) |
| 55 | continue; |
| 56 | variable->clearVotes(); |
| 57 | } |
| 58 | |
| 59 | // Identify the set of variables that are always subject to the same structure |
| 60 | // checks. For now, only consider monomorphic structure checks (one structure). |
| 61 | |
| 62 | for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { |
| 63 | BasicBlock* block = m_graph.m_blocks[blockIndex].get(); |
| 64 | if (!block) |
| 65 | continue; |
| 66 | for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { |
| 67 | NodeIndex nodeIndex = block->at(indexInBlock); |
| 68 | Node& node = m_graph[nodeIndex]; |
| 69 | if (!node.shouldGenerate()) |
| 70 | continue; |
| 71 | switch (node.op()) { |
fpizlo@apple.com | 6e0a9ed | 2012-09-16 02:36:22 +0000 | [diff] [blame] | 72 | case CheckStructure: |
| 73 | case StructureTransitionWatchpoint: { |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 74 | Node& child = m_graph[node.child1()]; |
| 75 | if (child.op() != GetLocal) |
| 76 | break; |
| 77 | VariableAccessData* variable = child.variableAccessData(); |
| 78 | variable->vote(VoteStructureCheck); |
| 79 | if (variable->isCaptured() || variable->structureCheckHoistingFailed()) |
| 80 | break; |
| 81 | if (!isCellSpeculation(variable->prediction())) |
| 82 | break; |
| 83 | noticeStructureCheck(variable, node.structureSet()); |
| 84 | break; |
| 85 | } |
| 86 | |
| 87 | case ForwardCheckStructure: |
fpizlo@apple.com | eb3323d | 2012-08-20 06:11:24 +0000 | [diff] [blame] | 88 | case ForwardStructureTransitionWatchpoint: |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 89 | // We currently rely on the fact that we're the only ones who would |
| 90 | // insert this node. |
| 91 | ASSERT_NOT_REACHED(); |
| 92 | break; |
| 93 | |
| 94 | case GetByOffset: |
| 95 | case PutByOffset: |
| 96 | case PutStructure: |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 97 | case AllocatePropertyStorage: |
| 98 | case ReallocatePropertyStorage: |
fpizlo@apple.com | d8dd053 | 2012-09-13 04:18:52 +0000 | [diff] [blame] | 99 | case GetButterfly: |
fpizlo@apple.com | f24804c | 2012-08-15 02:48:35 +0000 | [diff] [blame] | 100 | case GetByVal: |
| 101 | case PutByVal: |
| 102 | case PutByValAlias: |
| 103 | case GetArrayLength: |
fpizlo@apple.com | 04c1974 | 2012-08-26 22:35:26 +0000 | [diff] [blame] | 104 | case CheckArray: |
| 105 | case GetIndexedPropertyStorage: |
fpizlo@apple.com | f24804c | 2012-08-15 02:48:35 +0000 | [diff] [blame] | 106 | case Phantom: |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 107 | // Don't count these uses. |
| 108 | break; |
| 109 | |
fpizlo@apple.com | f10d072 | 2012-12-03 09:21:22 +0000 | [diff] [blame] | 110 | case ArrayifyToStructure: |
| 111 | case Arrayify: |
| 112 | if (node.arrayMode().conversion() == Array::RageConvert) { |
| 113 | // Rage conversion changes structures. We should avoid tying to do |
| 114 | // any kind of hoisting when rage conversion is in play. |
| 115 | Node& child = m_graph[node.child1()]; |
| 116 | if (child.op() != GetLocal) |
| 117 | break; |
| 118 | VariableAccessData* variable = child.variableAccessData(); |
| 119 | variable->vote(VoteOther); |
| 120 | if (variable->isCaptured() || variable->structureCheckHoistingFailed()) |
| 121 | break; |
| 122 | if (!isCellSpeculation(variable->prediction())) |
| 123 | break; |
| 124 | noticeStructureCheck(variable, 0); |
| 125 | } |
| 126 | break; |
| 127 | |
fpizlo@apple.com | 6e0a9ed | 2012-09-16 02:36:22 +0000 | [diff] [blame] | 128 | case SetLocal: { |
| 129 | // Find all uses of the source of the SetLocal. If any of them are a |
| 130 | // kind of CheckStructure, then we should notice them to ensure that |
| 131 | // we're not hoisting a check that would contravene checks that are |
| 132 | // already being performed. |
| 133 | VariableAccessData* variable = node.variableAccessData(); |
| 134 | if (variable->isCaptured() || variable->structureCheckHoistingFailed()) |
| 135 | break; |
| 136 | if (!isCellSpeculation(variable->prediction())) |
| 137 | break; |
| 138 | NodeIndex source = node.child1().index(); |
| 139 | for (unsigned subIndexInBlock = 0; subIndexInBlock < block->size(); ++subIndexInBlock) { |
| 140 | NodeIndex subNodeIndex = block->at(subIndexInBlock); |
| 141 | Node& subNode = m_graph[subNodeIndex]; |
| 142 | if (!subNode.shouldGenerate()) |
| 143 | continue; |
| 144 | switch (subNode.op()) { |
fpizlo@apple.com | 3710889 | 2012-09-28 20:38:40 +0000 | [diff] [blame] | 145 | case CheckStructure: { |
fpizlo@apple.com | 6e0a9ed | 2012-09-16 02:36:22 +0000 | [diff] [blame] | 146 | if (subNode.child1().index() != source) |
| 147 | break; |
| 148 | |
| 149 | noticeStructureCheck(variable, subNode.structureSet()); |
| 150 | break; |
| 151 | } |
fpizlo@apple.com | 3710889 | 2012-09-28 20:38:40 +0000 | [diff] [blame] | 152 | case StructureTransitionWatchpoint: { |
| 153 | if (subNode.child1().index() != source) |
| 154 | break; |
| 155 | |
| 156 | noticeStructureCheck(variable, subNode.structure()); |
| 157 | break; |
| 158 | } |
fpizlo@apple.com | 6e0a9ed | 2012-09-16 02:36:22 +0000 | [diff] [blame] | 159 | default: |
| 160 | break; |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | m_graph.vote(node, VoteOther); |
| 165 | break; |
| 166 | } |
oliver@apple.com | c909f5f | 2012-10-18 23:37:40 +0000 | [diff] [blame] | 167 | case GarbageValue: |
| 168 | break; |
fpizlo@apple.com | 6e0a9ed | 2012-09-16 02:36:22 +0000 | [diff] [blame] | 169 | |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 170 | default: |
| 171 | m_graph.vote(node, VoteOther); |
| 172 | break; |
| 173 | } |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | // Disable structure hoisting on variables that appear to mostly be used in |
| 178 | // contexts where it doesn't make sense. |
| 179 | |
| 180 | for (unsigned i = m_graph.m_variableAccessData.size(); i--;) { |
| 181 | VariableAccessData* variable = &m_graph.m_variableAccessData[i]; |
| 182 | if (!variable->isRoot()) |
| 183 | continue; |
| 184 | if (variable->voteRatio() >= Options::structureCheckVoteRatioForHoisting()) |
| 185 | continue; |
| 186 | HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(variable); |
| 187 | if (iter == m_map.end()) |
| 188 | continue; |
| 189 | #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) |
fpizlo@apple.com | c6e5add | 2012-12-03 01:59:42 +0000 | [diff] [blame] | 190 | dataLog( |
| 191 | "Zeroing the structure to hoist for ", VariableAccessDataDump(m_graph, variable), |
| 192 | " because the ratio is ", variable->voteRatio(), ".\n"); |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 193 | #endif |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 194 | iter->value.m_structure = 0; |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 195 | } |
fpizlo@apple.com | 8e11677 | 2012-08-28 00:40:43 +0000 | [diff] [blame] | 196 | |
| 197 | // Disable structure check hoisting for variables that cross the OSR entry that |
| 198 | // we're currently taking, and where the value currently does not have the |
| 199 | // structure we want. |
| 200 | |
| 201 | for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { |
| 202 | BasicBlock* block = m_graph.m_blocks[blockIndex].get(); |
| 203 | if (!block) |
| 204 | continue; |
| 205 | ASSERT(block->isReachable); |
| 206 | if (!block->isOSRTarget) |
| 207 | continue; |
| 208 | if (block->bytecodeBegin != m_graph.m_osrEntryBytecodeIndex) |
| 209 | continue; |
| 210 | for (size_t i = 0; i < m_graph.m_mustHandleValues.size(); ++i) { |
| 211 | int operand = m_graph.m_mustHandleValues.operandForIndex(i); |
| 212 | NodeIndex nodeIndex = block->variablesAtHead.operand(operand); |
| 213 | if (nodeIndex == NoNode) |
| 214 | continue; |
| 215 | VariableAccessData* variable = m_graph[nodeIndex].variableAccessData(); |
| 216 | HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(variable); |
| 217 | if (iter == m_map.end()) |
| 218 | continue; |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 219 | if (!iter->value.m_structure) |
fpizlo@apple.com | 8e11677 | 2012-08-28 00:40:43 +0000 | [diff] [blame] | 220 | continue; |
| 221 | JSValue value = m_graph.m_mustHandleValues[i]; |
| 222 | if (!value || !value.isCell()) { |
| 223 | #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) |
fpizlo@apple.com | c6e5add | 2012-12-03 01:59:42 +0000 | [diff] [blame] | 224 | dataLog( |
| 225 | "Zeroing the structure to hoist for ", VariableAccessDataDump(m_graph, variable), |
fpizlo@apple.com | d2e0051 | 2012-12-07 22:55:58 +0000 | [diff] [blame] | 226 | " because the OSR entry value is not a cell: ", value, ".\n"); |
fpizlo@apple.com | 8e11677 | 2012-08-28 00:40:43 +0000 | [diff] [blame] | 227 | #endif |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 228 | iter->value.m_structure = 0; |
fpizlo@apple.com | 8e11677 | 2012-08-28 00:40:43 +0000 | [diff] [blame] | 229 | continue; |
| 230 | } |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 231 | if (value.asCell()->structure() != iter->value.m_structure) { |
fpizlo@apple.com | 8e11677 | 2012-08-28 00:40:43 +0000 | [diff] [blame] | 232 | #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) |
fpizlo@apple.com | c6e5add | 2012-12-03 01:59:42 +0000 | [diff] [blame] | 233 | dataLog( |
| 234 | "Zeroing the structure to hoist for ", VariableAccessDataDump(m_graph, variable), |
| 235 | " because the OSR entry value has structure ", |
| 236 | RawPointer(value.asCell()->structure()), " and we wanted ", |
| 237 | RawPointer(iter->value.m_structure), ".\n"); |
fpizlo@apple.com | 8e11677 | 2012-08-28 00:40:43 +0000 | [diff] [blame] | 238 | #endif |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 239 | iter->value.m_structure = 0; |
fpizlo@apple.com | 8e11677 | 2012-08-28 00:40:43 +0000 | [diff] [blame] | 240 | continue; |
| 241 | } |
| 242 | } |
| 243 | } |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 244 | |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 245 | bool changed = false; |
| 246 | |
| 247 | #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) |
| 248 | for (HashMap<VariableAccessData*, CheckData>::iterator it = m_map.begin(); |
| 249 | it != m_map.end(); ++it) { |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 250 | if (!it->value.m_structure) { |
fpizlo@apple.com | c6e5add | 2012-12-03 01:59:42 +0000 | [diff] [blame] | 251 | dataLog( |
| 252 | "Not hoisting checks for ", VariableAccessDataDump(m_graph, it->key), |
| 253 | " because of heuristics.\n"); |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 254 | continue; |
| 255 | } |
fpizlo@apple.com | c6e5add | 2012-12-03 01:59:42 +0000 | [diff] [blame] | 256 | dataLog("Hoisting checks for ", VariableAccessDataDump(m_graph, it->key), "\n"); |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 257 | } |
| 258 | #endif // DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) |
fpizlo@apple.com | 6a23c42 | 2012-08-18 00:48:38 +0000 | [diff] [blame] | 259 | |
fpizlo@apple.com | f1ee41f | 2012-10-14 20:22:17 +0000 | [diff] [blame] | 260 | // Place CheckStructure's at SetLocal sites. |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 261 | |
fpizlo@apple.com | f45e88b | 2013-01-20 19:29:50 +0000 | [diff] [blame^] | 262 | InsertionSet insertionSet(m_graph); |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 263 | for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { |
| 264 | BasicBlock* block = m_graph.m_blocks[blockIndex].get(); |
| 265 | if (!block) |
| 266 | continue; |
| 267 | for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { |
| 268 | NodeIndex nodeIndex = block->at(indexInBlock); |
| 269 | Node& node = m_graph[nodeIndex]; |
fpizlo@apple.com | 8ab9c43 | 2012-08-03 21:41:05 +0000 | [diff] [blame] | 270 | // Be careful not to use 'node' after appending to the graph. In those switch |
| 271 | // cases where we need to append, we first carefully extract everything we need |
| 272 | // from the node, before doing any appending. |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 273 | if (!node.shouldGenerate()) |
| 274 | continue; |
| 275 | switch (node.op()) { |
| 276 | case SetArgument: { |
| 277 | ASSERT(!blockIndex); |
| 278 | // Insert a GetLocal and a CheckStructure immediately following this |
| 279 | // SetArgument, if the variable was a candidate for structure hoisting. |
| 280 | // If the basic block previously only had the SetArgument as its |
| 281 | // variable-at-tail, then replace it with this GetLocal. |
| 282 | VariableAccessData* variable = node.variableAccessData(); |
| 283 | HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(variable); |
| 284 | if (iter == m_map.end()) |
| 285 | break; |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 286 | if (!iter->value.m_structure) |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 287 | break; |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 288 | |
fpizlo@apple.com | 8ab9c43 | 2012-08-03 21:41:05 +0000 | [diff] [blame] | 289 | CodeOrigin codeOrigin = node.codeOrigin; |
| 290 | |
fpizlo@apple.com | f45e88b | 2013-01-20 19:29:50 +0000 | [diff] [blame^] | 291 | NodeIndex getLocalIndex = insertionSet.insertNode( |
| 292 | indexInBlock + 1, DontRefChildren, DontRefNode, variable->prediction(), |
| 293 | GetLocal, codeOrigin, OpInfo(variable), nodeIndex); |
| 294 | insertionSet.insertNode( |
| 295 | indexInBlock + 1, RefChildren, DontRefNode, SpecNone, CheckStructure, |
| 296 | codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)), |
| 297 | getLocalIndex); |
| 298 | |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 299 | if (block->variablesAtTail.operand(variable->local()) == nodeIndex) |
| 300 | block->variablesAtTail.operand(variable->local()) = getLocalIndex; |
| 301 | |
fpizlo@apple.com | 00673b3 | 2012-08-16 23:17:24 +0000 | [diff] [blame] | 302 | m_graph.substituteGetLocal(*block, indexInBlock, variable, getLocalIndex); |
| 303 | |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 304 | changed = true; |
| 305 | break; |
| 306 | } |
| 307 | |
| 308 | case SetLocal: { |
| 309 | VariableAccessData* variable = node.variableAccessData(); |
| 310 | HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(variable); |
| 311 | if (iter == m_map.end()) |
| 312 | break; |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 313 | if (!iter->value.m_structure) |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 314 | break; |
fpizlo@apple.com | 8ab9c43 | 2012-08-03 21:41:05 +0000 | [diff] [blame] | 315 | |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 316 | // First insert a dead SetLocal to tell OSR that the child's value should |
| 317 | // be dropped into this bytecode variable if the CheckStructure decides |
| 318 | // to exit. |
fpizlo@apple.com | 8ab9c43 | 2012-08-03 21:41:05 +0000 | [diff] [blame] | 319 | |
| 320 | CodeOrigin codeOrigin = node.codeOrigin; |
| 321 | NodeIndex child1 = node.child1().index(); |
| 322 | |
fpizlo@apple.com | f45e88b | 2013-01-20 19:29:50 +0000 | [diff] [blame^] | 323 | insertionSet.insertNode( |
| 324 | indexInBlock, DontRefChildren, DontRefNode, SpecNone, SetLocal, codeOrigin, |
| 325 | OpInfo(variable), child1); |
| 326 | |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 327 | // Use a ForwardCheckStructure to indicate that we should exit to the |
| 328 | // next bytecode instruction rather than reexecuting the current one. |
fpizlo@apple.com | f45e88b | 2013-01-20 19:29:50 +0000 | [diff] [blame^] | 329 | insertionSet.insertNode( |
| 330 | indexInBlock, RefChildren, DontRefNode, SpecNone, ForwardCheckStructure, |
| 331 | codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)), child1); |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 332 | changed = true; |
| 333 | break; |
| 334 | } |
| 335 | |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 336 | default: |
| 337 | break; |
| 338 | } |
| 339 | } |
fpizlo@apple.com | f45e88b | 2013-01-20 19:29:50 +0000 | [diff] [blame^] | 340 | insertionSet.execute(block); |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 341 | } |
| 342 | |
| 343 | return changed; |
| 344 | } |
| 345 | |
| 346 | private: |
| 347 | void noticeStructureCheck(VariableAccessData* variable, Structure* structure) |
| 348 | { |
| 349 | HashMap<VariableAccessData*, CheckData>::AddResult result = |
fpizlo@apple.com | f1ee41f | 2012-10-14 20:22:17 +0000 | [diff] [blame] | 350 | m_map.add(variable, CheckData(structure)); |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 351 | if (result.isNewEntry) |
| 352 | return; |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 353 | if (result.iterator->value.m_structure == structure) |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 354 | return; |
benjamin@webkit.org | ee55405 | 2012-10-07 23:12:07 +0000 | [diff] [blame] | 355 | result.iterator->value.m_structure = 0; |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 356 | } |
| 357 | |
| 358 | void noticeStructureCheck(VariableAccessData* variable, const StructureSet& set) |
| 359 | { |
| 360 | if (set.size() != 1) { |
| 361 | noticeStructureCheck(variable, 0); |
| 362 | return; |
| 363 | } |
| 364 | noticeStructureCheck(variable, set.singletonStructure()); |
| 365 | } |
| 366 | |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 367 | struct CheckData { |
| 368 | Structure* m_structure; |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 369 | |
| 370 | CheckData() |
| 371 | : m_structure(0) |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 372 | { |
| 373 | } |
| 374 | |
fpizlo@apple.com | f1ee41f | 2012-10-14 20:22:17 +0000 | [diff] [blame] | 375 | CheckData(Structure* structure) |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 376 | : m_structure(structure) |
fpizlo@apple.com | caa6881 | 2012-08-02 04:32:30 +0000 | [diff] [blame] | 377 | { |
| 378 | } |
| 379 | }; |
| 380 | |
| 381 | HashMap<VariableAccessData*, CheckData> m_map; |
| 382 | }; |
| 383 | |
| 384 | bool performStructureCheckHoisting(Graph& graph) |
| 385 | { |
| 386 | SamplingRegion samplingRegion("DFG Structure Check Hoisting Phase"); |
| 387 | return runPhase<StructureCheckHoistingPhase>(graph); |
| 388 | } |
| 389 | |
| 390 | } } // namespace JSC::DFG |
| 391 | |
| 392 | #endif // ENABLE(DFG_JIT) |
| 393 | |
| 394 | |