1/* 2 * Copyright (C) 2013, 2014 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 "DFGAbstractValue.h" 28 29#if ENABLE(DFG_JIT) 30 31#include "DFGGraph.h" 32#include "JSCInlines.h" 33 34namespace JSC { namespace DFG { 35 36void AbstractValue::setMostSpecific(Graph& graph, JSValue value) 37{ 38 if (!!value && value.isCell()) { 39 Structure* structure = value.asCell()->structure(); 40 m_currentKnownStructure = structure; 41 setFuturePossibleStructure(graph, structure); 42 m_arrayModes = asArrayModes(structure->indexingType()); 43 } else { 44 m_currentKnownStructure.clear(); 45 m_futurePossibleStructure.clear(); 46 m_arrayModes = 0; 47 } 48 49 m_type = speculationFromValue(value); 50 m_value = value; 51 52 checkConsistency(); 53} 54 55void AbstractValue::set(Graph& graph, JSValue value) 56{ 57 if (!!value && value.isCell()) { 58 m_currentKnownStructure.makeTop(); 59 Structure* structure = value.asCell()->structure(); 60 setFuturePossibleStructure(graph, structure); 61 m_arrayModes = asArrayModes(structure->indexingType()); 62 clobberArrayModes(); 63 } else { 64 m_currentKnownStructure.clear(); 65 m_futurePossibleStructure.clear(); 66 m_arrayModes = 0; 67 } 68 69 m_type = speculationFromValue(value); 70 m_value = value; 71 72 checkConsistency(); 73} 74 75void AbstractValue::set(Graph& graph, Structure* structure) 76{ 77 m_currentKnownStructure = structure; 78 setFuturePossibleStructure(graph, structure); 79 m_arrayModes = asArrayModes(structure->indexingType()); 80 m_type = speculationFromStructure(structure); 81 m_value = JSValue(); 82 83 checkConsistency(); 84} 85 86void AbstractValue::fixTypeForRepresentation(NodeFlags representation) 87{ 88 if (representation == NodeResultDouble) { 89 if (m_value) { 90 ASSERT(m_value.isNumber()); 91 if (m_value.isInt32()) 92 m_value = jsDoubleNumber(m_value.asNumber()); 93 } 94 if (m_type & SpecMachineInt) { 95 m_type &= ~SpecMachineInt; 96 m_type |= SpecInt52AsDouble; 97 } 98 if (m_type & ~SpecFullDouble) { 99 startCrashing(); 100 dataLog("Abstract value ", *this, " for double node has type outside SpecFullDouble.\n"); 101 CRASH(); 102 } 103 } else if (representation == NodeResultInt52) { 104 if (m_type & SpecInt52AsDouble) { 105 m_type &= ~SpecInt52AsDouble; 106 m_type |= SpecInt52; 107 } 108 if (m_type & ~SpecMachineInt) { 109 startCrashing(); 110 dataLog("Abstract value ", *this, " for int52 node has type outside SpecMachineInt.\n"); 111 CRASH(); 112 } 113 } else { 114 if (m_type & SpecInt52) { 115 m_type &= ~SpecInt52; 116 m_type |= SpecInt52AsDouble; 117 } 118 if (m_type & ~SpecBytecodeTop) { 119 startCrashing(); 120 dataLog("Abstract value ", *this, " for value node has type outside SpecBytecodeTop.\n"); 121 CRASH(); 122 } 123 } 124 125 checkConsistency(); 126} 127 128void AbstractValue::fixTypeForRepresentation(Node* node) 129{ 130 fixTypeForRepresentation(node->result()); 131} 132 133FiltrationResult AbstractValue::filter(Graph& graph, const StructureSet& other) 134{ 135 if (isClear()) 136 return FiltrationOK; 137 138 // FIXME: This could be optimized for the common case of m_type not 139 // having structures, array modes, or a specific value. 140 // https://bugs.webkit.org/show_bug.cgi?id=109663 141 142 m_type &= other.speculationFromStructures(); 143 m_arrayModes &= other.arrayModesFromStructures(); 144 m_currentKnownStructure.filter(other); 145 146 // It's possible that prior to the above two statements we had (Foo, TOP), where 147 // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that 148 // case, we will now have (None, [someStructure]). In general, we need to make 149 // sure that new information gleaned from the SpeculatedType needs to be fed back 150 // into the information gleaned from the StructureSet. 151 m_currentKnownStructure.filter(m_type); 152 153 if (m_currentKnownStructure.hasSingleton()) 154 setFuturePossibleStructure(graph, m_currentKnownStructure.singleton()); 155 156 filterArrayModesByType(); 157 filterValueByType(); 158 return normalizeClarity(); 159} 160 161FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes) 162{ 163 ASSERT(arrayModes); 164 165 if (isClear()) 166 return FiltrationOK; 167 168 m_type &= SpecCell; 169 m_arrayModes &= arrayModes; 170 return normalizeClarity(); 171} 172 173FiltrationResult AbstractValue::filter(SpeculatedType type) 174{ 175 if ((m_type & type) == m_type) 176 return FiltrationOK; 177 178 m_type &= type; 179 180 // It's possible that prior to this filter() call we had, say, (Final, TOP), and 181 // the passed type is Array. At this point we'll have (None, TOP). The best way 182 // to ensure that the structure filtering does the right thing is to filter on 183 // the new type (None) rather than the one passed (Array). 184 m_currentKnownStructure.filter(m_type); 185 m_futurePossibleStructure.filter(m_type); 186 filterArrayModesByType(); 187 filterValueByType(); 188 return normalizeClarity(); 189} 190 191FiltrationResult AbstractValue::filterByValue(JSValue value) 192{ 193 FiltrationResult result = filter(speculationFromValue(value)); 194 if (m_type) 195 m_value = value; 196 return result; 197} 198 199void AbstractValue::setFuturePossibleStructure(Graph& graph, Structure* structure) 200{ 201 ASSERT(structure); 202 if (graph.watchpoints().isStillValid(structure->transitionWatchpointSet())) 203 m_futurePossibleStructure = structure; 204 else 205 m_futurePossibleStructure.makeTop(); 206} 207 208void AbstractValue::filterValueByType() 209{ 210 // We could go further, and ensure that if the futurePossibleStructure contravenes 211 // the value, then we could clear both of those things. But that's unlikely to help 212 // in any realistic scenario, so we don't do it. Simpler is better. 213 214 if (!!m_type) { 215 // The type is still non-empty. It may be that the new type renders 216 // the value empty because it contravenes the constant value we had. 217 if (m_value && !validateType(m_value)) 218 clear(); 219 return; 220 } 221 222 // The type has been rendered empty. That means that the value must now be invalid, 223 // as well. 224 ASSERT(!m_value || !validateType(m_value)); 225 m_value = JSValue(); 226} 227 228void AbstractValue::filterArrayModesByType() 229{ 230 if (!(m_type & SpecCell)) 231 m_arrayModes = 0; 232 else if (!(m_type & ~SpecArray)) 233 m_arrayModes &= ALL_ARRAY_ARRAY_MODES; 234 235 // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the 236 // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since 237 // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype 238 // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes 239 // type system they are arrays (since they expose the magical length 240 // property and are otherwise allocated using array allocation). Hence the 241 // following would be wrong: 242 // 243 // if (!(m_type & SpecArray)) 244 // m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES; 245} 246 247bool AbstractValue::shouldBeClear() const 248{ 249 if (m_type == SpecNone) 250 return true; 251 252 if (!(m_type & ~SpecCell) 253 && (!m_arrayModes 254 || m_currentKnownStructure.isClear())) 255 return true; 256 257 return false; 258} 259 260FiltrationResult AbstractValue::normalizeClarity() 261{ 262 // It's useful to be able to quickly check if an abstract value is clear. 263 // This normalizes everything to make that easy. 264 265 FiltrationResult result; 266 267 if (shouldBeClear()) { 268 clear(); 269 result = Contradiction; 270 } else 271 result = FiltrationOK; 272 273 checkConsistency(); 274 275 return result; 276} 277 278#if !ASSERT_DISABLED 279void AbstractValue::checkConsistency() const 280{ 281 if (!(m_type & SpecCell)) { 282 ASSERT(m_currentKnownStructure.isClear()); 283 ASSERT(m_futurePossibleStructure.isClear()); 284 ASSERT(!m_arrayModes); 285 } 286 287 if (isClear()) 288 ASSERT(!m_value); 289 290 if (!!m_value) { 291 SpeculatedType type = m_type; 292 // This relaxes the assertion below a bit, since we don't know the representation of the 293 // node. 294 if (type & SpecInt52) 295 type |= SpecInt52AsDouble; 296 ASSERT(mergeSpeculations(type, speculationFromValue(m_value)) == type); 297 } 298 299 // Note that it's possible for a prediction like (Final, []). This really means that 300 // the value is bottom and that any code that uses the value is unreachable. But 301 // we don't want to get pedantic about this as it would only increase the computational 302 // complexity of the code. 303} 304#endif 305 306void AbstractValue::dump(PrintStream& out) const 307{ 308 dumpInContext(out, 0); 309} 310 311void AbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const 312{ 313 out.print("(", SpeculationDump(m_type)); 314 if (m_type & SpecCell) { 315 out.print( 316 ", ", ArrayModesDump(m_arrayModes), ", ", 317 inContext(m_currentKnownStructure, context), ", ", 318 inContext(m_futurePossibleStructure, context)); 319 } 320 if (!!m_value) 321 out.print(", ", inContext(m_value, context)); 322 out.print(")"); 323} 324 325} } // namespace JSC::DFG 326 327#endif // ENABLE(DFG_JIT) 328 329