Ignore:
Timestamp:
Jul 24, 2013, 9:02:00 PM (12 years ago)
Author:
[email protected]
Message:

fourthTier: Clean up AbstractValue
https://bugs.webkit.org/show_bug.cgi?id=117217

Reviewed by Oliver Hunt.

This started as an attempt to make it so that when AbstractValue becomes empty,
its m_type always becomes SpecNone. I wanted this to happen naturally. That turns
out to be basically impossible, since AbstractValue is a set that is dynamically
computed from the intersection of several internal sets: so the value becomes
empty when any of the sets go empty. It's OK if we're imprecise here because it's
always safe for the AbstractValue to seem to overapproximate the set of values
that we see. So I mostly gave up on cleaning up that aspect of AbstractValue. But
while trying to make this happen, I encountered two bugs:

  • filterValueByType() ignores the case when m_type contravenes m_value. Namely, we might filter the AbstractValue against a SpeculatedType leading to m_value becoming inconsistent with the new m_type. This change fixes that case. This wasn't a symptomatic bug but it was a silly oversight.
  • filterFuturePossibleStructure() was never right. The one call to this method, in filter(Graph&, const StructureSet&), assumed that the previous notions of what structures the value could have in the future were still relevant. This could lead to a bug where we:

1) CheckStructure(@foo, S1)

Where S1 has a valid watchpoint. Now @foo's abstract value will have current
and future structure = S1.

2) Clobber the world.

Now @foo's abstract value will have current structure = TOP, and future
possible structure = S1.

3) CheckStructure(@foo, S2)

Now @foo's abstract value will have current structure = S2 and future
possible structure = S1 intersect S2 = BOTTOM.

Now we will think that any subsequent watchpoint on @foo is valid because the
value is effectively BOTTOM. That would only be correct if we had actually set
a watchpoint on S1. If we had done so, then (3) would only pass (i.e. @foo
would only have structure S2) if S1's watchpoint fired, in which case (3)
wouldn't have been reachable. But we didn't actually set a watchpoint on S1:
we just observed that we *could* have set the watchpoint. Hence future possible
structure should only be set to either the known structure at compile-time, or
it should be the structure we just checked; in both cases it should only be set
if the structure is watchable.

Then, in addition to all of this, I changed AbstractValue's filtering methods to
call clear() if the AbstractValue is effectively clear. This is just meant to
simplify the recognition of truly empty AbstractValues, but doesn't actually have
any other implications.

  • bytecode/StructureSet.h:

(JSC::StructureSet::dump):

  • dfg/DFGAbstractValue.cpp:

(JSC::DFG::AbstractValue::filter):
(DFG):
(JSC::DFG::AbstractValue::filterArrayModes):
(JSC::DFG::AbstractValue::filterValueByType):
(JSC::DFG::AbstractValue::filterArrayModesByType):
(JSC::DFG::AbstractValue::shouldBeClear):
(JSC::DFG::AbstractValue::normalizeClarity):
(JSC::DFG::AbstractValue::checkConsistency):

  • dfg/DFGAbstractValue.h:

(JSC::DFG::AbstractValue::isClear):
(AbstractValue):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.h

    r153129 r153208  
    5858    }
    5959   
    60     bool isClear() const
    61     {
    62         bool result = m_type == SpecNone && !m_arrayModes && m_currentKnownStructure.isClear() && m_futurePossibleStructure.isClear();
    63         if (result)
    64             ASSERT(!m_value);
    65         return result;
    66     }
     60    bool isClear() const { return m_type == SpecNone; }
    6761   
    6862    void makeTop()
     
    191185    void filter(Graph&, const StructureSet&);
    192186   
    193     void filterArrayModes(ArrayModes arrayModes)
    194     {
    195         ASSERT(arrayModes);
    196        
    197         m_type &= SpecCell;
    198         m_arrayModes &= arrayModes;
    199        
    200         // I could do more fancy filtering here. But it probably won't make any difference.
    201        
    202         checkConsistency();
    203     }
    204    
    205     void filter(SpeculatedType type)
    206     {
    207         if (type == SpecTop)
    208             return;
    209         m_type &= type;
    210        
    211         // It's possible that prior to this filter() call we had, say, (Final, TOP), and
    212         // the passed type is Array. At this point we'll have (None, TOP). The best way
    213         // to ensure that the structure filtering does the right thing is to filter on
    214         // the new type (None) rather than the one passed (Array).
    215         m_currentKnownStructure.filter(m_type);
    216         m_futurePossibleStructure.filter(m_type);
    217        
    218         filterArrayModesByType();
    219         filterValueByType();
    220        
    221         checkConsistency();
    222     }
     187    void filterArrayModes(ArrayModes arrayModes);
     188   
     189    void filter(SpeculatedType type);
    223190   
    224191    void filterByValue(JSValue value)
     
    281248    }
    282249   
    283     void checkConsistency() const
    284     {
    285         if (!(m_type & SpecCell)) {
    286             ASSERT(m_currentKnownStructure.isClear());
    287             ASSERT(m_futurePossibleStructure.isClear());
    288             ASSERT(!m_arrayModes);
    289         }
    290        
    291         if (isClear())
    292             ASSERT(!m_value);
    293        
    294         if (!!m_value)
    295             ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type);
    296        
    297         // Note that it's possible for a prediction like (Final, []). This really means that
    298         // the value is bottom and that any code that uses the value is unreachable. But
    299         // we don't want to get pedantic about this as it would only increase the computational
    300         // complexity of the code.
    301     }
     250    void checkConsistency() const;
    302251   
    303252    void dump(PrintStream&) const;
     
    315264    //
    316265    //    Where x will later have a new property added to it, 'g'. Because of the
    317     //    known but not-yet-executed property addition, x's currently structure will
     266    //    known but not-yet-executed property addition, x's current structure will
    318267    //    not be watchpointable; hence we have no way of statically bounding the set
    319268    //    of possible structures that x may have if a clobbering event happens. So,
     
    411360   
    412361    void setFuturePossibleStructure(Graph&, Structure* structure);
    413     void filterFuturePossibleStructure(Graph&, Structure* structure);
    414 
    415     // We could go further, and ensure that if the futurePossibleStructure contravenes
    416     // the value, then we could clear both of those things. But that's unlikely to help
    417     // in any realistic scenario, so we don't do it. Simpler is better.
    418     void filterValueByType()
    419     {
    420         if (!!m_type) {
    421             // The type is still non-empty. This implies that regardless of what filtering
    422             // was done, we either didn't have a value to begin with, or that value is still
    423             // valid.
    424             ASSERT(!m_value || validateType(m_value));
    425             return;
    426         }
    427        
    428         // The type has been rendered empty. That means that the value must now be invalid,
    429         // as well.
    430         ASSERT(!m_value || !validateType(m_value));
    431         m_value = JSValue();
    432     }
    433    
    434     void filterArrayModesByType()
    435     {
    436         if (!(m_type & SpecCell))
    437             m_arrayModes = 0;
    438         else if (!(m_type & ~SpecArray))
    439             m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
    440 
    441         // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the
    442         // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since
    443         // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype
    444         // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes
    445         // type system they are arrays (since they expose the magical length
    446         // property and are otherwise allocated using array allocation). Hence the
    447         // following would be wrong:
    448         //
    449         // if (!(m_type & SpecArray))
    450         //    m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
    451     }
     362
     363    void filterValueByType();
     364    void filterArrayModesByType();
     365   
     366    bool shouldBeClear() const;
     367    void normalizeClarity();
    452368};
    453369
Note: See TracChangeset for help on using the changeset viewer.