X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/4be4e30906bcb8ee30b4d189205cb70bad6707ce..81345200c95645a1b0d2635520f96ad55dfde63f:/dfg/DFGAbstractValue.h diff --git a/dfg/DFGAbstractValue.h b/dfg/DFGAbstractValue.h index 25757b5..14363df 100644 --- a/dfg/DFGAbstractValue.h +++ b/dfg/DFGAbstractValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,18 +26,22 @@ #ifndef DFGAbstractValue_h #define DFGAbstractValue_h -#include - #if ENABLE(DFG_JIT) #include "ArrayProfile.h" +#include "DFGFiltrationResult.h" +#include "DFGNodeFlags.h" #include "DFGStructureAbstractValue.h" #include "JSCell.h" #include "SpeculatedType.h" +#include "DumpContext.h" #include "StructureSet.h" namespace JSC { namespace DFG { +class Graph; +struct Node; + struct AbstractValue { AbstractValue() : m_type(SpecNone) @@ -55,22 +59,17 @@ struct AbstractValue { checkConsistency(); } - bool isClear() const + bool isClear() const { return m_type == SpecNone; } + bool operator!() const { return isClear(); } + + void makeHeapTop() { - bool result = m_type == SpecNone && !m_arrayModes && m_currentKnownStructure.isClear() && m_futurePossibleStructure.isClear(); - if (result) - ASSERT(!m_value); - return result; + makeTop(SpecHeapTop); } - void makeTop() + void makeBytecodeTop() { - m_type |= SpecTop; // The state may have included SpecEmpty, in which case we want this to become SpecEmptyOrTop. - m_arrayModes = ALL_ARRAY_MODES; - m_currentKnownStructure.makeTop(); - m_futurePossibleStructure.makeTop(); - m_value = JSValue(); - checkConsistency(); + makeTop(SpecBytecodeTop); } void clobberStructures() @@ -90,9 +89,9 @@ struct AbstractValue { m_value = JSValue(); } - bool isTop() const + bool isHeapTop() const { - return m_type == SpecTop && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop(); + return (m_type | SpecHeapTop) == m_type && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop(); } bool valueIsTop() const @@ -105,64 +104,18 @@ struct AbstractValue { return m_value; } - static AbstractValue top() + static AbstractValue heapTop() { AbstractValue result; - result.makeTop(); + result.makeHeapTop(); return result; } - void setMostSpecific(JSValue value) - { - if (!!value && value.isCell()) { - Structure* structure = value.asCell()->structure(); - m_currentKnownStructure = structure; - setFuturePossibleStructure(structure); - m_arrayModes = asArrayModes(structure->indexingType()); - } else { - m_currentKnownStructure.clear(); - m_futurePossibleStructure.clear(); - m_arrayModes = 0; - } - - m_type = speculationFromValue(value); - m_value = value; - - checkConsistency(); - } - - void set(JSValue value) - { - if (!!value && value.isCell()) { - m_currentKnownStructure.makeTop(); - Structure* structure = value.asCell()->structure(); - setFuturePossibleStructure(structure); - m_arrayModes = asArrayModes(structure->indexingType()); - clobberArrayModes(); - } else { - m_currentKnownStructure.clear(); - m_futurePossibleStructure.clear(); - m_arrayModes = 0; - } - - m_type = speculationFromValue(value); - m_value = value; - - checkConsistency(); - } - - void set(Structure* structure) - { - m_currentKnownStructure = structure; - setFuturePossibleStructure(structure); - m_arrayModes = asArrayModes(structure->indexingType()); - m_type = speculationFromStructure(structure); - m_value = JSValue(); - - checkConsistency(); - } + void setMostSpecific(Graph&, JSValue); + void set(Graph&, JSValue); + void set(Graph&, Structure*); - void set(SpeculatedType type) + void setType(SpeculatedType type) { if (type & SpecCell) { m_currentKnownStructure.makeTop(); @@ -178,6 +131,9 @@ struct AbstractValue { checkConsistency(); } + void fixTypeForRepresentation(NodeFlags representation); + void fixTypeForRepresentation(Node*); + bool operator==(const AbstractValue& other) const { return m_type == other.m_type @@ -232,90 +188,27 @@ struct AbstractValue { checkConsistency(); } - void filter(const StructureSet& other) + bool couldBeType(SpeculatedType desiredType) { - // FIXME: This could be optimized for the common case of m_type not - // having structures, array modes, or a specific value. - // https://bugs.webkit.org/show_bug.cgi?id=109663 - m_type &= other.speculationFromStructures(); - m_arrayModes &= other.arrayModesFromStructures(); - m_currentKnownStructure.filter(other); - if (m_currentKnownStructure.isClear()) - m_futurePossibleStructure.clear(); - else if (m_currentKnownStructure.hasSingleton()) - filterFuturePossibleStructure(m_currentKnownStructure.singleton()); - - // It's possible that prior to the above two statements we had (Foo, TOP), where - // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that - // case, we will now have (None, [someStructure]). In general, we need to make - // sure that new information gleaned from the SpeculatedType needs to be fed back - // into the information gleaned from the StructureSet. - m_currentKnownStructure.filter(m_type); - m_futurePossibleStructure.filter(m_type); - - filterArrayModesByType(); - filterValueByType(); - - checkConsistency(); + return !!(m_type & desiredType); } - void filterArrayModes(ArrayModes arrayModes) + bool isType(SpeculatedType desiredType) { - ASSERT(arrayModes); - - m_type &= SpecCell; - m_arrayModes &= arrayModes; - - // I could do more fancy filtering here. But it probably won't make any difference. - - checkConsistency(); + return !(m_type & ~desiredType); } - void filter(SpeculatedType type) - { - if (type == SpecTop) - return; - m_type &= type; - - // It's possible that prior to this filter() call we had, say, (Final, TOP), and - // the passed type is Array. At this point we'll have (None, TOP). The best way - // to ensure that the structure filtering does the right thing is to filter on - // the new type (None) rather than the one passed (Array). - m_currentKnownStructure.filter(m_type); - m_futurePossibleStructure.filter(m_type); - - filterArrayModesByType(); - filterValueByType(); - - checkConsistency(); - } + FiltrationResult filter(Graph&, const StructureSet&); - void filterByValue(JSValue value) - { - filter(speculationFromValue(value)); - if (m_type) - m_value = value; - } + FiltrationResult filterArrayModes(ArrayModes); - bool validateType(JSValue value) const - { - if (isTop()) - return true; - - if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type) - return false; - - if (value.isEmpty()) { - ASSERT(m_type & SpecEmpty); - return true; - } - - return true; - } + FiltrationResult filter(SpeculatedType); + + FiltrationResult filterByValue(JSValue); bool validate(JSValue value) const { - if (isTop()) + if (isHeapTop()) return true; if (!!m_value && m_value != value) @@ -349,35 +242,20 @@ struct AbstractValue { return 0; } - void checkConsistency() const + bool hasClobberableState() const { - if (!(m_type & SpecCell)) { - ASSERT(m_currentKnownStructure.isClear()); - ASSERT(m_futurePossibleStructure.isClear()); - ASSERT(!m_arrayModes); - } - - if (isClear()) - ASSERT(!m_value); - - if (!!m_value) - ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type); - - // Note that it's possible for a prediction like (Final, []). This really means that - // the value is bottom and that any code that uses the value is unreachable. But - // we don't want to get pedantic about this as it would only increase the computational - // complexity of the code. + return m_currentKnownStructure.isNeitherClearNorTop() + || !arrayModesAreClearOrTop(m_arrayModes); } - void dump(PrintStream& out) const - { - out.print( - "(", SpeculationDump(m_type), ", ", ArrayModesDump(m_arrayModes), ", ", - m_currentKnownStructure, ", ", m_futurePossibleStructure); - if (!!m_value) - out.print(", ", m_value); - out.print(")"); - } +#if ASSERT_DISABLED + void checkConsistency() const { } +#else + void checkConsistency() const; +#endif + + void dumpInContext(PrintStream&, DumpContext*) const; + void dump(PrintStream&) const; // A great way to think about the difference between m_currentKnownStructure and // m_futurePossibleStructure is to consider these four examples: @@ -391,7 +269,7 @@ struct AbstractValue { // y = x.f; // // Where x will later have a new property added to it, 'g'. Because of the - // known but not-yet-executed property addition, x's currently structure will + // known but not-yet-executed property addition, x's current structure will // not be watchpointable; hence we have no way of statically bounding the set // of possible structures that x may have if a clobbering event happens. So, // x's m_currentKnownStructure will be whatever structure we check to get @@ -486,57 +364,46 @@ private: m_arrayModes = ALL_ARRAY_MODES; } - void setFuturePossibleStructure(Structure* structure) + bool validateType(JSValue value) const { - if (structure->transitionWatchpointSetIsStillValid()) - m_futurePossibleStructure = structure; - else - m_futurePossibleStructure.makeTop(); + if (isHeapTop()) + return true; + + // Constant folding always represents Int52's in a double (i.e. Int52AsDouble). + // So speculationFromValue(value) for an Int52 value will return Int52AsDouble, + // and that's fine - the type validates just fine. + SpeculatedType type = m_type; + if (type & SpecInt52) + type |= SpecInt52AsDouble; + + if (mergeSpeculations(type, speculationFromValue(value)) != type) + return false; + + if (value.isEmpty()) { + ASSERT(m_type & SpecEmpty); + return true; + } + + return true; } - void filterFuturePossibleStructure(Structure* structure) + void makeTop(SpeculatedType top) { - if (structure->transitionWatchpointSetIsStillValid()) - m_futurePossibleStructure.filter(StructureAbstractValue(structure)); - } - - // We could go further, and ensure that if the futurePossibleStructure contravenes - // the value, then we could clear both of those things. But that's unlikely to help - // in any realistic scenario, so we don't do it. Simpler is better. - void filterValueByType() - { - if (!!m_type) { - // The type is still non-empty. This implies that regardless of what filtering - // was done, we either didn't have a value to begin with, or that value is still - // valid. - ASSERT(!m_value || validateType(m_value)); - return; - } - - // The type has been rendered empty. That means that the value must now be invalid, - // as well. - ASSERT(!m_value || !validateType(m_value)); + m_type |= top; + m_arrayModes = ALL_ARRAY_MODES; + m_currentKnownStructure.makeTop(); + m_futurePossibleStructure.makeTop(); m_value = JSValue(); + checkConsistency(); } - void filterArrayModesByType() - { - if (!(m_type & SpecCell)) - m_arrayModes = 0; - else if (!(m_type & ~SpecArray)) - m_arrayModes &= ALL_ARRAY_ARRAY_MODES; + void setFuturePossibleStructure(Graph&, Structure*); - // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the - // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since - // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype - // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes - // type system they are arrays (since they expose the magical length - // property and are otherwise allocated using array allocation). Hence the - // following would be wrong: - // - // if (!(m_type & SpecArray)) - // m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES; - } + void filterValueByType(); + void filterArrayModesByType(); + + bool shouldBeClear() const; + FiltrationResult normalizeClarity(); }; } } // namespace JSC::DFG