Changeset d318a18 for src/ResolvExpr


Ignore:
Timestamp:
Jul 18, 2018, 5:18:29 PM (7 years ago)
Author:
Aaron Moss <a3moss@…>
Branches:
new-env
Children:
eff03a94
Parents:
5c14030
Message:

Fix assorted memory bugs with persistent-array environment

Location:
src/ResolvExpr
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/TypeEnvironment.cc

    r5c14030 rd318a18  
    3333
    3434namespace ResolvExpr {
     35        #if 1
     36        #define PRE_POST_VALIDATE auto dbg = ValidateGuard{this, __func__};
     37        #define PRE_POST_VALIDATE_NOM auto dbg = ValidateGuard{this};
     38        struct ValidateGuard {
     39                const TypeEnvironment* env;
     40                const TypeEnvironment::Classes* old_classes;
     41                const TypeEnvironment::Bindings* old_bindings;
     42                const char* last_fn;
     43
     44                void validate_classes( const TypeEnvironment::Classes* c ) {
     45                        typedef TypeEnvironment::Classes C;
     46
     47                        assertf( c != nullptr, "classes non-null" );
     48                       
     49                        C::Mode cmode = c->get_mode();
     50                        if ( cmode == C::BASE ) {
     51                                // xxx - consistency checks
     52                        } else {
     53                                assertf( cmode == C::ADD || cmode == C::REM || cmode == C::ADDTO || cmode == C::REMFROM, "valid classes mode" );
     54                                validate_classes( c->get_base() );
     55                        }
     56                }
     57
     58                void validate_bindings( const TypeEnvironment::Bindings* b ) {
     59                        typedef TypeEnvironment::Bindings B;
     60
     61                        assertf( b != nullptr, "bindings non-null" );
     62
     63                        B::Mode bmode = b->get_mode();
     64                        if ( bmode == B::BASE ) {
     65                                // xxx - consistency checks
     66                        } else {
     67                                assertf( bmode == B::REM || bmode == B::INS || bmode == B::UPD, "valid bindings mode" );
     68                                validate_bindings( b->get_base() );
     69                        }
     70                }
     71
     72                void validate_env() {
     73                        validate_classes( env->classes );
     74                        validate_bindings( env->bindings );
     75                       
     76                        // xxx - joint validation
     77                }
     78
     79                ValidateGuard(const TypeEnvironment* e)
     80                        : env{e}, old_classes{e->classes}, old_bindings{e->bindings}, last_fn{e->last_fn}
     81                        { validate_env(); }
     82                ValidateGuard(const TypeEnvironment* e, const char* fn)
     83                        : env{e}, old_classes{e->classes}, old_bindings{e->bindings}, last_fn{fn}
     84                        { validate_env(); }
     85                ~ValidateGuard() {
     86                        validate_env();
     87                        if ( env->classes != old_classes ) validate_classes( old_classes );
     88                        if ( env->bindings != old_bindings ) validate_bindings( old_bindings );
     89                        const_cast<TypeEnvironment*>(env)->last_fn = last_fn;
     90                }
     91        };
     92        #else
     93        #define PRE_POST_VALIDATE
     94        #define PRE_POST_VALIDATE_NOM
     95        #endif
     96
    3597        void printAssertionSet( const AssertionSet &assertions, std::ostream &os, int indent ) {
    3698                for ( AssertionSet::const_iterator i = assertions.begin(); i != assertions.end(); ++i ) {
     
    53115        std::pair<interned_string, interned_string> TypeEnvironment::mergeClasses(
    54116                        interned_string root1, interned_string root2 ) {
     117                PRE_POST_VALIDATE
    55118                // merge classes
    56119                Classes* newClasses = classes->merge( root1, root2 );
     
    100163                        const TypeDecl::Data& data, AssertionSet& need, AssertionSet& have,
    101164                        const OpenVarSet& openVars, WidenMode widenMode, const SymTab::Indexer& indexer ) {
     165                PRE_POST_VALIDATE
    102166                // remove references from other, so that type variables can only bind to value types
    103167                bindTo = bindTo->stripReferences();
     
    148212                        const TypeDecl::Data& data, AssertionSet& need, AssertionSet& have,
    149213                        const OpenVarSet& openVars, WidenMode widenMode, const SymTab::Indexer& indexer ) {
     214                PRE_POST_VALIDATE
    150215                ClassRef class1 = lookup( var1->get_name() );
    151216                ClassRef class2 = lookup( var2->get_name() );
     
    237302
    238303        void TypeEnvironment::add( const Type::ForallList &tyDecls ) {
     304                PRE_POST_VALIDATE
    239305                for ( Type::ForallList::const_iterator i = tyDecls.begin(); i != tyDecls.end(); ++i ) {
    240306                        interned_string name = (*i)->get_name();
     
    245311
    246312        void TypeEnvironment::add( const TypeSubstitution & sub ) {
     313                PRE_POST_VALIDATE
    247314                interned_string not_found{nullptr};
    248315
     
    251318                       
    252319                        // filter overlapping classes out of existing environment
    253                         // (this is a very shady assumption, but has worked for a long time...)
     320                        // xxx - this is a very shady assumption, but has worked for a long time...
    254321                        interned_string root = classes->find_or_default( var, not_found );
    255322                        if ( root != not_found ) {
     
    270337
    271338        void TypeEnvironment::makeSubstitution( TypeSubstitution &sub ) const {
     339                PRE_POST_VALIDATE_NOM
    272340                bindings->for_each([&]( interned_string root, const BoundType& bound ){
    273341                        classes->for_class(root, [&]( interned_string var ) {
     
    300368        }
    301369
     370        namespace {
     371                // temporary representation of an equivalence class
     372                struct EqvClass {
     373                        std::vector<interned_string> vars;
     374                        BoundType bound;
     375
     376                        EqvClass() = default;
     377                        EqvClass(const BoundType& b) : bound{b} {}
     378                };
     379        }
     380
    302381        void TypeEnvironment::simpleCombine( const TypeEnvironment &o ) {
     382                PRE_POST_VALIDATE
     383                // check for same environment
     384                if ( classes == o.classes && bindings == o.bindings ) return;
     385
     386                // read out equivalence classes (avoids conflicting reroots)
     387                std::vector<EqvClass> ecs;
    303388                o.bindings->for_each( [&]( interned_string root, const BoundType& bound ) {
    304                         // add members of new class
     389                        ecs.emplace_back(bound);
     390                        o.classes->for_class( root, [&]( interned_string var ) {
     391                                ecs.back().vars.push_back( var );
     392                        } );
     393                } );
     394
     395                // read equivalence classes into self
     396                for ( EqvClass& ec : ecs ) {
     397                        // merge vars
    305398                        interned_string new_root{nullptr};
    306                         o.classes->for_class( root, [this,&new_root]( interned_string var ) {
    307                                 classes = classes->add( var );
     399                        for ( interned_string var : ec.vars ) {
     400                                Classes* new_classes = classes->add( var );
     401                                if ( new_classes == classes ) { var = classes->find( var ); }
     402                                else { classes = new_classes; }
    308403                                new_root = new_root ? mergeClasses( new_root, var ).first : var;
    309                         });
    310                         // set binding for new class
    311                         bindings = bindings->set( new_root, bound );
    312                 });
     404                        }
     405                        // set binding
     406                        bindings = bindings->set( new_root, ec.bound );
     407                }
    313408        }
    314409
     
    322417
    323418        void TypeEnvironment::addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ) {
     419                PRE_POST_VALIDATE
     420                if ( classes == actualEnv.classes && bindings == actualEnv.bindings ) {
     421                        // actualEnv already the same, just need to update openVars
     422                        extractOpenVars( openVars );
     423                        return;
     424                } else assertf(classes != actualEnv.classes && bindings != actualEnv.bindings, "classes & bindings updated together");
     425
     426                // read out equivalence classes (avoids conflicting reroots)
     427                std::vector<EqvClass> ecs;
    324428                actualEnv.bindings->for_each( [&]( interned_string root, const BoundType& bound ) {
    325                         // add members of new class, setting openVars concurrently
     429                        ecs.emplace_back(bound);
     430                        actualEnv.classes->for_class( root, [&]( interned_string var ) {
     431                                ecs.back().vars.push_back( var );
     432                        } );
     433                } );
     434
     435                // add members of new class, setting openVars concurrently
     436                for ( EqvClass& ec : ecs ) {
     437                        // merge vars
    326438                        interned_string new_root{nullptr};
    327                         actualEnv.classes->for_class( root, [&]( interned_string var ) {
    328                                 classes = classes->add( var );
     439                        for ( interned_string var : ec.vars ) {
     440                                openVars[ var ] = ec.bound.data;
     441                                Classes* new_classes = classes->add( var );
     442                                if ( new_classes == classes ) {
     443                                        // xxx - this case is a bit sketchy, but has been working
     444                                        // xxx - merging the classes is a departure from previous behaviour
     445                                        var = classes->find( var );
     446                                } else { classes = new_classes; }
    329447                                new_root = new_root ? mergeClasses( new_root, var ).first : var;
    330                                 openVars[ var ] = bound.data;
    331                         } );
    332                         // add new type binding without widening
     448                        }
     449                        // set binding without widening
    333450                        bindings = bindings->set( new_root,
    334                                 BoundType{ maybeClone(bound.type), false, bound.data } );
    335                 } );
     451                                BoundType{ maybeClone(ec.bound.type), false, ec.bound.data } );
     452                }
    336453        }
    337454
    338455        void TypeEnvironment::forbidWidening() {
     456                PRE_POST_VALIDATE
    339457                bindings = bindings->mutate_each([]( const interned_string&, BoundType& c ) {
    340458                        if ( c.allowWidening ) {
     
    352470
    353471        PassVisitor<GcTracer> & operator<<( PassVisitor<GcTracer> & gc, const TypeEnvironment & env ) {
    354                 for ( ClassRef c : env ) {
    355                         maybeAccept( c.get_bound().type, gc );
    356                 }
     472                gc.pass.visit( env );
     473                // for ( ClassRef c : env ) {
     474                //      maybeAccept( c.get_bound().type, gc );
     475                // }
    357476                return gc;
    358477        }
  • src/ResolvExpr/TypeEnvironment.h

    r5c14030 rd318a18  
    138138        };
    139139
     140        class ValidateGuard;
     141
    140142        class TypeEnvironment {
    141143                friend ClassRef;
    142 
     144                friend GcTracer;
     145               
    143146                /// Backing storage for equivalence classes
    144147                using Classes = PersistentDisjointSet<interned_string>;
     
    152155                /// may be null.
    153156                Bindings* bindings;
     157
     158                // for debugging
     159                friend ValidateGuard;
     160                const char* last_fn = "<none>";
    154161
    155162                /// Merges the classes rooted at root1 and root2, returning a pair containing the root and
     
    234241        T ClassRef::get_vars() const {
    235242                T vars;
    236                 if ( ! env->classes->count( root ) ) return vars;
    237243                env->classes->for_class( root, [&vars]( interned_string var ) {
    238244                        vars.insert( vars.end(), var );
Note: See TracChangeset for help on using the changeset viewer.