Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/GenInit.cc

    rcad355a r6cf27a07  
    2626#include "SymTab/Autogen.h"
    2727#include "GenPoly/PolyMutator.h"
     28#include "GenPoly/DeclMutator.h"
    2829
    2930namespace InitTweak {
     
    5556          public:
    5657                /// create constructor and destructor statements for object declarations.
    57                 /// Destructors are inserted directly into the code, whereas constructors
    58                 /// will be added in after the resolver has run so that the initializer expression
    59                 /// is only removed if a constructor is found
     58                /// the actual call statements will be added in after the resolver has run
     59                /// so that the initializer expression is only removed if a constructor is found
     60                /// and the same destructor call is inserted in all of the appropriate locations.
    6061                static void generateCtorDtor( std::list< Declaration * > &translationUnit );
    61 
    62                 CtorDtor() : inFunction( false ) {}
    6362
    6463                virtual DeclarationWithType * mutate( ObjectDecl * );
    6564                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl );
    66                 virtual Declaration* mutate( StructDecl *aggregateDecl );
    67                 virtual Declaration* mutate( UnionDecl *aggregateDecl );
    68                 virtual Declaration* mutate( EnumDecl *aggregateDecl );
    69                 virtual Declaration* mutate( TraitDecl *aggregateDecl );
    70                 virtual TypeDecl* mutate( TypeDecl *typeDecl );
    71                 virtual Declaration* mutate( TypedefDecl *typeDecl );
    72 
    73                 virtual Type * mutate( FunctionType *funcType );
     65                // should not traverse into any of these declarations to find objects
     66                // that need to be constructed or destructed
     67                virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }
     68                virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }
     69                virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }
     70                virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }
     71                virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; }
     72                virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; }
     73
     74                virtual Type * mutate( FunctionType *funcType ) { return funcType; }
    7475
    7576          protected:
    76                 bool inFunction;
     77        };
     78
     79        class HoistArrayDimension : public GenPoly::DeclMutator {
     80          public:
     81                typedef GenPoly::DeclMutator Parent;
     82
     83                /// hoist dimension from array types in object declaration so that it uses a single
     84                /// const variable of type size_t, so that side effecting array dimensions are only
     85                /// computed once.
     86                static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
     87
     88          private:
     89                virtual DeclarationWithType * mutate( ObjectDecl * objectDecl );
     90                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl );
     91                // should not traverse into any of these declarations to find objects
     92                // that need to be constructed or destructed
     93                virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }
     94                virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }
     95                virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }
     96                virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }
     97                virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; }
     98                virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; }
     99
     100                virtual Type* mutate( FunctionType *funcType ) { return funcType; }
     101
     102                void hoist( Type * type );
     103
     104                DeclarationNode::StorageClass storageclass = DeclarationNode::NoStorageClass;
     105                bool inFunction = false;
    77106        };
    78107
    79108        void genInit( std::list< Declaration * > & translationUnit ) {
    80109                ReturnFixer::makeReturnTemp( translationUnit );
     110                HoistArrayDimension::hoistArrayDimension( translationUnit );
    81111                CtorDtor::generateCtorDtor( translationUnit );
    82112        }
     
    124154        }
    125155
     156        void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
     157                HoistArrayDimension hoister;
     158                hoister.mutateDeclarationList( translationUnit );
     159        }
     160
     161        DeclarationWithType * HoistArrayDimension::mutate( ObjectDecl * objectDecl ) {
     162                storageclass = objectDecl->get_storageClass();
     163                DeclarationWithType * temp = Parent::mutate( objectDecl );
     164                hoist( objectDecl->get_type() );
     165                storageclass = DeclarationNode::NoStorageClass;
     166                return temp;
     167        }
     168
     169        void HoistArrayDimension::hoist( Type * type ) {
     170                // if in function, generate const size_t var
     171                static UniqueName dimensionName( "_array_dim" );
     172                if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
     173                        if ( ! inFunction ) return;
     174
     175                        if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
     176
     177                        // don't need to hoist dimension if it's a constexpr - only need to if there's potential
     178                        // for side effects.
     179                        if ( isConstExpr( arrayType->get_dimension() ) ) return;
     180
     181                        ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageclass, LinkageSpec::C, 0, SymTab::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
     182                        arrayDimension->get_type()->set_isConst( true );
     183
     184                        arrayType->set_dimension( new VariableExpr( arrayDimension ) );
     185                        addDeclaration( arrayDimension );
     186
     187                        hoist( arrayType->get_base() );
     188                        return;
     189                }
     190        }
     191
     192        DeclarationWithType * HoistArrayDimension::mutate( FunctionDecl *functionDecl ) {
     193                bool oldInFunc = inFunction;
     194                inFunction = true;
     195                DeclarationWithType * decl = Parent::mutate( functionDecl );
     196                inFunction = oldInFunc;
     197                return decl;
     198        }
    126199
    127200        void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
     
    140213
    141214        DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) {
    142                 // hands off if designated or if @=
     215                // hands off if designated, if @=, or if extern
    143216                if ( tryConstruct( objDecl ) ) {
    144                         if ( inFunction ) {
    145                                 if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->get_type() ) ) {
    146                                         // call into makeArrayFunction from validate.cc to generate calls to ctor/dtor for each element of array
    147                                         // TODO: walk initializer and generate appropriate copy ctor if element has initializer
    148                                         std::list< Expression * > args = makeInitList( objDecl->get_init() );
    149                                         if ( args.empty() ) {
    150                                                 std::list< Statement * > ctor;
    151                                                 std::list< Statement * > dtor;
    152 
    153                                                 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "?{}", back_inserter( ctor ) );
    154                                                 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "^?{}", front_inserter( dtor ), false );
    155 
    156                                                 // Currently makeArrayFunction produces a single Statement - a CompoundStmt
    157                                                 // which  wraps everything that needs to happen. As such, it's technically
    158                                                 // possible to use a Statement ** in the above calls, but this is inherently
    159                                                 // unsafe, so instead we take the slightly less efficient route, but will be
    160                                                 // immediately informed if somehow the above assumption is broken. In this case,
    161                                                 // we could always wrap the list of statements at this point with a CompoundStmt,
    162                                                 // but it seems reasonable at the moment for this to be done by makeArrayFunction
    163                                                 // itself
    164                                                 assert( ctor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( ctor.front() ) );
    165                                                 assert( dtor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( dtor.front() ) );
     217                        if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->get_type() ) ) {
     218                                // call into makeArrayFunction from validate.cc to generate calls to ctor/dtor for each element of array
     219                                // TODO: walk initializers and generate appropriate ctor if element has initializer.
     220                                // Initializer could be nested (depends on the depth of the array type on the object)
     221
     222                                std::list< Expression * > args = makeInitList( objDecl->get_init() );
     223                                if ( args.empty() ) {
     224                                        std::list< Statement * > ctor;
     225                                        std::list< Statement * > dtor;
     226
     227                                        SymTab::genImplicitCall( NULL, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
     228                                        SymTab::genImplicitCall( NULL, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     229
     230                                        // Currently genImplicitCall produces a single Statement - a CompoundStmt
     231                                        // which  wraps everything that needs to happen. As such, it's technically
     232                                        // possible to use a Statement ** in the above calls, but this is inherently
     233                                        // unsafe, so instead we take the slightly less efficient route, but will be
     234                                        // immediately informed if somehow the above assumption is broken. In this case,
     235                                        // we could always wrap the list of statements at this point with a CompoundStmt,
     236                                        // but it seems reasonable at the moment for this to be done by genImplicitCall
     237                                        // itself. It is possible that genImplicitCall produces no statements (e.g. if
     238                                        // an array type does not have a dimension). In this case, it's fine to ignore
     239                                        // the object for the purposes of construction.
     240                                        assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
     241                                        if ( ctor.size() == 1 ) {
     242                                                assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
    166243                                                objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
    167                                         } else {
    168                                                 // array came with an initializer list: initialize each element
    169                                                 // may have more initializers than elements in the array - need to check at each index that
    170                                                 // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting
    171                                                 // computation.
    172                                                 // may have fewer initializers than eleemnts in the array - need to default construct
    173                                                 // remaining elements.
    174                                                 // might be able to merge this with the case above.
    175244                                        }
    176245                                } else {
    177                                         // it's sufficient to attempt to call the ctor/dtor for the given object and its initializer
    178                                         Expression * ctor = makeCtorDtorExpr( "?{}", objDecl, makeInitList( objDecl->get_init() ) );
    179                                         Expression * dtor = makeCtorDtorExpr( "^?{}", objDecl, std::list< Expression * >() );
    180 
    181                                         // need to remember init expression, in case no ctors exist
    182                                         // if ctor does exist, want to use ctor expression instead of init
    183                                         // push this decision to the resolver
    184                                         ExprStmt * ctorStmt = new ExprStmt( noLabels, ctor );
    185                                         ExprStmt * dtorStmt = new ExprStmt( noLabels, dtor );
    186                                         objDecl->set_init( new ConstructorInit( new ImplicitCtorDtorStmt( ctorStmt ), new ImplicitCtorDtorStmt( dtorStmt ), objDecl->get_init() ) );
     246                                        // array came with an initializer list: initialize each element
     247                                        // may have more initializers than elements in the array - need to check at each index that
     248                                        // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting
     249                                        // computation.
     250                                        // may have fewer initializers than elements in the array - need to default construct
     251                                        // remaining elements.
     252                                        // might be able to merge this with the case above.
     253
    187254                                }
     255                        } else {
     256                                // it's sufficient to attempt to call the ctor/dtor for the given object and its initializer
     257                                Expression * ctor = makeCtorDtorExpr( "?{}", objDecl, makeInitList( objDecl->get_init() ) );
     258                                Expression * dtor = makeCtorDtorExpr( "^?{}", objDecl, std::list< Expression * >() );
     259
     260                                // need to remember init expression, in case no ctors exist
     261                                // if ctor does exist, want to use ctor expression instead of init
     262                                // push this decision to the resolver
     263                                ExprStmt * ctorStmt = new ExprStmt( noLabels, ctor );
     264                                ExprStmt * dtorStmt = new ExprStmt( noLabels, dtor );
     265                                objDecl->set_init( new ConstructorInit( new ImplicitCtorDtorStmt( ctorStmt ), new ImplicitCtorDtorStmt( dtorStmt ), objDecl->get_init() ) );
    188266                        }
    189267                }
     
    193271        DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) {
    194272                // parameters should not be constructed and destructed, so don't mutate FunctionType
    195                 bool oldInFunc = inFunction;
    196273                mutateAll( functionDecl->get_oldDecls(), *this );
    197                 inFunction = true;
    198274                functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) );
    199                 inFunction = oldInFunc;
    200275                return functionDecl;
    201276        }
    202 
    203         // should not traverse into any of these declarations to find objects
    204         // that need to be constructed or destructed
    205         Declaration* CtorDtor::mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }
    206         Declaration* CtorDtor::mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }
    207         Declaration* CtorDtor::mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }
    208         Declaration* CtorDtor::mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }
    209         TypeDecl* CtorDtor::mutate( TypeDecl *typeDecl ) { return typeDecl; }
    210         Declaration* CtorDtor::mutate( TypedefDecl *typeDecl ) { return typeDecl; }
    211         Type* CtorDtor::mutate( FunctionType *funcType ) { return funcType; }
    212 
    213277} // namespace InitTweak
    214278
Note: See TracChangeset for help on using the changeset viewer.