C-Breeze
C Compiler Infrastructure

[ Project home page]
Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

pointers.cc

Go to the documentation of this file.
00001 // $Id: pointers.cc,v 1.52 2003/08/08 15:16:29 toktb Exp $
00002 // ----------------------------------------------------------------------
00003 //
00004 //  C-Breeze
00005 //  C Compiler Framework
00006 // 
00007 //  Copyright (c) 2000 University of Texas at Austin
00008 // 
00009 //  Samuel Z. Guyer
00010 //  Daniel A. Jimenez
00011 //  Calvin Lin
00012 // 
00013 //  Permission is hereby granted, free of charge, to any person
00014 //  obtaining a copy of this software and associated documentation
00015 //  files (the "Software"), to deal in the Software without
00016 //  restriction, including without limitation the rights to use, copy,
00017 //  modify, merge, publish, distribute, sublicense, and/or sell copies
00018 //  of the Software, and to permit persons to whom the Software is
00019 //  furnished to do so, subject to the following conditions:
00020 //  
00021 //  The above copyright notice and this permission notice shall be
00022 //  included in all copies or substantial portions of the Software.
00023 //  
00024 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00025 //  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00026 //  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00027 //  NONINFRINGEMENT.  IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT
00028 //  AUSTIN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00029 //  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
00030 //  OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00031 //  THE SOFTWARE.
00032 //
00033 //  We acknowledge the C-to-C Translator from MIT Laboratory for
00034 //  Computer Science for inspiring parts of the C-Breeze design.
00035 //
00036 // ----------------------------------------------------------------------
00037 
00038 #include "c_breeze.h"
00039 #include "print_walker.h"
00040 #include "pointers.h"
00041 
00042 long int Pointers::call_counter;
00043 
00044 // ------------------------------------------------------------
00045 //  Pointer options
00046 // ------------------------------------------------------------
00047 
00050 bool pointerOptions::Context_insensitive = false;
00051 
00054 bool pointerOptions::Recursion_Context_sensitive = true; // TB
00055 
00058 bool pointerOptions::Use_multiplicity = true;
00059 
00062 bool pointerOptions::Verbose = false;
00063   
00070 bool pointerOptions::Show_memoryblocks = false;
00071 
00077 bool pointerOptions::Show_procedures = false;
00078 
00081 bool pointerOptions::Pointer_statistics = false;
00082 
00088 bool pointerOptions::Ignore_fields = false;
00089 
00096 bool pointerOptions::One_struct_per_type = false;
00097 
00100 bool pointerOptions::Show_stack = false;
00101 
00110 bool pointerOptions::Flow_insensitive = false;
00111 
00112 // TB_unify
00117 bool pointerOptions::Unification = false;
00118 
00119 // TB_unify
00122 bool pointerOptions::Unification_use_annotation = true;
00123 
00126 bool pointerOptions::Show_Unification = false;
00127 
00133 bool pointerOptions::Conditional_analysis = false;
00134 
00142 bool pointerOptions::Bidirectional_assignment = false;
00143 
00161 bool pointerOptions::Aggressive_multiplicity = false;
00162 
00169 bool pointerOptions::One_string_constant = true;
00170 
00177 bool pointerOptions::Context_insensitive_memory = false; // true;
00178 
00184 bool pointerOptions::Use_escape_analysis = false;
00185 
00190 bool pointerOptions::Verbose_unification = false;
00191 
00196 bool pointerOptions::Verbose_constants = false;
00197 
00202 bool pointerOptions::Verbose_liveness = false;
00203 
00207 bool pointerOptions::Show_unknown_procedures = false;
00208 
00214 bool pointerOptions::Show_memory_leaks = false;
00215 
00221 bool pointerOptions::Monitor_precision = false;
00222 
00228 str_set pointerOptions::Context_sensitive_procedures;
00229 
00235 flow_sensitive_set pointerOptions::Flow_sensitive_objects;
00236 
00242 flow_sensitive_set pointerOptions::Flow_sensitive_allocation_objects;
00243 
00244 // TB_unify
00250 UnifyTypes pointerOptions::Non_unify_types;
00251 
00253 int pointerOptions::Unify_objects = 0;
00254 
00261 basicblock_set pointerOptions::Path_sensitive_branches;
00262 
00267 str_set pointerOptions::Verbose_procedures;
00268 
00269 
00270 
00271 // ------------------------------------------------------------
00272 // Constructor
00273 // ------------------------------------------------------------
00274 
00275 Pointers::Pointers(procNode * root, Linker & l, unitNode * unit)
00276   : Memory(),
00277     HeapMap(),
00278     Root(root),
00279     root_location(0),
00280     linker(l),
00281     Procedures(),
00282     _constants(),
00283     Problem(0),
00284     computePointers(true),
00285     _direction(Forward),
00286     _procedureCount(0),
00287     _skipCount(0),
00288     _show_progress(true),
00289     _use_multiplicity(true),
00290     _unknown_procedures(),
00291     _def_accuracy(),
00292     _star_accuracy(),
00293     _unification_based(0)
00294 {
00295   _constants.set_null_object(Memory.null());
00296 }
00297 
00298 Pointers::~Pointers()
00299 {
00300   delete root_location;
00301 
00302   for (heap_map_p p = HeapMap.begin();
00303        p != HeapMap.end();
00304        ++p)
00305     {
00306       delete (*p).second;
00307     }
00308 }
00309 
00310 
00311 void Pointers::run_unification() {
00312   if(pointerOptions::Unification) {
00313     if(pointerOptions::Show_Unification || pointerOptions::Verbose)
00314       cout << "Start unification-based analysis\n";
00315     _unification_based = UnificationBasedPtr::analyze_all(linker);
00316     Memory.unification(_unification_based);
00317     if(pointerOptions::Show_Unification || pointerOptions::Verbose)
00318       cout << "Unification-based analysis done\n";
00319     if(pointerOptions::Show_Unification)
00320       _unification_based->print_ecr();
00321   }
00322 } // run_unification
00323 
00324 // ------------------------------------------------------------
00325 // Analyze
00326 // ------------------------------------------------------------
00327 
00328 void Pointers::analyze()
00329 {
00330   // -- Check to see if this is a re-analysis
00331 
00332   if (root_location) {
00333 
00334     // -- It is, so make sure all the data structures are clear.
00335 
00336     // -- Delete all memory blocks
00337 
00338     Memory.clear();
00339 
00340     // -- Clear the heap mapping
00341 
00342     HeapMap.clear();
00343 
00344     // -- Reset the computePointers flag
00345 
00346     computePointers = true;
00347 
00348     // -- Make sure the direction of analysis is Forward
00349 
00350     _direction = Forward;
00351 
00352     // -- Delete all the location objects
00353 
00354     delete root_location;
00355 
00356     // -- Clear the user-defined problem
00357 
00358     Problem = 0;
00359 
00360     // -- All other components will reinitialize themselves
00361   }
00362 
00363   // -- Run the linker to build a global symbol table
00364 
00365   // linker.link();
00366 
00367   // -- Build the procedure database
00368 
00369   Procedures.build(Root, linker);
00370 
00371   // -- Set up the main() location (must be done *after* build above).
00372 
00373   root_location = new procLocation(0, Root);
00374 
00375   // -- Run the analyzer
00376 
00377   memoryblock_set external_defs;
00378   memoryuse_set external_uses;
00379   memoryblock_set external_changes;
00380 
00381   _procedureCount = 0;
00382   _skipCount = 0;
00383   int iterations = 0;
00384   call_counter = 0;
00385 
00386   if (_show_progress)
00387     cout << "  ==== Analyze Pointers ====" << endl;
00388 
00389   procedureInfo * root_info = Procedures.lookup(root_location->proc());
00390 
00391   Procedures.setup_analysis();
00392 
00393   bool done = false;
00394 
00395   pointerValue main_return;
00396 
00397   // -- This is a chance for a subclass to run some initialization
00398 
00399   initialize();
00400 
00401   // -- Run the analysis
00402 
00403   do {
00404 
00405     Procedures.call_to((stmtLocation *)0, root_info);
00406 
00407     root_info->start_self_timer();
00408     root_info->start_total_timer();
00409 
00410     analyze_procedure(root_location, 
00411                       external_defs,
00412                       external_uses,
00413                       external_changes);
00414 
00415     Procedures.return_from();
00416 
00417     root_info->stop_self_timer();
00418     root_info->stop_total_timer();
00419 
00420     iterations++;
00421 
00422     bool needs_reanalysis = Procedures.is_reanalysis_required(root_info);
00423 
00424     done = ( ! needs_reanalysis) || (iterations > 10);
00425 
00426     // Procedures.print_leftovers();
00427 
00428     if (_show_progress && ! done)
00429       cout << "  ---- Reanalyze ----" << endl;
00430 
00431   } while ( ! done );
00432 
00433   // -- Set up the def-use chains
00434 
00435   Memory.update_def_use_chains();
00436 
00437   computePointers = false;
00438 
00439   // -- Show unkown procedures
00440 
00441   if (pointerOptions::Show_unknown_procedures) {
00442     cout << "-----------------------------------------------------------" << endl;
00443     cout << "Unknown procedures:" << endl;
00444     for (string_set_p p = _unknown_procedures.begin();
00445          p != _unknown_procedures.end();
00446          ++p)
00447       cout << "  " << (*p) << endl;
00448     pointerOptions::Show_unknown_procedures = false;
00449   }
00450 }
00451 
00452 void Pointers::analyze(analysisProblem * problem)
00453 {
00454   // -- See if pointers have been computed at all..
00455 
00456   if (computePointers == true) {
00457 
00458     // -- Run the linker to build a global symbol table
00459 
00460     // linker.link();
00461 
00462     // -- Build the procedure database
00463 
00464     Procedures.build(Root, linker);
00465 
00466     // -- Set up the main() location (must be done *after* build above).
00467 
00468     root_location = new procLocation(0, Root);
00469   }
00470 
00471   Problem = problem;
00472 
00473   _direction = problem->direction();
00474 
00475   memoryblock_set external_defs;
00476   memoryuse_set external_uses;
00477   memoryblock_set external_changes;
00478 
00479   _procedureCount = 0;
00480   _skipCount = 0;
00481   int iterations = 0;
00482   call_counter = 0;
00483 
00484   if (_show_progress)
00485     cout << "  ==== Analyze " << Problem->name() << " ====" << endl;
00486 
00487   procedureInfo * root_info = Procedures.lookup(root_location->proc());
00488 
00489   Procedures.setup_analysis();
00490 
00491   bool done = false;
00492 
00493   pointerValue main_return;
00494 
00495   // -- This is a chance for a subclass to run some initialization
00496 
00497   initialize();
00498 
00499   // -- Run the analysis
00500 
00501   do {
00502 
00503     root_info->start_self_timer();
00504     root_info->start_total_timer();
00505 
00506     Procedures.call_to((stmtLocation *)0, root_info);
00507 
00508     if (Problem) {
00509       if (_direction == Forward)
00510         Problem->at_procedure_entry(root_location, root_info, main_return);
00511       else
00512         Problem->at_procedure_exit(root_location, root_info, main_return);
00513     }
00514       
00515     analyze_procedure(root_location, 
00516                       external_defs,
00517                       external_uses,
00518                       external_changes);
00519 
00520     if (Problem) {
00521       if (_direction == Forward)
00522         Problem->at_procedure_exit(root_location, root_info, main_return);
00523       else
00524         Problem->at_procedure_entry(root_location, root_info, main_return);
00525     }
00526       
00527     Procedures.return_from();
00528 
00529     root_info->stop_self_timer();
00530     root_info->stop_total_timer();
00531 
00532     iterations++;
00533 
00534     bool needs_reanalysis = Procedures.is_reanalysis_required(root_info);
00535 
00536     done = ( ! needs_reanalysis) || (iterations > 10);
00537 
00538     if (_show_progress)
00539       Procedures.print_leftovers();
00540 
00541     if (_show_progress && ! done)
00542       cout << "    ---- Reanalyze ----" << endl;
00543 
00544   } while ( ! done );
00545 
00546   Problem = 0;
00547 
00548   // -- Record the fact that we've computed the pointers
00549 
00550   computePointers = false;
00551 
00552   // -- Show unkown procedures
00553 
00554   if (pointerOptions::Show_unknown_procedures) {
00555     cout << "-----------------------------------------------------------" << endl;
00556     cout << "Unknown procedures:" << endl;
00557     for (string_set_p p = _unknown_procedures.begin();
00558          p != _unknown_procedures.end();
00559          ++p)
00560       cout << "  " << (*p) << endl;
00561     pointerOptions::Show_unknown_procedures = false;
00562   }
00563 
00564   if (pointerOptions::Show_procedures)
00565     Procedures.stats(cout);
00566 }
00567 
00569 /*
00570 void Pointers::reanalyze_at(procedureInfo * info, stmtLocation * callsite)
00571 {
00572   // -- Get the caller at this callsite
00573 
00574   procedureInfo * caller = info->caller_at(callsite);
00575 
00576   // -- Get the actual expression for the callsite
00577 
00578   exprstmtNode * stmt = (exprstmtNode *) callsite->stmt();
00579   exprNode * E = stmt->expr();
00580 
00581   // -- Store the defs, uses and changes, and the result
00582 
00583   memoryblock_set defs;
00584   memoryuse_set uses;
00585   memoryblock_set changes;
00586   pointerValue result;
00587 
00588   // -- Run the analyzer
00589 
00590   eval(caller, callsite, E,
00591        defs, uses, changes,
00592        result, true);
00593 
00594   // -- If anything changed here, put the caller back on the worklist
00595 
00596   if ( ! changes.empty())
00597     Procedures.mark_for_reanalysis(caller, callsite);
00598 }
00599 */
00600 // ------------------------------------------------------------
00601 // Analyze a single procedure
00602 // ------------------------------------------------------------
00603 
00604 
00605 void Pointers::analyze_procedure(procLocation * current,
00606                                  memoryblock_set & defs,
00607                                  memoryuse_set & uses,
00608                                  memoryblock_set & changes)
00609 {
00610   procNode * procedure = current->proc();
00611   basicblockNode * procedure_exit = procedure->exit();
00612 
00613   // -- Look up the current procedure information
00614 
00615   procedureInfo * info = Procedures.lookup(procedure);
00616 
00617   info->add_all_blocks();
00618   info->incr_analysis_count();
00619 
00620   // -- Collect all the defs (whether or not they change) and uses
00621   /*
00622   memoryblock_set defs;
00623   memoryuse_set uses;
00624   memoryblock_set changes;
00625   */
00626 
00627   // === MAIN LOOP: until the worklist is empty...
00628 bool hack = pointerOptions::Verbose;
00629 pointerOptions::Verbose = info->is_verbose();
00630   while ( ! info->is_empty() ) {
00631 
00632     // -- Get the next basic block off the list
00633 
00634     basicblockNode * bb = info->get_next_block(_direction);
00635     basicblockLocation * current_block = current->lookup_block(bb);
00636 
00637     // -- Set tree numbering minimum
00638 
00639     current_block->visit();
00640 
00641     // -- Print some information about the current block
00642 
00643     if (pointerOptions::Verbose)
00644       cout << "==== " << *current_block << " ====" << endl << endl;
00645 
00646     // -- Use this flag to record if this basic block calls a procedure
00647     // that never returns.
00648 
00649     bool never_returns = false;
00650 
00651     // -- IP Analyzer: Initialize the flow value for this block
00652 
00653     pointerValue result;
00654 
00655     if (Problem) {
00656       if (_direction == Forward)
00657         Problem->at_basicblock_entry(current_block, info, result);
00658       else
00659         Problem->at_basicblock_exit(current_block, info, result);
00660     }
00661 
00662     // -- Keep a list of the changes that occur in this block. Distinguish
00663     // between those caused by processing any phi functions, and those
00664     // cause by regular statements.
00665 
00666     memoryblock_set merge_changes;
00667     memoryblock_set stmt_changes;
00668 
00669     // -- Record the value of the branch
00670 
00671     const constant * branch_value = _constants.bottom();
00672 
00673     // -- Process the merge point now, if the direction is Forward
00674     // (otherwise, we'll process it at the end of the basic block).
00675 
00676     if (_direction == Forward)
00677       process_merge_point(info, current_block, result, defs, uses, merge_changes);
00678 
00679     // -- Visit each statement and corresponding statement location
00680 
00681     stmt_list & stmts = bb->stmts();
00682     stmt_location_vec & stmt_locs = current_block->statements();
00683 
00684     // Current statement location (we'll also save this value to hold the
00685     // last statement for use during the insertion of merge points).
00686 
00687     stmtLocation * current_stmt = 0;
00688     stmtLocation * previous_stmt = 0;
00689 
00690     stmt_list_p stmt_p;
00691     int stmt_num;
00692     int number_of_statements = stmts.size();
00693 
00694     // -- Start at the beginning or end, depending on the direction
00695 
00696     if (_direction == Forward) {
00697       stmt_p = stmts.begin();
00698       stmt_num = 0;
00699     }
00700     else {
00701       stmt_p = stmts.end();
00702       stmt_p--;
00703       stmt_num = number_of_statements - 1;
00704     }
00705 
00706     for (int counter = 0; counter < number_of_statements; counter++)
00707       {
00708         // -- Get the current statement and statement location
00709 
00710         stmtNode * statement = *stmt_p;
00711         current_stmt = & (stmt_locs[stmt_num]);
00712 
00713         // -- Print out the current statement
00714 
00715         if (pointerOptions::Verbose) {
00716           cout << "---- " << *current_stmt << " -- (" << statement->coord() << ") ----" << endl;
00717 
00718           output_context oc(cout);
00719           statement->output(oc, 0);
00720           cout << endl << endl;
00721         }
00722 
00723         // -- Set tree numbering minimum (do this *after* processing the
00724         // statement -- see special call after finishing a procedure).
00725 
00726         current_stmt->visit();
00727 
00728         // -- Check the never_returns flag: if it's true, then break out
00729         // immediately.
00730 
00731         if ( ! never_returns) {
00732 
00733           // -- IP Analyzer: Initialize the flow value for this statement
00734 
00735           result.initialize_pointers();
00736           _constants.at_stmt_entry(current_stmt, result);
00737 
00738           if (Problem) {
00739             if (_direction == Forward)
00740               Problem->at_stmt_entry(current_stmt, result);
00741             else
00742               Problem->at_stmt_exit(current_stmt, result);
00743           }
00744 
00745           // -- Handle the different statement types
00746 
00747           // == CASE 1: (Used to be return statement: now it's handled more
00748           // directly by pass_return_value().
00749 
00750           // == CASE 2: Plain expression statement
00751 
00752           if (statement->typ() == Expr) // TB: changed.
00753             assert(! ((exprstmtNode*) statement)->expr() );
00754 
00755           // TB: adopt from case Expr.
00756           if(statement->typ() == ThreeAddr) {
00757             // -- Special case: If we're about to make a procedure call, then
00758             // make sure process all the changes that have happened so far
00759             // right now.
00760           /*
00761           callNode * call = current_stmt->callnode();
00762           if (call) {
00763             if ( ! merge_changes.empty() ||
00764                  ! stmt_changes.empty()) {
00765 
00766               if (pointerOptions::Verbose) {
00767                 print_memoryblock_def_set("  Phi  Changes   : ", merge_changes, cout);
00768                 print_memoryblock_def_set("  Stmt Changes   : ", stmt_changes, cout);
00769               }
00770 
00771               // -- Post-process the changes from this basic block. We set up merge
00772               // points for each block, and transfer the local changes to the
00773               // global change set.
00774 
00775               process_local_changes(info, current_block, merge_changes, changes);
00776               process_local_changes(info, current_block, stmt_changes, changes);
00777 
00778               // -- Record the external inputs and outputs
00779 
00780               record_external_inputs_and_outputs(info, current,
00781                                                  changes, external_changes,
00782                                                  all_nonlocal_changes,
00783                                                  uses, external_uses);
00784             }
00785           }
00786           */
00787             // -- Don't generate a use of the result
00788 
00789             result.is_a_use = false;
00790 
00791             threeAddrNode * t = (threeAddrNode *) statement;
00792             eval(info, current_stmt, t,
00793                  defs, uses, stmt_changes, result, never_returns);
00794           
00795             // -- IP Analyzer: Expression statement transfer function
00796 
00797             if (Problem)
00798               Problem->at_threeAddr(current_stmt, t, result);
00799           }
00800 
00801           // == CASE 3: If statement
00802 
00803           if (statement->typ() == If)
00804             assert(false);
00805 
00806           // TB: adopt from case If.
00807           if(statement->typ() == Condition) {
00808             // -- Here the result is used
00809 
00810             pointerValue left, right;
00811             left.is_a_use = true;
00812             right.is_a_use = true;
00813             result.is_a_use = true;
00814 
00815             conditiongotoNode * C = (conditiongotoNode *) statement;
00816             if (C->left()) {
00817               eval(info, current_stmt, C->left(), statement,
00818                    defs, uses, stmt_changes, left, never_returns);
00819 
00820               if (C->right()) {
00821                 eval(info, current_stmt, C->right(), statement,
00822                      defs, uses, stmt_changes, right, never_returns);
00823                 _constants.at_binary(current_stmt, C, left, right, result);
00824               } else
00825                 _constants.at_unary(current_stmt, C, left, result);
00826             }
00827 
00828             // -- IP Analyzer: If statement transfer function
00829             
00830             if (Problem)
00831               Problem->at_conditiongoto(current_stmt, C, result);
00832 
00833             // -- Record the value of the branch
00834 
00835             if (result.constant_value)
00836               branch_value = result.constant_value;
00837           }
00838 
00839           // -- End of the statement
00840 
00841           if (Problem) {
00842             if (_direction == Forward)
00843               Problem->at_stmt_exit(current_stmt, result);
00844             else
00845               Problem->at_stmt_entry(current_stmt, result);
00846           }
00847         }
00848 
00849         // -- Go to the next statement, depending on direction
00850 
00851         if (_direction == Forward) {
00852           stmt_p++;
00853           stmt_num++;
00854         }
00855         else {
00856           stmt_p--;
00857           stmt_num--;
00858         }
00859       } // END For all statements
00860 
00861     // When done with the basic block, take all the changed memoryBlocks
00862     // and set up merge points for them.
00863 
00864     if (pointerOptions::Verbose) {
00865       cout << "          --- (end basic block) ---" << endl << endl;
00866     }
00867 
00868     // -- Set tree numbering maximum: if the basic block doesn't dominate
00869     // anything, then zip up the dominator tree.
00870 
00871     if (bb->children().empty() &&
00872         (bb != procedure->exit()))
00873       {
00874         stmtLocation * last = current_block->last();
00875         last->finish();
00876       }
00877 
00878     // -- Handle changes: add merge-points in the appropriate places, and
00879     // update the worklists
00880 
00881     if ( ! merge_changes.empty() ||
00882          ! stmt_changes.empty())
00883       {
00884 
00885         if (pointerOptions::Verbose) {
00886           print_memoryblock_def_set("  Phi  Changes   : ", merge_changes, cout);
00887           print_memoryblock_def_set("  Stmt Changes   : ", stmt_changes, cout);
00888         }
00889 
00890         if ( ! never_returns ) {
00891 
00892           // -- Post-process the changes from this basic block. We set up
00893           // merge points for each block, and transfer the local changes to
00894           // the global change set.
00895         
00896           process_local_changes(info, current_block, merge_changes, changes);
00897           process_local_changes(info, current_block, stmt_changes, changes);
00898           // -- Add all reachable basic blocks to the worklist
00899 
00900           //if ( ! stmt_changes.empty())
00901 
00902           info->add_reachable_blocks(bb, Forward);
00903         }
00904       }
00905 
00906     // -- This is not a real merge-point; we just need this here for
00907     // backward analyses, which need to see the merge points *after* the
00908     // statements in the block.
00909 
00910     if (_direction == Backward)
00911       process_merge_point(info, current_block, result, defs, uses, merge_changes);
00912 
00913     // -- IP Analyzer: End of the basic block
00914 
00915     if (Problem) {
00916       if (_direction == Forward)
00917         Problem->at_basicblock_exit(current_block, info, result);
00918       else
00919         Problem->at_basicblock_entry(current_block, info, result);
00920     }
00921 
00922     // -- Conditional analysis
00923 
00924     if (pointerOptions::Conditional_analysis) {
00925 
00926       bool has_truth_value = false;
00927       bool which_branch = false;
00928       
00929       has_truth_value = _constants.has_truth_value(branch_value, which_branch);
00930       if (has_truth_value) {
00931 
00932         // -- The branch has a definite value
00933 
00934         if (pointerOptions::Verbose)
00935           cout << "Found constant branch at " << * current_block
00936                << " -- value = " << _constants.to_string(branch_value) << endl;
00937       }
00938 
00939       // -- Run the special worklist algorithm, with the following
00940       // exception: if the basic block we just processed calls exit() or
00941       // abort() (or another procedure that never returns), then don't
00942       // activate any of the outgoing edges.
00943 
00944       if ( ! never_returns)
00945         info->update_conditional_worklist(bb, has_truth_value, which_branch);
00946     }
00947 
00948     // -- Check the never_returns flag: if this basic block calls exit() or
00949     // abort(), and it dominates the exit of the procedure, then the
00950     // procedure itself never returns.
00951 
00952     if (never_returns &&
00953         Dominators::dominates(bb, procedure_exit)) {
00954 
00955       info->set_never_returns();
00956 
00957       if (pointerOptions::Verbose)
00958         cout << info->qualified_name() << " never returns." << endl;
00959     }
00960 
00961   } // END until worklist empty
00962 pointerOptions::Verbose = hack;
00963 }
00964 
00965 // ------------------------------------------------------------
00966 // Procedure call 
00967 // ------------------------------------------------------------
00968 
00969 void Pointers::procedure_call(procedureInfo * caller,
00970                               stmtLocation * callsite,
00971                               operandNode * call,
00972                               operand_list & args,
00973                               pointerValue & call_target,
00974                               memoryBlock * target_mb,
00975                               pointervalue_list & arguments,
00976                               memoryblock_set & external_defs,
00977                               memoryuse_set & external_uses,
00978                               memoryblock_set & external_changes,
00979                               pointerValue & return_val,
00980                               bool & never_returns)
00981 {
00982   procedureInfo * info = 0;
00983   bool resolved = false;
00984   bool recursive_call = false;
00985   procNode * callee = 0;
00986 
00987   // ------- Special-case procedure calls ---------------------------
00988     
00989   // -- Is this a call to *alloc or *free?
00990 
00991   if (is_allocation(call_target)) {
00992 
00993     // -- Call the allocation method
00994 
00995     memoryBlock * alloc_block;
00996 
00997     string name = caller->proc()->decl()->name() + "/malloc";
00998 
00999     alloc_block = at_allocation(name, caller,
01000                                 callsite, callsite->stmt(), (declNode *)0,
01001                                 external_defs, external_uses, external_changes,
01002                                 return_val);
01003 
01004     if (pointerOptions::Verbose)
01005       cout << "Allocate heap object: " << alloc_block->name() << endl;
01006 
01007     // -- IP Analyzer: Memory allocation transfer function  
01008 
01009     if (Problem)
01010       Problem->at_allocation(callsite, arguments, alloc_block, external_changes);
01011 
01012     return;
01013   }
01014 
01015   if (is_deallocation(call_target)) {
01016 
01017     // -- First, dereference the pointer argument
01018         
01019     pointerValue & dealloc_ptrs = arguments.front();
01020     pointerValue to_deallocate;
01021         
01022     star_operator(caller, callsite, dealloc_ptrs,
01023                   external_defs, external_uses, external_changes, to_deallocate);
01024         
01025     if (pointerOptions::Verbose)
01026       print_memoryblock_set("Deallocate heap objects: ", to_deallocate.blocks, cout);
01027         
01028     // -- Call the deallocation routine for each target
01029         
01030     at_deallocation(caller, callsite, to_deallocate,
01031                     external_defs, external_uses, external_changes);
01032     
01033     // -- IP Analyzer: Memory deallocation transfer function  
01034         
01035     if (Problem)
01036       Problem->at_deallocation(callsite, to_deallocate, external_changes);
01037         
01038     return;
01039   }
01040       
01041   if (is_reallocation(call_target)) {
01042         
01043     // -- Realloc is basically a no-op
01044         
01045     pointerValue & realloc_ptrs = arguments.front();
01046         
01047     // -- Just dump the input pointers into the return value
01048         
01049     star_operator(caller, callsite, realloc_ptrs,
01050                   external_defs, external_uses, external_changes, return_val);
01051     return_val.is_address = true;
01052     
01053     if (pointerOptions::Verbose)
01054       print_memoryblock_set("Reallocate heap objects: ", return_val.blocks, cout);
01055     
01056     return;
01057   }
01058       
01059   if (is_va_arg(call_target)) {
01060         
01061     // -- va_arg works by just dereferencing the va_list object, which
01062     // should by the first argument.
01063         
01064     pointerValue & varargs_list = arguments.front();
01065         
01066     // -- Just dump the resulting objects into the return value
01067         
01068     star_operator(caller, callsite, varargs_list,
01069                   external_defs, external_uses, external_changes, return_val);
01070     return_val.is_address = true;
01071     
01072     if (pointerOptions::Verbose)
01073       print_memoryblock_set("Get varargs objects: ", return_val.blocks, cout);
01074         
01075     return;
01076   }
01077       
01078   if (is_va_start(call_target) ||
01079       is_va_end(call_target))
01080     return;
01081   
01082   if (is_exit(call_target)) {
01083         
01084     // -- This is a call to exit() or abort() or some other procedure that
01085     // never returns. Set the never_returns flag.
01086         
01087     never_returns = true;
01088     return;
01089   }
01090 
01091   // -- Look up the target procedure
01092 
01093   // target_mb = * (call_target.blocks.begin());
01094 
01095   callee = linker.lookup_procedure(target_mb->decl());
01096   if (callee == 0) {
01097         
01098     if (pointerOptions::Verbose)
01099       cout << "WARNING: No source for " << target_mb->name() << 
01100         " at " << * callsite << endl;
01101         
01102     _unknown_procedures.insert(target_mb->name());
01103   }
01104   else {
01105         
01106     // -- Make callNode point to the called procedure
01107     
01108     // TODO?? call->proc(callee);
01109         
01110     resolved = true;
01111   }
01112 
01113   // ------ Can we procede? -----------------------
01114 
01115   if ( ! resolved ) {
01116 
01117     // -- Conservative: assume all reachable memory blocks could be read or
01118     // modified.
01119 
01120     return;
01121 
01122     memoryblock_set reachable_blocks;
01123     conservative_procedure_call(caller, callsite, arguments, reachable_blocks,
01124                                 external_defs, external_uses, external_changes,
01125                                 return_val);
01126 
01127     // -- Constant propagation
01128 
01129     _constants.at_conservative_procedure_call(callsite, call, args, call_target,
01130                                               arguments, reachable_blocks,
01131                                               return_val, external_changes);
01132 
01133     // -- User-defined analysis
01134 
01135     if (Problem)
01136       Problem->at_conservative_procedure_call(callsite, call, args, call_target,
01137                                               arguments, reachable_blocks,
01138                                               return_val, external_changes);
01139 
01140     return;
01141   }
01142 
01143   // ------- All other procedures -----------------------------------
01144 
01145   // -- User-defined analysis
01146 
01147   if (Problem)
01148     Problem->at_call(callsite, call, call_target, callee, arguments, return_val);
01149 
01150   // -- Look up the procedure information
01151 
01152   info = Procedures.lookup(callee);
01153 
01154   // -- Check for recursion.
01155 
01156   int num_instances = 0;
01157   recursive_call = Procedures.is_recursive_call(info, num_instances);
01158 
01159   // -- Check for multiple targets
01160 
01161   bool multiple_call_targets = false;
01162 
01163   if (call_target.blocks.size() > 1)
01164     multiple_call_targets = true;
01165 
01166   // -- Set up the call, including managing context sensitivity
01167 
01168   info->setup_call_at(caller, callsite, recursive_call, multiple_call_targets);
01169 
01170   // -- Timers
01171 
01172   caller->stop_self_timer();
01173 
01174   if (! recursive_call) {
01175     info->start_self_timer();
01176     info->start_total_timer();
01177   }
01178 
01179   // -- Run the analyzer at this particular call site
01180 
01181   analyze_procedure_at(info, callsite, arguments,
01182                        external_defs,
01183                        external_uses,
01184                        external_changes,
01185                        return_val);
01186 
01187   // -- Timers
01188 
01189   caller->start_self_timer();
01190 
01191   if (! recursive_call) {
01192     info->stop_self_timer();
01193     info->stop_total_timer();
01194   }
01195 
01196   // -- Pick up any pending external changes for this callsite. We need
01197   // to do this *after* calling pass_external_outputs.
01198 
01199   memoryblock_set pending_changes;
01200   caller->get_pending_changes(callsite, pending_changes);
01201 
01202   if ( ! pending_changes.empty()) {
01203 
01204     if (pointerOptions::Verbose)
01205       print_memoryblock_set("  => Pickup pending changes: ", pending_changes, cout);
01206     
01207     external_changes.insert(pending_changes.begin(), pending_changes.end());
01208   }
01209 
01210   // -- Check to see if the procedure never returns, and pass that value
01211   // up.
01212 
01213   never_returns = info->never_returns();
01214 }
01215 
01216 void Pointers::analyze_procedure_at(procedureInfo * info,
01217                                     stmtLocation * callsite,
01218                                     pointervalue_list & arguments,
01219                                     memoryblock_set & external_defs,
01220                                     memoryuse_set & external_uses,
01221                                     memoryblock_set & external_changes,
01222                                     pointerValue & return_val)
01223 {
01224   long int call_id;
01225 
01226   // -- Check for recursion (again). Note, we must do this before we call
01227   // procedureDB::call_to, otherwise everything will seem recursive!
01228  
01229   int num_instances = 0;
01230   bool recursive_call = Procedures.is_recursive_call(info, num_instances);
01231 
01232   // -- Push this call on the call stack
01233       
01234   Procedures.call_to(callsite, info);
01235 
01236   // -- Get the callee path
01237 
01238   procLocation * callee_path = info->procedure_location(callsite);
01239 
01240   // -- Print some context info
01241 
01242   if (pointerOptions::Verbose || pointerOptions::Show_stack) {
01243 
01244     call_id = call_counter;
01245     call_counter++;
01246 
01247     cout << "------------------------------------------------------------" << endl;
01248 
01249     if (info->is_context_insensitive())
01250       cout << "    CI Call ";
01251     else
01252       cout << "    CS Call ";
01253 
01254     cout << info->name() << " (id=" << call_id << ")";
01255 
01256     if (callsite) {
01257       /* TB: callnode() removed, replace code with callsite's coord.
01258       callNode * call = callsite->callnode();
01259       if (call)
01260         cout << " (" << call->coord() << ")";
01261       else
01262         cout << " (unknown source)";
01263       */
01264       cout << *callsite;
01265     }
01266 
01267     cout << endl;
01268     
01269     cout << "    Call-Path: ";
01270     Procedures.print_call_stack(cout);
01271     cout << endl;
01272     cout << "------------------------------------------------------------" << endl;
01273     cout << endl;
01274   }
01275 
01276   // -- Find out if reanalysis of this procedure is mandated
01277 
01278   bool reanalysis_required = Procedures.is_reanalysis_required(info);
01279 
01280   // -- Collect uses, defs, changes, etc.
01281 
01282   memoryblock_set defs;
01283   memoryuse_set uses;
01284   memoryblock_set changes;
01285   memoryblock_set changed_inputs;
01286   memoryblock_set parameters;
01287 
01288   // -- Forward or backward....
01289 
01290   if (_direction == Forward) {
01291 
01292     // -- Forward analysis ------------------------------
01293 
01294     // -- Pass in the parameters
01295     
01296     pass_parameters(info, callsite, arguments, parameters, changed_inputs);
01297 
01298     // -- Pass in any external, implied parameters (for context insensitivity)
01299 
01300     pass_external_inputs(info, callsite, external_uses, changed_inputs);
01301 
01302     // -- Short circuit: if the procedure is context insensitive, and both
01303     // the arguments and the external inputs are the same, then there is no
01304     // need to reanalyze it.
01305 
01306     bool skip_analysis = false;
01307 
01308     if ((num_instances >= 1) || (info->is_context_insensitive() &&
01309                                  (! reanalysis_required) &&
01310                                  (changed_inputs.empty())))
01311       {
01312         skip_analysis = true;
01313 
01314         if (pointerOptions::Verbose) {
01315           cout << "SKIP " << info->name() << " at ";
01316           Procedures.print_call_stack(cout);
01317           cout << endl;
01318         }
01319       }
01320 
01321     // -- Analyze the body of the procedure
01322 
01323     int start_progress = _procedureCount;
01324     int start_def_count = memoryAccess::def_count;
01325 
01326     progress_meter(info, skip_analysis);
01327 
01328     if ( ! skip_analysis) {
01329 
01330       if (Problem)
01331         Problem->at_procedure_entry(callee_path, info, return_val);
01332 
01333       // -- Analyze the body of the procedure, collecting the uses, defs,
01334       // and changes.
01335 
01336       analyze_procedure(callee_path, defs, uses, changes);
01337 
01338       // -- Determine external inputs and outputs (including any changes
01339       // visible to the caller).
01340 
01341       record_external_inputs_and_outputs(info, callee_path, arguments,
01342                                          parameters, defs, external_defs,
01343                                          uses, external_uses,
01344                                          changes, external_changes);
01345 
01346       if (Problem)
01347         Problem->at_procedure_exit(callee_path, info, return_val);
01348     }
01349 
01350     // -- Set tree numbering minimum (do this *after* processing the
01351     // procedure).
01352     
01353     callsite->visit();
01354 
01355     int end_progress = _procedureCount;
01356     int end_def_count = memoryAccess::def_count;
01357 
01358     // -- Pass the return value
01359 
01360     pass_return_value(info, callsite, return_val, external_changes);
01361 
01362     // -- Pass out the external, implied outputs. We should only need to do
01363     // this if the procedure was actually analyzed, which might cause the
01364     // external outputs to change. We need to be very careful though: when
01365     // we pickup pending changes, we need to set the current_def (see
01366     // procedureInfo::get_pending_changes).
01367 
01368     // TB: add 2nd clause below
01369     if ( ! skip_analysis && ! info->never_returns()) {
01370       pass_external_outputs(info, callsite);
01371 }
01372   }
01373   else {
01374 
01375     // -- Backward analysis ------------------------------
01376     // (Do the same thing in reverse)
01377 
01378     // -- External changes and the return value are now the changed inputs
01379 
01380     if (! info->never_returns()) // TB: add condition
01381       pass_external_outputs(info, callsite);
01382 
01383     pass_return_value(info, callsite, return_val, changed_inputs);
01384 
01385     // TBD: We need to pass in the return value here and check if it changed
01386 
01387     // -- Short circuit: if the procedure is context insensitive, and both
01388     // the arguments and the external inputs are the same, then there is no
01389     // need to reanalyze it.
01390 
01391     bool skip_analysis = false;
01392 
01393     if (info->is_context_insensitive() &&
01394         ( ! reanalysis_required) &&
01395         (changed_inputs.empty()))
01396       {
01397         skip_analysis = true;
01398 
01399         if (pointerOptions::Verbose) {
01400           cout << "SKIP " << info->name() << " at ";
01401           Procedures.print_call_stack(cout);
01402           cout << endl;
01403         }
01404       }
01405 
01406     if ( ! skip_analysis) {
01407 
01408       if (Problem)
01409         Problem->at_procedure_exit(callee_path, info, return_val);
01410       
01411       // -- Analyze the body of the procedure, collecting the uses, defs,
01412       // and changes.
01413       
01414       analyze_procedure(callee_path, defs, uses, changes);
01415 
01416       // -- Determine external inputs and outputs (including any changes
01417       // visible to the caller).
01418 
01419       record_external_inputs_and_outputs(info,  callee_path, arguments,
01420                                          parameters, defs, external_defs,
01421                                          uses, external_uses,
01422                                          changes, external_changes);
01423 
01424       if (Problem)
01425         Problem->at_procedure_entry(callee_path, info, return_val);
01426     }
01427 
01428     progress_meter(info, skip_analysis);
01429 
01430     // -- Pass back the inputs.
01431 
01432     pass_external_inputs(info, callsite, external_uses, external_changes);
01433     
01434     pass_parameters(info, callsite, arguments, parameters, external_changes);
01435   }
01436 
01437   // -- Indicate that we're returning.
01438 
01439   Procedures.return_from();
01440 
01441   // -- Debug info
01442 
01443   if (pointerOptions::Verbose || pointerOptions::Show_stack) {
01444     cout << "------------------------------------------------------------" << endl;
01445     cout << "    Return from " << info->name() << " (id=" << call_id << ")" << endl;
01446     cout << "    Return-Path: ";
01447     Procedures.print_call_stack(cout);
01448     cout << endl;
01449 
01450     print_memoryblock_set("    Returning: ", return_val.blocks, cout);
01451 
01452     cout << "------------------------------------------------------------" << endl;
01453     cout << endl;
01454   }
01455 }
01456 
01457 void Pointers::pass_parameters(procedureInfo * info,
01458                                stmtLocation * callsite,
01459                                pointervalue_list & arguments,
01460                                memoryblock_set & parameters,
01461                                memoryblock_set & changed_inputs)
01462 {
01463   procNode * callee = info->proc();
01464   procLocation * callee_path = info->procedure_location(callsite);
01465   procedureInfo * caller = Procedures.current_caller();
01466 
01467   // -- Perform the parameter passing
01468 
01469   funcNode * f = (funcNode *) callee->decl()->no_tdef_type();
01470   if (f->typ() != Func) {
01471     if (pointerOptions::Verbose)
01472       cout << "INTERNAL ERROR: Attempting to call a non-procedure." << endl;
01473     return;
01474   }
01475 
01476   if ( ! f->is_void_args()) {
01477 
01478     decl_list & params = f->args();
01479 
01480     // -- Treat each passed parameter as an assignment from the actual
01481     // parameter to the formal parameter. We don't care about defs or uses,
01482     // but we will record if any of the inputs are different.
01483 
01484     memoryblock_set defs;
01485     memoryuse_set uses;
01486     memoryblock_set changes;
01487 
01488     pointervalue_list_p args_p = arguments.begin();
01489 
01490     for (decl_list_p params_p = params.begin();
01491          params_p != params.end();
01492          ++params_p)
01493       {
01494         declNode * formal = * params_p;
01495         typeNode * formal_type = formal->no_tdef_type();
01496 
01497         // -- Test for varargs...
01498 
01499         if (formal_type->is_ellipsis() ||
01500             is_va_list(formal)) {
01501 
01502           // -- Here's how we'll handle varargs: we will use the "..."
01503           // declaration as a special object to collect the rest of the
01504           // arguments. We'll use the additive assignment so that the
01505           // values are accumulated. Then, any variables declared with type
01506           // "va_list" are pointers to that thing. Then let the rest of the
01507           // system handle itself.
01508 
01509           // -- Create the ellipsis object
01510 
01511           memoryBlock * ellipsis = Memory.lookup_variable(callee_path, formal, callee);
01512 
01513           parameters.insert(ellipsis);
01514 
01515           pointerValue lhs(ellipsis);
01516 
01517           if (pointerOptions::Verbose)
01518             cout << "Pass varargs object: " << ellipsis->name() << endl;
01519 
01520           // -- Assign each remaining argument to it
01521           
01522           while (args_p != arguments.end()) {
01523             pointerValue & actual = * args_p;
01524 
01525             // -- Additive assignment...
01526 
01527             assignment_operator(info, callee_path, callsite, lhs, actual,
01528                                 defs, uses, changed_inputs);
01529 
01530             // -- Constant propagation
01531 
01532             _constants.at_parameter_pass(callee_path, lhs, actual, changed_inputs);
01533 
01534             // -- User-defined analysis
01535             
01536             if (Problem)
01537               Problem->at_parameter_pass(callee_path, callsite, lhs, actual, changed_inputs);
01538 
01539             args_p++;
01540           }
01541 
01542           // -- Make the va_list variables point to the ellipsis object
01543 
01544           setup_va_list_variables(info, callee_path, callsite, callee, ellipsis);
01545 
01546           // -- Get out of the loop...
01547 
01548           break;
01549         }
01550         else {
01551 
01552           // -- Pass a regular parameter
01553 
01554           // -- Get the actual parameter (and value)
01555 
01556           if (args_p == arguments.end()) {
01557             if (pointerOptions::Verbose)
01558               cout << "ERROR: Too few arguments to " << callee->decl()->name() << 
01559                 " at " << callee->coord() << endl;
01560             break;
01561           }
01562 
01563           pointerValue & actual = * args_p;
01564 
01565           // -- Look up the formal parameter.
01566 
01567           memoryBlock * left = Memory.lookup_variable(callee_path, formal, callee);
01568           parameters.insert(left);
01569           pointerValue lhs(left);
01570 
01571           if (pointerOptions::Verbose)
01572             cout << endl << "Pass parameter: " << left->name() << endl;
01573 
01574           // -- Perform the assignment. THIS IS CRITICAL: the current path
01575           // must be in the context of the procedure being called (the
01576           // callee path) ALSO NOTE: We assume that no argument to
01577           // function is an address-of operator.
01578 
01579           assignment_operator(info, callee_path, callsite, lhs, actual,
01580                               defs, uses, changed_inputs);
01581 
01582           // -- If the direction is backward, make sure we have the uses
01583 
01584           if (_direction == Backward)
01585             generate_uses(info, callsite, uses, actual);
01586 
01587           // -- Constant propagation
01588 
01589           _constants.at_parameter_pass(callee_path, lhs, actual, changed_inputs);
01590 
01591           // -- User-defined analysis
01592           
01593           if (Problem)
01594             Problem->at_parameter_pass(callee_path, callsite, lhs, actual, changed_inputs);
01595 
01596           // -- Check
01597 
01598           if ((formal_type->typ() == Struct) ||
01599               (formal_type->typ() == Union))
01600             {
01601               /* This happens a lot in bind
01602               cout << "WARNING at " << * callee_path << "struct/union parameter:" << endl;
01603               output_context oc(cout);
01604               formal->output(oc,0);
01605               cout << endl;
01606               */
01607             }
01608         }
01609 
01610         ++args_p;
01611       }
01612   }
01613 }
01614 
01615 void Pointers::pass_return_value(procedureInfo * info,
01616                                  stmtLocation * current_callsite,
01617                                  pointerValue & return_val,
01618                                  memoryblock_set & changes)
01619 {
01620   procLocation * callee_path = info->procedure_location(current_callsite);
01621 
01622   // -- Get the return value variable, if there is one.
01623 
01624   declNode * return_var = info->return_variable();
01625   returnNode * return_stmt = info->return_stmt();
01626 
01627   if (return_stmt &&
01628       return_stmt->expr()) {
01629 
01630     // -- Get the return statement: it *must* be the last statement in the
01631     // procedure.
01632 
01633     stmtLocation * last = callee_path->last();
01634 
01635     if (last->stmt() != return_stmt) {
01636       cout << "FATAL ERROR returning from " << info->name() 
01637            << " at " << * current_callsite << ":" << endl;
01638       cout << "  Last statement of the procedure is not the return statement." << endl;
01639       abort();
01640     }
01641 
01642     memoryblock_set ignore_defs;
01643     memoryuse_set   ignore_uses;
01644     memoryblock_set ignore_changes;
01645     bool ignore_never_returns;
01646 
01647     return_val.is_a_use = true;
01648 
01649     eval(info, last, return_stmt->expr(), NULL,
01650          ignore_defs, ignore_uses, ignore_changes,
01651          return_val, ignore_never_returns);
01652 
01653     // -- Look up the return variable.
01654     /*
01655     memoryBlock * return_block = Memory.lookup_variable(callee_path, return_var, info->proc());
01656 
01657     if (pointerOptions::Verbose)
01658       cout << endl << "Pass return value " << return_block->name() << endl;
01659 
01660     // -- Pass this variable back as the return value
01661 
01662     return_val.blocks.insert(return_block);
01663 
01664     // -- Is this procedure context sensitive?
01665 
01666     if (info->is_context_insensitive()) {
01667 
01668       // -- Context insensitive: pass the return value back to all the call
01669       // sites.
01670 
01671       bool is_return_value = true;
01672 
01673       pass_one_external_output(info, current_callsite,
01674                                return_block, is_return_value);
01675     }
01676     else {
01677 
01678       // -- Context sensitive: there is nothing to do here because the
01679       // assignment to the return variable at the end of a
01680       // context-sensitive call will dominate the call site.
01681 
01682       memoryuse_set ignore_uses;
01683       generate_uses(info, current_callsite, ignore_uses, return_val);
01684 
01685       // pass_one_external_output(info, current_callsite,
01686       //                       return_block, def,
01687       //                       changes);
01688     }
01689     */
01690   }
01691 }
01692 
01693 
01694 void Pointers::process_merge_point(procedureInfo * info,
01695                                    basicblockLocation * current_block,
01696                                    pointerValue & result,
01697                                    memoryblock_set & defs,
01698                                    memoryuse_set & uses,
01699                                    memoryblock_set & changes)
01700 {
01701   // -- Find all the objects to be merge at this point, if any
01702 
01703   const memoryblock_set * to_be_merged = info->lookup_merge_point(current_block);
01704   if (to_be_merged) {
01705 
01706     // -- For each one, merge the incoming uses and create the
01707     // corresponding def.
01708 
01709     for (memoryblock_set_cp p = to_be_merged->begin();
01710          p != to_be_merged->end();
01711          ++p)
01712       {
01713         memoryuse_list phi_uses;
01714         memoryBlock * block_to_merge = *p;
01715 
01716         // -- Only merge flow-sensitive blocks
01717 
01718         if (block_to_merge->is_flow_sensitive()) {
01719 
01720           // -- When computing pointers, find the def that dominates the
01721           // merge point
01722 
01723           memoryDef * dominating_def = 0;
01724           if (computePointers)
01725             dominating_def = nearest_def_at(info, block_to_merge, current_block);
01726 
01727           // -- First find the corresponding uses, one for each control-flow
01728           // predecessor.
01729 
01730           block_to_merge->merge_uses_at(current_block, phi_uses, info->active_edges(),
01731                                         dominating_def, computePointers);
01732           // -- Merge the values together
01733 
01734           merge_operator(info, current_block, block_to_merge, phi_uses, defs, uses, changes);
01735 
01736           // -- Constant propagation
01737 
01738           _constants.at_merge(current_block, block_to_merge, phi_uses, result, changes);
01739 
01740           // -- IP Analyzer: merge the incoming flow values
01741 
01742           if (Problem)
01743             Problem->at_merge(current_block, block_to_merge, phi_uses, result, changes);
01744         }
01745       }
01746   }
01747 }
01748 
01754 void Pointers::process_local_changes(procedureInfo * info,
01755                                      basicblockLocation * current_block,
01756                                      memoryblock_set & local_changes,
01757                                      memoryblock_set & changes)
01758 {
01759   if (pointerOptions::Verbose)
01760     cout << " Process local changes at " << * current_block << endl;
01761 
01762 
01763   // -- For each changed block...
01764 
01765   for (memoryblock_set_p q = local_changes.begin();
01766        q != local_changes.end();
01767        ++q)
01768     {
01769       memoryBlock * block = (*q);
01770 
01771       if (pointerOptions::Verbose)
01772         cout << "    Change: " << block->name();
01773 
01774       // -- Add the changed block to the global changes
01775 
01776       changes.insert(block);
01777 
01778       if (pointerOptions::Verbose) {
01779         memoryDef * cur_def = block->current_def();
01780         memoryDef * def;
01781 
01782         if ( cur_def )
01783           def = cur_def;
01784         else
01785           def = block->last_def_at(current_block);
01786 
01787         if (def)
01788           cout << " -- def at " << * (def->where()) << endl;
01789         else
01790           cout << " -- (non-local def)" << endl;
01791       }
01792 
01793       // -- For flow insensitive objects, make sure all the procedures
01794       // that use this object are reanalyzed.
01795 
01796       if ( ! block->is_flow_sensitive()) {
01797         procedureinfo_set input_to = block->input_to();
01798 
01799         for (procedureinfo_set_p w = input_to.begin(); w != input_to.end();
01800              ++w) {
01801           procedureInfo * info_needs_input = *w;
01802 
01803           bool mark = true; // TB_unify
01804           if(block->property && Problem) {
01805             memoryDef *def = block->current_def() ?
01806                                def = block->current_def() :
01807                                block->last_def_at(current_block);
01808             memoryblock_set ext_inputs = info_needs_input->external_inputs();
01809             // if block is not in ext_inputs, we have never called
01810             // record_input_to_value(block), but since now callee is in
01811             // block->input_to(), need to reanalyze callee.
01812             if(def && ext_inputs.find(block) != ext_inputs.end() &&
01813                Problem->compare_property_value(def->where(), block,
01814                                                info_needs_input))
01815               mark = false;
01816           }
01817 
01818           if(mark) // TB_unify
01819             Procedures.mark_for_reanalysis(info_needs_input, (stmtLocation *)0, true);
01820           // Procedures.mark_one_for_reanalysis(info_needs_input);
01821         }
01822       }
01823 
01824       // -- If we're computing pointers, then set up a merge point. In
01825       // flow-insensitive mode, there are no merge points.
01826 
01827       if (computePointers)
01828         info->setup_merge_point(block, current_block);
01829 
01830       /*** I don't like sanity...
01831 
01832       // -- Sanity check
01833 
01834       if (!computePointers)
01835         info->check_merge_point(block, current_block);
01836       */
01837     }
01838 
01839   if (pointerOptions::Verbose && ( ! local_changes.empty()))
01840     cout << endl;
01841 }
01842 
01854 void Pointers::pass_external_inputs(procedureInfo * info,
01855                                     stmtLocation * current_callsite,
01856                                     memoryuse_set & external_uses,
01857                                     memoryblock_set & changed_inputs)
01858 {
01859   // -- Just to make sure...
01860 
01861   if ( ! info->is_context_insensitive())
01862     return;
01863 
01864   pointerValue result;
01865 
01866   // -- Get the current caller
01867 
01868   procedureInfo * caller = Procedures.current_caller();
01869 
01870   // -- Get the external inputs
01871 
01872   const memoryblock_set & external_inputs = info->external_inputs();
01873 
01874   // -- For each external input
01875 
01876   for (memoryblock_set_cp p = external_inputs.begin();
01877        p != external_inputs.end();
01878        ++p)
01879     {
01880       memoryBlock * block_to_pass = *p;
01881 
01882       pass_one_external_input(info, caller, current_callsite, block_to_pass, changed_inputs);
01883     }
01884 }
01885 
01893 void Pointers::pass_one_external_input(procedureInfo * callee,
01894                                        procedureInfo * caller,
01895                                        stmtLocation * current_callsite,
01896                                        memoryBlock * block_to_pass,
01897                                        memoryblock_set & changed_inputs)
01898 {
01899   // -- Attach the merge to basic block zero.
01900 
01901   Location * input_location = callee->procedure_location(current_callsite);
01902 
01903   // -- Skip write-protected objects
01904 
01905   if (block_to_pass->write_protected()) {
01906 
01907     // -- Write protected inputs: nothing to do because they always
01908     // return the only definition.
01909 
01910     if (pointerOptions::Verbose)
01911       cout << endl << "Pass write-protected input " << block_to_pass->name() << endl;
01912   }
01913   else
01914     if ( ! block_to_pass->is_flow_sensitive()) {
01915 
01916       // -- No need to pass flow-insensitive objects
01917 
01918       if (pointerOptions::Verbose)
01919         cout << endl << "Skip flow-insensitive input " << block_to_pass->name() << endl;
01920     }
01921     else {
01922 
01923       // -- Only pass inputs that could be visible in the caller
01924 
01925       if (Procedures.is_visible_to_caller(callee, block_to_pass)) {
01926 
01927             /*
01928             caller &&
01929               Procedures.is_visible_to(caller, block_to_pass)) {}
01930             */
01931             // Procedures.is_visible_to_caller(callee, block_to_pass)) {}
01932 
01933         // -- Regular inputs: use additive assignment to meet together
01934         // the reaching defs in the different contexts.
01935 
01936         if (pointerOptions::Verbose)
01937           cout << endl << "Pass external input " << block_to_pass->name() << endl;
01938 
01939         // -- Set up the use in the calling context, and set it's
01940         // reaching def properly. Attach the use to the procLocation
01941         // that represents the callsite
01942 
01943         // procLocation * attach_to = current_callsite->calls();
01944         Location * attach_to = current_callsite;
01945 
01946         // -- Look up the use. By calling use_at() here, we set the
01947         // current_use so that the assignment operator will find it.
01948 
01949         memoryUse * use = block_to_pass->use_at(attach_to);
01950 
01951         // -- When computing pointers, actually find the reaching def
01952 
01953         memoryDef * def = 0;
01954 
01955         if (computePointers) {
01956           def = nearest_def_at(caller, block_to_pass, current_callsite);
01957           use->reaching_def(def);
01958         }
01959 
01960         if (pointerOptions::Verbose) {
01961           def = use->reaching_def();
01962           cout << "  At callsite " << * current_callsite
01963                << " use at " << * attach_to << " reaching def is ";
01964           if (def)
01965             cout << * (def->where()) << endl;
01966           else
01967             cout << "(no reaching def)" << endl;
01968         }
01969 
01970         // if (use->reaching_def()) {}
01971 
01972         // -- Use the assignment operator with the additive flag to merge
01973         // this actual into the formal.
01974         
01975         self_assignment(attach_to, input_location, block_to_pass, changed_inputs);
01976 
01977         // -- Constant propagation
01978 
01979         _constants.at_self_assignment(attach_to, input_location, block_to_pass, changed_inputs);
01980 
01981         // -- User-defined analysis
01982               
01983         if (Problem)
01984           Problem->at_self_assignment(attach_to, input_location, block_to_pass, changed_inputs, true);
01985       }
01986     }
01987 
01988   // TB_unify
01989   if(Problem && block_to_pass->property)
01990     Problem->record_input_to_value(callee, block_to_pass, current_callsite);
01991 }
01992 
02002 void Pointers::pass_external_outputs(procedureInfo * callee,
02003                                      stmtLocation * current_callsite)
02004 {
02005   // -- Just to make sure...
02006 
02007   if ( ! callee->is_context_insensitive())
02008     return;
02009 
02010   // -- Don't pass back values when the procedure never returns
02011 
02012   if (callee->never_returns())
02013     return;
02014 
02015   // -- Get the external outputs
02016 
02017   const memoryblock_set & external_outputs = callee->external_outputs();
02018 
02019   /*************************************************************
02020    *
02021    *  This doesn't work, here's why: when we discover a new callsite, we
02022    *  need to propagate all of the external outputs to that callsite,
02023    *  regardless of whether or not they have changed.
02024    ************************************************************ */
02025   /*
02026   // -- Compute the set of external outputs that has actually changed
02027 
02028   memoryblock_list changed_outputs;
02029 
02030   set_intersection(external_outputs.begin(), external_outputs.end(),
02031                    all_nonlocal_changes.begin(), all_nonlocal_changes.end(),
02032                    back_inserter(changed_outputs));
02033 
02034   memoryblock_list diffs;
02035 
02036   set_difference(external_outputs.begin(), external_outputs.end(),
02037                  all_nonlocal_changes.begin(), all_nonlocal_changes.end(),
02038                  back_inserter(diffs));
02039 
02040   for (memoryblock_list_p p = diffs.begin();
02041        p != diffs.end();
02042        ++p)
02043     {
02044       memoryBlock * cur = (*p);
02045       if (cur->is_flow_sensitive()) {
02046         cout << "At " << callee->qualified_name() << " nochange-skip " << cur->name() << endl;
02047       }
02048     }
02049 
02050   copy(external_outputs.begin(), external_outputs.end(),
02051        back_inserter(changed_outputs));
02052   */
02053 
02054   // -- For each external output
02055 
02056   for (memoryblock_set_cp p = external_outputs.begin();
02057        p != external_outputs.end();
02058        ++p)
02059     {
02060       memoryBlock * block_to_pass = *p;
02061 
02062       if (pointerOptions::Verbose)
02063         cout << endl << "Pass external output " << block_to_pass->name() << endl;
02064 
02065       bool is_return_value = false;
02066 
02067       pass_one_external_output(callee, current_callsite,
02068                                block_to_pass, is_return_value);
02069     }
02070 }
02071 
02072 void Pointers::pass_one_external_output(procedureInfo * callee,
02073                                         stmtLocation * current_callsite,
02074                                         memoryBlock * block_to_pass,
02075                                         bool is_return_value)
02076 {
02077   // -- Generate a special use inside the procedure (actually at the last
02078   // statement of the exit block).
02079 
02080   stmtLocation * last_stmt_of_proc = callee->get_context()->last();
02081 
02082   memoryUse * use = block_to_pass->use_at(last_stmt_of_proc);
02083 
02084   // -- When computing pointers, we also search for the def that reaches
02085   // the exit of the procedure
02086 
02087   memoryDef * internal_reaching_def = 0;
02088 
02089   if (computePointers) {
02090     internal_reaching_def = block_to_pass->nearest_def_at(last_stmt_of_proc);
02091     use->reaching_def(internal_reaching_def);
02092   }
02093 
02094   internal_reaching_def = use->reaching_def();
02095 
02096   if (pointerOptions::Verbose) {
02097 
02098     cout << "  Interal use at " << * (use->where())
02099          << " with reaching def at ";
02100 
02101     memoryDef * def = use->reaching_def();
02102     if (def)
02103       cout << * (def->where()) << endl;
02104     else
02105       cout << "(no reaching def)" << endl;
02106   }
02107 
02108   // -- Skip flow insensitive objects
02109 
02110   if (! block_to_pass->is_flow_sensitive()) {
02111     if (pointerOptions::Verbose)
02112       cout << endl << "  Skip flow-insensitive external output " << block_to_pass->name() << endl;
02113     return;
02114   }
02115 
02116   // -- Get the list of callsites
02117 
02118   const procedureInfo::callsite_map & callsites = callee->callsites();
02119 
02120   // -- For each call site...
02121 
02122   for (procedureInfo::callsite_map_cp csp = callsites.begin();
02123        csp != callsites.end();
02124        ++csp)
02125     {
02126       // -- At each target call site
02127 
02128       stmtLocation * target_callsite = (*csp).first;
02129       procedureInfo * caller  = (*csp).second;
02130 
02131       // -- Test to see if the given memoryBlock is actually visible in the
02132       // caller's scope. The exception is the return value variable, which
02133       // must be passed back.
02134 
02135       if (is_return_value ||
02136           Procedures.is_visible_to(caller, block_to_pass)) {
02137 
02138         if (pointerOptions::Verbose)
02139           cout << "+ Back to callsite " << * target_callsite << endl;
02140 
02141         // -- Use the assignment operator to pass the value back.
02142 
02143         memoryblock_set pending_changes;
02144 
02145         self_assignment(last_stmt_of_proc, target_callsite,
02146                         block_to_pass, pending_changes);
02147 
02148         // -- Constant propagation
02149         
02150         _constants.at_self_assignment(last_stmt_of_proc, target_callsite,
02151                                       block_to_pass, pending_changes);
02152         
02153         // -- User-defined analysis
02154         
02155         if (Problem)
02156           Problem->at_self_assignment(last_stmt_of_proc, target_callsite,
02157                                       block_to_pass, pending_changes, false);
02158         
02159         // -- If changes occured, force reanalysis of the callsite and
02160         // store the changes until we get there. Don't record changes to
02161         // the return value variable.
02162         
02163         if ( ! is_return_value && ! pending_changes.empty()) {
02164           
02165           // -- Save the pending changes for the caller to pick up
02166           
02167           caller->set_pending_changes(target_callsite, pending_changes);
02168           if (pointerOptions::Verbose)
02169             print_memoryblock_set("    => Pending changes: ", pending_changes, cout);
02170           
02171           // -- Force reanalysis of the caller, unless it is the
02172           // current caller.
02173           
02174           if (target_callsite != current_callsite) {
02175             Procedures.mark_for_reanalysis(caller, target_callsite, true);
02176           }
02177         }
02178       }
02179       else {
02180         
02181         // -- Variable not visible
02182         
02183         if (pointerOptions::Verbose)
02184           cout << "+ Not visible at callsite " << * target_callsite << endl;
02185       }
02186     }
02187 
02188   // -- Reset the current def/use information: THIS IS CRITICAL: don't
02189   // reset the current use and def for the return value, otherwise the
02190   // assignment won't be able to find the reaching definition.
02191 
02192   if ( ! is_return_value)
02193     block_to_pass->reset_current_def_use((Location *)0);
02194 }
02195 
02203 void Pointers::record_external_inputs_and_outputs(procedureInfo * callee,
02204                                                   procLocation * current,
02205                                                   pointervalue_list & arguments,
02206                                                   memoryblock_set & parameters,
02207                                                   memoryblock_set & defs,
02208                                                   memoryblock_set & external_defs,
02209                                                   memoryuse_set & uses,
02210                                                   memoryuse_set & external_uses,
02211                                                   memoryblock_set & changes,
02212                                                   memoryblock_set & external_changes)
02213 {
02214   // -- NOTE: we are not transfering *ANY* defs to the external defs. Oh well.
02215 
02216   // -- If the routine never returns, don't pass anything back to the caller.
02217 
02218   /* if (callee->never_returns())
02219     return; TB */
02220 
02221   // -- Get call information
02222 
02223   procNode * procedure = callee->proc();
02224   procedureInfo * caller = Procedures.current_caller();
02225   stmtLocation * current_callsite = Procedures.current_callsite();
02226   stmtLocation * last_stmt_of_proc = current->last();
02227 
02228   // -- Get existing external inputs
02229 
02230   const memoryblock_set & external_inputs = callee->external_inputs();
02231 
02232   // -- Record escape analysis "roots": initialize with formal parameters
02233 
02234   memoryblock_set roots(parameters);
02235 
02236   // -- Record proposed external changes
02237 
02238   memoryblock_set proposed_external_changes;
02239 
02240   // -- Proposed new external inputs
02241 
02242   memoryblock_set new_inputs;
02243 
02244   // -- Proposed new external outputs
02245 
02246   memoryblock_set new_outputs;
02247 
02248   // -- Visit all the uses and identify those whose reaching definitions
02249   // are outside the procedure.
02250 
02251   if (pointerOptions::Verbose) {
02252     cout << "Record external inputs to " << procedure->decl()->name() << " at ";
02253     Procedures.print_call_stack(cout);
02254     cout << endl;
02255   }
02256 
02257   // TB_unify
02258   memoryblock_set external_uses_blocks;
02259   bool gathered_external_uses_blocks = false;
02260       
02261   if ( ! uses.empty() )
02262     for (memoryuse_set_p p = uses.begin();
02263          p != uses.end();
02264          ++p)
02265       {
02266         memoryUse * use = *p;
02267         memoryBlock * block = use->owner();
02268         memoryDef * def = use->reaching_def();
02269 
02270         // -- All existing inputs are escape analysis roots
02271 
02272         if (external_inputs.find(block) != external_inputs.end())
02273           roots.insert(block);
02274         
02275         // -- The only variables we care about are those that are not local
02276         // to this procedure, and are modifiable.
02277 
02278         if ( ! block->write_protected() &&
02279              (block->local_to() != procedure)) {
02280 
02281           // -- For flow insensitive objects, just record that the object
02282           // is an input to this procedure
02283 
02284           if ( ! block->is_flow_sensitive())
02285             block->input_to().insert(callee);
02286 
02287           // -- Check for external input. There are two cases: (1) the
02288           // input has a reaching def outside the current procedure, (2)
02289           // the input has no reaching def, but it might later in the
02290           // analysis. NEW: just wait until that happens!
02291 
02292           bool is_external_input = false;
02293 
02294           if (def) {
02295 
02296             // memoryBlock * block = def->owner();
02297 
02298             // -- We're looking for reaching defs that are not inside this
02299             // procedure. If the current location is NOT a prefix location
02300             // of the reaching def, then this is a non-local use.
02301 
02302             if ( ! Location::is_prefix(current, def->where()))
02303               is_external_input = true;
02304           }
02305           else {
02306 
02307             // -- Why? BROKEN: New: if there is no reaching def, then it's not an input.
02308 
02309             if (block->is_heap_object())
02310               is_external_input = false; // true; // false; // true;
02311             else
02312               is_external_input = true;
02313           }
02314 
02315           if (is_external_input) {
02316 
02317             // -- If computing pointers, add the new input
02318 
02319             if (computePointers)
02320               new_inputs.insert(block);
02321 
02322               // if (callee->add_external_input(block))
02323               //    found_new_inputs = true;
02324 
02325             // -- Pass it up to the caller, if it's visible there
02326 
02327             if (caller &&
02328                 Procedures.is_visible_to(caller, block)) {
02329 
02330               external_uses.insert(use);
02331 
02332               if(_unification_based && gathered_external_uses_blocks) //TB_unify
02333                 external_uses_blocks.insert(use->owner());
02334 
02335               if(!(_unification_based && block->is_unify/*Type*/()))
02336                 roots.insert(block->top_most_container());
02337               else { // TB_unify
02338                 // insert into roots the block's top_most_container that occurs
02339                 // in caller context: it must be in external_uses, and is
02340                 // either a global or a argument to current call.
02341                 memoryblock_set tops = block->top_most_containers();
02342                 for(memoryblock_set_p t=tops.begin(); t!=tops.end(); t++) {
02343                   memoryBlock *one_top = *t;
02344                   if(roots.find(one_top) != roots.end()) continue;
02345                   if(one_top == block) { roots.insert(block); continue; }
02346                   bool is_global =
02347                     one_top->decl()->decl_location()==declNode::TOP ||
02348                     // check for global vars defined in annotation.
02349                     !one_top->decl()->type() && !one_top->local_to();
02350                   bool is_arg = false;
02351                   if(! is_global) // check if is an argument to call.
02352                     for(pointervalue_list_p a=arguments.begin();
02353                         a!=arguments.end(); a++)
02354                       if(a->blocks.find(one_top) != a->blocks.end())
02355                       { is_arg=true; break; }
02356 
02357                   if(is_global || is_arg) {
02358                     if(! gathered_external_uses_blocks) {
02359                       for(memoryuse_set_p u=external_uses.begin();
02360                           u!=external_uses.end(); u++)
02361                         external_uses_blocks.insert((*u)->owner());
02362                       gathered_external_uses_blocks = true;
02363                     }
02364                     if(external_uses_blocks.find(one_top) !=
02365                        external_uses_blocks.end()) {
02366                       roots.insert(one_top);
02367                     }
02368                   }
02369                 }
02370               }
02371             }
02372           }
02373         }
02374       }
02375 
02376   if (pointerOptions::Verbose)
02377     cout << endl;
02378 
02379   // -- Visit all the defs and identify those that are visible outside the
02380   // procedure. We reset their current_def and current_use to avoid
02381   // reaching definition errors.
02382 
02383   if (pointerOptions::Verbose) {
02384     cout << "Record external outputs to " << procedure->decl()->name() << " at ";
02385     Procedures.print_call_stack(cout);
02386     cout << endl;
02387   }
02388 
02389   // -- Get the location of the input merges
02390 
02391   Location * input_location = 0;
02392   if (current_callsite)
02393     input_location = callee->procedure_location(current_callsite);
02394 
02395   if ( ! changes.empty() ) {
02396     for (memoryblock_set_p p = changes.begin();
02397          p != changes.end();
02398          ++p)
02399       {
02400         memoryBlock * block = *p;
02401 
02402         // -- Outputs are non-local if they are accessible outside this
02403         // procedure. We'll test this in the following way: if the block is
02404         // not local to the current procedure, but is in scope above it,
02405         // then it's external.
02406 
02407         if ((block->local_to() != procedure)) {
02408           // && Procedures.is_visible_to_caller(callee, block)) {
02409 
02410           // -- Special case: check for a trivial def. If the only def of
02411           // this object is the merge of the external inputs, then we
02412           // won't really consider this to be a def.
02413 
02414           bool trivial_def = false;
02415 
02416           if (input_location &&
02417               block->current_def()) {
02418 
02419             if (block->current_def()->where() == input_location)
02420               trivial_def = true;
02421           }
02422 
02423           // -- Special case: don't pass out unallocated or deallocated
02424           // heap objects.
02425 
02426           bool not_allocated = false;
02427 
02428           
02429           if (block->is_heap_object()) {
02430 
02431             /* - - - - - - - - - -
02432 
02433             Multiplicity multiplicity = Unbounded;
02434 
02435             if (block->is_allocation_object()) {
02436 
02437               // -- Case 1: block is the special allocation object. Check
02438               // the multiplicity directly.
02439 
02440               if (block->is_flow_sensitive()) {
02441                 if (block->current_def())
02442                   multiplicity = block->current_def()->multiplicity();
02443                 else
02444                   multiplicity = Unallocated;
02445               }
02446               else
02447                 multiplicity = Unbounded;
02448             }
02449             else {
02450           
02451               // -- Case 2: regular block. Get the allocation block to
02452               // check multiplicity
02453   
02454               memoryuse_set ignore;  
02455               multiplicity = current_multiplicity(callee, last_stmt_of_proc, block, ignore);
02456 
02457               if (pointerOptions::Verbose) {
02458                 cout << "  Test escape: " << block->name() << " at " << * current << " multiplicity = ";
02459                 memoryBlock::print_multiplicity(multiplicity, cout);
02460                 cout << endl;
02461               }
02462             }
02463 
02464             if ((multiplicity == Deallocated) || (multiplicity == Unallocated)) {
02465               not_allocated = true;
02466 
02467               if (pointerOptions::Verbose) {
02468                 cout << "  NOT allocated: " << block->name() << " at " << * current << " multiplicity = ";
02469                 memoryBlock::print_multiplicity(multiplicity, cout);
02470                 cout << endl;
02471               }
02472             }
02473 
02474             - - - - - - - - - - - - - - */
02475           }
02476           else {
02477 
02478             // -- Record non-local non-heap objects (i.e., local variables
02479             // in the caller, or global variables)
02480 
02481             if(!(_unification_based && block->is_unify/*Type*/()))
02482               roots.insert(block->top_most_container());
02483             else { // TB_unify
02484               // insert into roots the block's top_most_container that occurs
02485               // in caller context: it must be in external_uses, and is
02486               // either a global or a argument to current call.
02487               memoryblock_set tops = block->top_most_containers();
02488               for(memoryblock_set_p t=tops.begin(); t!=tops.end(); t++) {
02489                 memoryBlock *one_top = *t;
02490                 if(roots.find(one_top) != roots.end()) continue;
02491                 if(one_top == block) { roots.insert(block); continue; }
02492                 bool is_global =
02493                   one_top->decl()->decl_location()==declNode::TOP ||
02494                   !one_top->decl()->type() && !one_top->local_to();
02495                 bool is_arg = false;
02496                 if(! is_global) // check if is an argument to call.
02497                   for(pointervalue_list_p a=arguments.begin();
02498                       a!=arguments.end(); a++)
02499                     if(a->blocks.find(one_top) != a->blocks.end())
02500                     { is_arg=true; break; }
02501 
02502                 if(is_global || is_arg) {
02503                   if(! gathered_external_uses_blocks) {
02504                     for(memoryuse_set_p u=external_uses.begin();
02505                         u!=external_uses.end(); u++)
02506                       external_uses_blocks.insert((*u)->owner());
02507                     gathered_external_uses_blocks = true;
02508                   }
02509                   if(external_uses_blocks.find(one_top) !=
02510                      external_uses_blocks.end())
02511                     roots.insert(one_top);
02512                 }
02513               }
02514             }
02515           }
02516 
02517           // -- If we are computing pointers, and this is a non-trivial
02518           // def, then add it to the external outputs list.
02519 
02520           if (computePointers) {
02521             if (! trivial_def && ! not_allocated) {
02522               new_outputs.insert(block);
02523 
02524               // if (callee->add_external_output(block))
02525               //   found_new_inputs = true;
02526             }
02527             else 
02528               if (pointerOptions::Verbose) {
02529                 if (trivial_def)
02530                   cout << "   Skip external output " << block->name() << " -- trivial def" << endl;
02531                 if (not_allocated)
02532                   cout << "   Skip external output " << block->name() << " -- no longer allocated" << endl;
02533               }
02534           }
02535 
02536           if (! trivial_def && ! not_allocated) {
02537 
02538             // -- Pass it up to the caller, if it's visible there
02539 
02540             if (caller &&
02541                 Procedures.is_visible_to(caller, block)) {
02542               // external_changes.insert(block);
02543 
02544               proposed_external_changes.insert(block);
02545             }
02546 
02547             // -- Record this as a non-local change. This helps
02548             // pass_external_outputs be more efficient.
02549 
02550             // all_nonlocal_changes.insert(block);
02551           }
02552 
02553           // -- Reset the current def and use
02554           
02555           block->reset_current_def_use((Location *)0);
02556         }
02557       }
02558   }
02559 
02560   if (pointerOptions::Verbose)
02561     cout << endl;
02562 
02563   // const memoryblock_set & external_outputs = callee->external_outputs();
02564 
02565   // -- If we found any new inputs, mark this procedure for reanalysis
02566 
02567   /*** We shouldn't need to do this
02568   if (found_new_inputs &&
02569       callee->is_context_insensitive())
02570     Procedures.mark_for_reanalysis(callee, current_callsite);
02571   */
02572 
02573   /*
02574   if (callee->name() == "log") {
02575     cout << callee->name();
02576     print_memoryblock_set(" external changes = ", external_changes, cout);
02577     cout << endl;
02578   }
02579   */
02580   /*
02581   if (external_changes.size() > 100) {
02582     cout << callee->name() << " has " << external_changes.size() << " external changes." << endl;
02583     print_memoryblock_set(" = ", external_changes, cout);
02584   }
02585 
02586   if (callee->external_outputs().size() > 100) {
02587     cout << callee->name() << " has " << callee->external_outputs().size() << " external outputs." << endl;
02588     print_memoryblock_set(" = ", callee->external_outputs(), cout);
02589   }
02590   */
02591 
02592   // -- Get the external inputs and outputs
02593 
02594   if (pointerOptions::Verbose) {
02595     cout << "Escape analysis at " << callee->name() << endl;
02596   }
02597 
02598   // -- Include the return value as a root
02599 
02600   declNode * return_var = callee->return_variable();
02601 
02602   if (return_var) {
02603 
02604     // -- Look up the return variable.
02605 
02606     memoryBlock * return_block = Memory.lookup_variable(current, return_var, callee->proc());
02607     roots.insert(return_block);
02608   }
02609 
02610   // -- Initialize the reachability worklist with the roots
02611 
02612   memoryblock_list worklist;
02613 
02614   for (memoryblock_set_p p = roots.begin();
02615        p != roots.end();
02616        ++p)
02617     {
02618       worklist.push_back(*p);
02619     }
02620 
02621   if (pointerOptions::Verbose) {
02622     print_memoryblock_set("  + Roots: ", roots, cout);
02623   }
02624 
02625   // -- Build a list of unreachable objects (or leave it empty if we're not
02626   // doing the escape analysis)
02627 
02628   memoryblock_set unreachable;
02629 
02630   // -- Escape analysis
02631 
02632   if (pointerOptions::Use_escape_analysis) {
02633 
02634     // -- Compute all the blocks reachable from the roots, including the
02635     // roots themselves.
02636 
02637     memoryblock_set reachable(roots);
02638     reachable_blocks(last_stmt_of_proc, worklist, reachable);
02639 
02640     if (pointerOptions::Verbose) {
02641       print_memoryblock_set("  + Reachable: ", reachable, cout);
02642     }
02643 
02644     // -- Produce a list of external changes that are not reachable. At the
02645     // same time, add reachable changes to the external changes list.
02646 
02647     // memoryblock_set valid;
02648 
02649     for (memoryblock_set_p p = proposed_external_changes.begin();
02650          p != proposed_external_changes.end();
02651          ++p)
02652       {
02653         memoryBlock * one_change = (*p);
02654 
02655         if(!(_unification_based && one_change->is_unify/*Type*/())) {
02656           memoryBlock * top_most = one_change->top_most_container();
02657           if (reachable.find(top_most) == reachable.end()) {
02658 
02659             // -- Record the unreachable blocks
02660 
02661             unreachable.insert(one_change);
02662           }
02663           else {
02664 
02665             // valid.insert(one_change);
02666 
02667             // -- Pass the reachable blocks back
02668 
02669             external_changes.insert(one_change);
02670           }
02671 
02672         } else { // TB_unify
02673           memoryblock_set tops = one_change->top_most_containers();
02674           bool reach = false;
02675           for(memoryblock_set_p t=tops.begin(); !reach && t!=tops.end(); t++)
02676             if(reachable.find(*t) != reachable.end()) reach = true;
02677           if(! reach)
02678             unreachable.insert(one_change);
02679           else
02680             external_changes.insert(one_change);
02681         }
02682       }
02683   }
02684   else {
02685 
02686     // -- No escape analysis: all changes are visible
02687 
02688     external_changes.insert(proposed_external_changes.begin(),
02689                             proposed_external_changes.end());
02690   }
02691 
02692   // -- Add reachable external inputs
02693 
02694   for (memoryblock_set_p p = new_inputs.begin();
02695        p != new_inputs.end();
02696        ++p)
02697     {
02698       memoryBlock * one_input = (*p);
02699 
02700       if (unreachable.find(one_input) == unreachable.end())
02701         callee->add_external_input(one_input);
02702     }
02703 
02704   // -- Add reachable external outputs
02705 
02706   for (memoryblock_set_p p = new_outputs.begin();
02707        p != new_outputs.end();
02708        ++p)
02709     {
02710       memoryBlock * one_output = (*p);
02711 
02712       if (unreachable.find(one_output) == unreachable.end())
02713         callee->add_external_output(one_output);
02714     }
02715 
02716 
02717   if (pointerOptions::Show_memory_leaks) {
02718 
02719     // -- Check for potential memory leak
02720 
02721     memoryblock_set leaks;
02722 
02723     for (memoryblock_set_p p = unreachable.begin();
02724          p != unreachable.end();
02725          ++p)
02726       {
02727         memoryBlock * one_unreachable = (*p);
02728 
02729         memoryuse_set ignore;
02730         Multiplicity multiplicity = current_multiplicity(callee, last_stmt_of_proc, one_unreachable, ignore);
02731 
02732         if (multiplicity == Single) {
02733           leaks.insert(one_unreachable->top_most_container());
02734         }
02735       }
02736     
02737     if (leaks.size() != 0) {
02738       cout << "WARNING: Potential memory leak at " << callee->name() << " (" << procedure->coord() << ")" << endl;
02739 
02740       for (memoryblock_set_p p = leaks.begin();
02741            p != leaks.end();
02742            ++p)
02743         {
02744           memoryBlock * one_leak = *p;
02745           stmtLocation * alloc_site = one_leak->allocation_site();
02746 
02747           if (alloc_site->stmt()->coord().is_unknown())
02748             alloc_site = alloc_site->block_location()->proc_location()->stmt_location();
02749 
02750           cout << "  + " << one_leak->name() << " allocated at " << alloc_site->stmt()->coord() << endl;
02751         }
02752     }
02753   }
02754 
02755 
02756   if (pointerOptions::Verbose) {
02757 
02758     if (unreachable.size() > 0) {
02759 
02760       cout << callee->name() << ": unreachable " 
02761            << unreachable.size() << "/" << proposed_external_changes.size() << endl;
02762 
02763       print_memoryblock_set("  Unreachable blocks: ", unreachable, cout);
02764       // print_memoryblock_set("  Reachable blocks: ", valid, cout);
02765 
02766     /*
02767         memoryuse_set ignore;  
02768         Multiplicity multiplicity = current_multiplicity(callee, last_stmt_of_proc, one_change, ignore);
02769         cout << "  - Unreachable: " << one_change->name() << " at " << *current << ", multiplicity = ";
02770         memoryBlock::print_multiplicity(multiplicity, cout);
02771         cout << endl;
02772 
02773     */
02774 
02775     }
02776   }
02777 }
02778 
02779 
02780 // ------------------------------------------------------------
02781 // eval : Pointer expression evaluator
02782 // ------------------------------------------------------------
02783 
02784 void Pointers::eval(procedureInfo * info,
02785                     stmtLocation * current,
02786                     exprNode * E,
02787                     stmtNode *cur_stmt,
02788                     memoryblock_set & defs,
02789                     memoryuse_set & uses,
02790                     memoryblock_set & changes,
02791                     pointerValue & result,
02792                     bool & never_returns)
02793 {
02794   switch (E->typ()) {
02795     
02796   case Id:
02797     {
02798       // === CASE 1: simple identifier
02799       // Look up the identifier in the memory model
02800 
02801       idNode * id = (idNode *) E;
02802       procLocation * procloc = Location::procedure(current);
02803       procNode * proc = procloc->proc();
02804       memoryBlock * mb = Memory.lookup_variable(procloc, id->decl(), proc);
02805       result.blocks.insert(mb);
02806 
02807       if (mb->decl() == info->return_variable())
02808         mb->set_return_value();
02809 
02810       // The name of a procedure is also a pointer to that procedure.
02811       // TB: with new dismantler, id may not have decl.
02812       // handle this by set result.is_address=true in determine_call_targets().
02813       typeNode * the_type = NULL;
02814       if(id->decl()) the_type = id->decl()->no_tdef_type();
02815       if (the_type && the_type->typ() == Func)
02816           result.is_address = true;
02817 
02818       // -- Generate uses if required
02819 
02820       if (result.is_a_use)
02821         generate_uses(info, current, uses, result);
02822 
02823       // -- Constant propagation
02824 
02825       _constants.at_id(current, id, result);
02826 
02827       // -- User-defined analysis
02828 
02829       if (Problem)
02830         Problem->at_id(current, id, result);
02831     }
02832     break;
02833 
02834   case Const:
02835     {
02836       // === CASE 11: Constants. Zero is interpreted as a null pointer
02837       // (which we implement as the addess of the null memoryBlock).
02838 
02839       constNode * con = (constNode *) E;
02840 
02841       /* -- NEW: only do this when zero is assigned to a pointer (see
02842                  assignment_operator()).
02843 
02844       if (con->value().is_zero()) {
02845         result.blocks.insert(Memory.null());
02846         result.is_address = true;
02847       } */
02848 
02849       // -- Handle string constants
02850 
02851       if (con->value().is_str()) {
02852         memoryBlock * mb = Memory.lookup_string_constant(con);
02853         result.blocks.insert(mb);
02854         result.is_address = true;
02855       }
02856 
02857       // -- Generate uses if required
02858 
02859       if (result.is_a_use)
02860         generate_uses(info, current, uses, result);
02861 
02862       // -- Constant propagation
02863 
02864       _constants.at_const(current, con, result);
02865 
02866       // -- User-defined analysis
02867 
02868       if (Problem)
02869         Problem->at_const(current, con, result);
02870     }
02871     break;
02872 
02873   case Operand:
02874     {
02875       operandNode * o = (operandNode *) E;
02876 
02877       // Evaluate the sub-expression. This operand subexpression is a
02878       // "use", unless the operator is just address-of
02879 
02880       bool o_is_lhs = (cur_stmt && cur_stmt->typ()==ThreeAddr &&
02881                        ((threeAddrNode*)cur_stmt)->lhs()==o);
02882       if(o_is_lhs)
02883         result.is_a_use = o->index() || !o->fields().empty() || o->star();
02884       else
02885         result.is_a_use = ! o->addr() || o->index() || !o->fields().empty() ||
02886                           o->star();
02887       eval(info, current, o->var(), cur_stmt,
02888            defs, uses, changes, result, never_returns);
02889 
02890       // special case: o->var() is a Func.
02891       if(o->var()->typ() == Id &&
02892          ((idNode*)o->var())->decl()->no_tdef_type()->typ() == Func) {
02893         assert(result.is_address); // set in case Id.
02894         // want to reset if there is cast to non func-ptr.
02895         assert(! o->star() && o->fields().empty() && !o->index());
02896         if (o->cast() &&
02897             (!o->cast()->follow_tdefs()->type() ||
02898              o->cast()->follow_tdefs()->type()->typ() != Func))
02899           result.is_address = false;
02900       }
02901 
02902       // Apply the pointer-analysis transfer function
02903       // precedence: star, field, index, addr, cast
02904 
02905       if(o->star()) {
02906         // === CASE 3: Unary "*" : Apply the star operator
02907 
02908         pointerValue subexpr;
02909         subexpr.copy_pointers_from(result);
02910         result.initialize_pointers();
02911         if(o_is_lhs)
02912           result.is_a_use = !o->fields().empty() || o->index();
02913         star_operator(info, current, subexpr, defs, uses, changes, result);
02914         result.is_address = false;
02915 
02916         // -- Generate uses if required
02917 
02918         if (result.is_a_use)
02919           generate_uses(info, current, uses, result);
02920 
02921         // -- Constant propagation
02922 
02923         _constants.at_dereference(current, o, result);
02924 
02925         // -- User-defined analysis
02926 
02927         if (Problem)
02928           Problem->at_dereference(current, o, subexpr, result);
02929       }
02930 
02931       // fields.
02932       for(id_list_p f=o->fields().begin(); f!=o->fields().end(); f++) {
02933         pointerValue left;
02934         left.copy_pointers_from(result);
02935         result.initialize_pointers();
02936         if(o_is_lhs)
02937           result.is_a_use = (*f!=o->fields().back()) || o->index();
02938 
02939         declNode * field_decl = (*f)->decl();
02940 
02941         // Evaluate the struct part of the expression
02942 
02943         dot_operator(current, (*f)->name(), field_decl, left, uses, result);
02944 
02945         // -- Generate uses if required
02946 
02947         if (result.is_a_use)
02948           generate_uses(info, current, uses, result);
02949 
02950         // -- User-defined analysis
02951 
02952         if (Problem)
02953           Problem->at_field_access(current, o, left, result);
02954       }
02955       if (! o->fields().empty())
02956         // -- Constant propagation
02957         _constants.at_field_access(current, o, result);
02958 
02959       // index
02960       if(o->index()) {
02961         pointerValue left;
02962         left.copy_pointers_from(result);
02963         pointerValue right;
02964         result.initialize_pointers();
02965         if(o_is_lhs)
02966           result.is_a_use = false;
02967 
02968         // Evaluate the right-hand side
02969 
02970         right.is_a_use = true;
02971         
02972         eval(info, current, o->index(), cur_stmt,
02973              defs, uses, changes, right, never_returns);
02974 
02975         // -- Index behaves like "*"
02976 
02977         star_operator(info, current, left, defs, uses, changes, result);
02978 
02979         // -- Mark the elements as indexed objects
02980 
02981         mark_as_indexed(result.blocks);
02982 
02983         // -- Generate uses if required
02984 
02985         if (result.is_a_use)
02986           generate_uses(info, current, uses, result);
02987 
02988         // -- Constant propagation
02989 
02990         _constants.at_index(current, o, result);
02991 
02992         // -- User-defined analysis
02993           
02994         if (Problem)
02995           Problem->at_index(current, o, left, right, result);
02996       } // index
02997 
02998       // addr
02999       if(o->addr()) {
03000         // === CASE 2: Unary "&" : Indicate that the results are to
03001         // be used as addresses.
03002 
03003         pointerValue subexpr;
03004         subexpr.copy_pointers_from(result);
03005         result.is_address = true;
03006 
03007         // -- Constant propagation
03008 
03009         _constants.at_address(current, o, result);
03010 
03011         // -- User-defined analysis
03012 
03013         if (Problem)
03014           Problem->at_address(current, o, subexpr, result);
03015       }
03016 
03017 
03018       if(o->cast()) {
03019         // === CASE 10: casts are essentially no-ops; we evaluate the
03020         // subexpression into a temporary, then just copy them into the
03021         // result.
03022 
03023         // -- Constant propagation
03024 
03025         // -- User-defined analysis
03026         pointerValue operand;
03027         operand.copy_pointers_from(result);
03028         operand.constant_value = result.constant_value;
03029         _constants.at_cast(current, o, operand, result);
03030         if (Problem)
03031           Problem->at_cast(current, o, operand, result);
03032       }
03033     }
03034 
03035     break; // case Operand
03036 
03037   default:
03038     {
03039       // === CASE 12: All other node types
03040       assert(false);
03041     }
03042   }
03043 } // eval(exprNode*)
03044 
03045 
03046 void Pointers::eval(procedureInfo * info,
03047                     stmtLocation * current,
03048                     threeAddrNode *threeaddr,
03049                     memoryblock_set & defs,
03050                     memoryuse_set & uses,
03051                     memoryblock_set & changes,
03052                     pointerValue & result,
03053                     bool & never_returns)
03054 {
03055   operandNode *rhs1 = threeaddr->rhs1(),
03056               *rhs2 = threeaddr->rhs2(),
03057               *lhs = threeaddr->lhs();
03058   Operator *op = threeaddr->op();
03059 
03060   pointerValue rhs1_value, rhs2_value, rhs_value;
03061   bool is_call;
03062   pointerValue call_targets;
03063 
03064   if(rhs1) {
03065     if(op && op->id() == Operator::FUNC_CALL) {
03066       // === CASE 11: function call
03067       is_call = true;
03068       call_operator(info, current, rhs1, threeaddr->arg_list(), defs, uses,
03069                     changes, rhs1_value, call_targets, never_returns);
03070     } else {
03071       is_call = false;
03072       rhs1_value.is_a_use = true;
03073       eval(info, current, rhs1, threeaddr, defs, uses, changes, rhs1_value,
03074            never_returns);
03075     }
03076   }
03077 
03078   if(rhs2) {
03079     rhs2_value.is_a_use = true;
03080     eval(info, current, rhs2, threeaddr, defs, uses, changes, rhs2_value,
03081          never_returns);
03082   }
03083 
03084   if(threeaddr->sizeof_type() || op && op->id()== Operator::SIZEOF) {
03085     // === CASE 3.5: Size of works just like the general unary case,
03086     // but doesn't propagate any pointers.
03087 
03088     // -- Constant propagation
03089 
03090     _constants.at_sizeof(current, threeaddr, rhs1_value, rhs_value);
03091 
03092     // -- User-defined analysis
03093 
03094     if (Problem)
03095       Problem->at_sizeof(current, threeaddr, rhs1_value, rhs_value);
03096   }
03097 
03098   if(rhs1 && !rhs2) {
03099     rhs_value.copy_pointers_from(rhs1_value);
03100     rhs_value.constant_value = rhs1_value.constant_value;
03101 
03102     if(op && op->id() != Operator::FUNC_CALL) {
03103       // === CASE 4: Other unary operators have no affect on pointers.
03104 
03105       // -- Generate uses if required
03106 
03107       if (rhs_value.is_a_use)
03108         generate_uses(info, current, uses, rhs_value);
03109 
03110       // -- Constant propagation
03111 
03112       _constants.at_unary(current, threeaddr, rhs1_value, rhs_value);
03113 
03114       // -- User-defined analysis
03115 
03116       if (Problem)
03117         Problem->at_unary(current, threeaddr, rhs1_value, rhs_value);
03118     }
03119   }
03120 
03121   if(rhs1 && rhs2) {
03122     // === CASE 9: All binary operators other than assignment. If they involve
03123     // pointers and they are appropriate operators, then just pass
03124     // the pointers through.
03125 
03126     assert(op);
03127     if ((op->id() == '+') || (op->id() == '-')) {
03128 
03129       // -- See if the left points to anything
03130 
03131       pointerValue left_after_star;
03132       star_operator(info, current, rhs1_value, defs, uses, changes,
03133                     left_after_star);
03134 
03135       // -- See if the right points to anything
03136 
03137       pointerValue right_after_star;
03138       star_operator(info, current, rhs2_value, defs, uses, changes,
03139                     right_after_star);
03140 
03141       // -- Combine the results: if either the left or right have
03142       // pointers, then assume pointer arithmetic. However, if
03143       // BOTH have pointers, then assume we are computing an
03144       // offset.
03145 
03146       bool pointers_on_left  = (! left_after_star.blocks.empty());
03147       bool pointers_on_right = (! right_after_star.blocks.empty());
03148 
03149       if (pointers_on_left &&
03150           pointers_on_right)
03151         {
03152           // -- Here's the special case: don't return any pointers
03153         }
03154       else
03155         {
03156           rhs_value.add_blocks_from(rhs1_value);
03157           rhs_value.add_blocks_from(rhs2_value);
03158         }
03159 
03160       if (pointerOptions::Verbose &&
03161           (! rhs_value.blocks.empty())) {
03162         print_memoryblock_set("binaryOp: combination is: ", rhs_value.blocks, cout);
03163         print_memoryblock_set("   Left after star: ", left_after_star.blocks, cout);
03164         print_memoryblock_set("   Right after star: ", right_after_star.blocks, cout);
03165       }
03166 
03167       // -- Generate uses if required
03168 
03169       if (rhs_value.is_a_use)
03170         generate_uses(info, current, uses, rhs_value);
03171     }
03172 
03173     // -- Constant propagation
03174 
03175     _constants.at_binary(current, threeaddr, rhs1_value, rhs2_value, rhs_value);
03176 
03177     // -- User-defined analysis
03178 
03179     if (Problem)
03180       Problem->at_binary(current, threeaddr, rhs1_value, rhs2_value, rhs_value);
03181   }
03182 
03183   if (lhs) {
03184       
03185     // === CASE 8: Assignment
03186 
03187     pointerValue lhs_value;
03188     lhs_value.is_a_use = false;
03189     eval(info, current, lhs, threeaddr, defs, uses, changes, lhs_value,
03190          never_returns);
03191 
03192     // Result is the left-hand side
03193 
03194     result.copy_pointers_from(lhs_value);
03195 
03196     // Call assignment operator
03197 
03198     assignment_operator(info, current, (stmtLocation *)0, lhs_value, rhs_value, defs, uses, changes);
03199 
03200     // -- Generate uses if required
03201 
03202     if (result.is_a_use)
03203       generate_uses(info, current, uses, result);
03204 
03205     // -- Constant propagation
03206 
03207     _constants.at_assignment(current, lhs_value, rhs_value, result, changes);
03208 
03209     // -- User-defined analysis
03210 
03211     if (Problem)
03212       Problem->at_assignment(current, lhs_value, rhs_value, result, changes);
03213 
03214     // -- Check for struct/union assignment
03215 
03216     if(!rhs2 && rhs1) {
03217       typeNode * btype=NULL;
03218       if(!is_call)
03219         btype = rhs1->type()->follow_tdefs();
03220       else if(rhs1->cast())
03221         btype = rhs1->cast()->follow_tdefs();
03222       else if(! call_targets.blocks.empty()) {
03223         // because of unification, some block in call_targets may not
03224         // actually be a function.
03225         for(memoryblock_set_p c=call_targets.blocks.begin(); 
03226             !btype && c!=call_targets.blocks.end(); c++) {
03227           declNode *one_callee = (*c)->decl();
03228           if(one_callee && one_callee->type() &&
03229              one_callee->type()->follow_tdefs()->typ()==Func)
03230             btype = ((funcNode*) one_callee->type()->follow_tdefs())
03231                     ->returns()->follow_tdefs();
03232         }
03233         if(!btype) // use lhs
03234           btype = lhs->type()->follow_tdefs();
03235       }
03236 
03237       if (btype &&
03238           ((btype->typ() == Struct) ||
03239            (btype->typ() == Union)))
03240         {
03241           sueNode * suetype = (sueNode *) btype;
03242           struct_union_assignment(info, current, threeaddr, suetype,
03243                                   lhs_value, rhs_value, defs, uses, changes);
03244         }
03245     }
03246   }
03247 } // eval(threeAddrNode*)
03248 
03249 // ------------------------------------------------------------
03250 // Operators
03251 // ------------------------------------------------------------
03252 
03253 // Star "*" : For each operand, find the nearest dominating definition
03254 // and retrieve the pointer values from it.
03255 
03256 //#define check_pt2_size // unify_debug
03257 #define print_pt2_set  pointerOptions::Verbose // unify_debug
03258 #define p2MAX 2
03259 
03260 void Pointers::star_operator(procedureInfo * info,
03261                              Location * current,
03262                              pointerValue & operand,
03263                              memoryblock_set & defs,
03264                              memoryuse_set & uses,
03265                              memoryblock_set & changes,
03266                              pointerValue & result)
03267 {
03268   // -- If precision monitor is on, collect any dereferenced pointers that
03269   // led to this one. This is especially important in Broadway, where we
03270   // have on_entry expressions like "a --> b --> c". We need imprecision in
03271   // c to percolate up to a, not just b.
03272 
03273   if (pointerOptions::Monitor_precision) {
03274     result.dereferenced.insert(operand.dereferenced.begin(),
03275                                operand.dereferenced.end());
03276   }
03277 
03278   // -- If operands are addresses, then star is a no-op
03279 
03280   if (operand.is_address) {
03281     result.copy_pointers_from(operand);
03282     result.is_address = false; // TB
03283 
03284 #ifdef check_pt2_size
03285 if(pointerOptions::Unification) {// unify_debug
03286   bool is_ellipsis = false;
03287   int points_to_size = 0;
03288   if(result.blocks.size() > 1) {
03289     if(print_pt2_set) cout << "star & operand: ";
03290     for(memoryblock_set_p p=operand.blocks.begin();p!=operand.blocks.end();++p)
03291     { /*if((*p)->decl()->type() && (*p)->decl()->type()->typ() == Enum ||
03292          (*p)->decl()->decl_location() == declNode::ENUM ||
03293          (*p)->container() && (*p)->container()->decl() &&
03294          (*p)->container()->decl()->decl_location() == declNode::ENUM) continue;
03295       */
03296       if(print_pt2_set) cout << (*p)->name() << ",";
03297       string s = (*p)->name();
03298       if(s.find("...")<s.length() || is_va_list((*p)->decl())) is_ellipsis=true;
03299       bool is_block = s.find("malloc_#") < s.length(), 
03300            is_string = s.find("__string_") < s.length();
03301       if(! (*p)->property && !is_string &&
03302          (is_block ||!(*p)->decl()->type() ||(*p)->decl()->type()->typ()!=Func))
03303         points_to_size++;
03304     }
03305     if(print_pt2_set) cout << endl;
03306   }
03307   if(points_to_size > 1 && !is_ellipsis) {
03308     if(UnificationBasedPtr::unify_points_to_max < points_to_size)
03309       UnificationBasedPtr::unify_points_to_max=points_to_size;
03310     if(print_pt2_set)
03311       cout << "Unification points-to=" << points_to_size << " (star&) max="
03312            << UnificationBasedPtr::unify_points_to_max << "\n";
03313     assert(UnificationBasedPtr::unify_points_to_max <p2MAX);
03314   }
03315 }
03316 #endif
03317 
03318     return;
03319   }
03320 
03321   // -- Otherwise, visit each operand and follow the pointers
03322 
03323   for (memoryblock_set_p p = operand.blocks.begin();
03324        p != operand.blocks.end();
03325        ++p)
03326     {
03327       memoryBlock * mb = *p;
03328 
03329       if (mb == Memory.null()) {
03330         if (pointerOptions::Verbose)
03331           cout << "ERROR: Attempt to access location zero." << endl;
03332       }
03333       else {
03334 
03335         // -- Look up the use entry (also looks up the reaching
03336         // definition).
03337 
03338         memoryUse * use = mb->current_use();
03339         if ( ! use)
03340           use = mb->use_at(current);
03341 
03342         if ( ! mb->is_return_value())
03343           uses.insert(use);
03344 
03345         // -- Find the last assignment to it, get points-to edges
03346         // and add them to the results.
03347 
03348         memoryDef * def = use->reaching_def();
03349 
03350         if (def) {
03351 
03352           const memoryblock_set & points_to = def->points_to();
03353 
03354           if (points_to.empty())
03355             if (pointerOptions::Verbose)
03356               cout << "ERROR: Attempt to dereference a pointer with no value:" <<
03357                 mb->name() << endl;
03358 
03359 #ifdef check_pt2_size
03360 if(pointerOptions::Unification) {// unify_debug
03361   bool is_ellipsis = false;
03362   int points_to_size = 0;
03363   if(points_to.size() > 1 /*&&
03364      !((*p)->decl()->type() && (*p)->decl()->type()->typ() == Enum ||
03365         (*p)->decl()->decl_location() == declNode::ENUM)*/) {
03366     if(print_pt2_set) cout << "star operand: " << (*p)->name();
03367     string s = (*p)->name();
03368     if(print_pt2_set && (*p)->unifyType())
03369       cout << " {" << * (*p)->unifyType()->ecr() << "}";
03370     if(s.find("...") < s.length() || is_va_list((*p)->decl())) is_ellipsis=true;
03371     if(print_pt2_set) cout << " result: ";
03372     for (memoryblock_set_cp q=points_to.begin(); q!=points_to.end(); ++q)
03373     { /*if((*q)->decl()->decl_location() == declNode::ENUM ||
03374          (*q)->container() && (*q)->container()->decl() &&
03375          (*q)->container()->decl()->decl_location() == declNode::ENUM) continue;
03376       */
03377       if(print_pt2_set) {
03378         cout << *q << " " << (*q)->name();
03379         if((*q)->unifyType()) cout << " {" << * (*q)->unifyType()->ecr() << "}";
03380         cout << ", ";
03381       }
03382       s = (*q)->name();
03383       bool is_block = s.find("malloc_#") < s.length(),
03384            is_string = s.find("__string_") < s.length();
03385       if(!(*q)->property && !is_string &&
03386          (is_block || !(*q)->decl()->type() ||
03387           (*q)->decl()->type()->typ()!=Func))
03388         points_to_size++;
03389     }
03390     if(print_pt2_set) cout << endl;
03391   }
03392   if(points_to_size > 1 && !is_ellipsis) {
03393     if(UnificationBasedPtr::unify_points_to_max < points_to_size)
03394       UnificationBasedPtr::unify_points_to_max=points_to_size;
03395     if(print_pt2_set)
03396       cout << "Unification points-to=" << points_to_size << " (star) max="
03397            << UnificationBasedPtr::unify_points_to_max << "\n";
03398     assert(UnificationBasedPtr::unify_points_to_max <p2MAX);
03399   }
03400 }
03401 #endif
03402 
03403           bool may_point_to_null = false;
03404 
03405           for (memoryblock_set_cp q = points_to.begin();
03406                q != points_to.end();
03407                ++q)
03408             {
03409               memoryBlock * target = *q;
03410 
03411               if (target == Memory.null())
03412                 may_point_to_null = true;
03413               else {
03414 
03415                 // -- NOTE: we never return the null object from a star
03416                 // operation.
03417 
03418                 result.blocks.insert(*q);
03419               }
03420             }
03421 
03422           if (pointerOptions::Monitor_precision) {
03423 
03424             // -- Record that this pointer was dereferenced, but only if it
03425             // has multiple targets.
03426 
03427             if (points_to.size() > 1)
03428               result.dereferenced.insert(mb);
03429           }
03430 
03431           // -- Dereference of a possibly null pointer: now it cannot be
03432           // null
03433 
03434           if (0) { // may_point_to_null) {
03435 
03436             // -- Get all the non-null pointers
03437 
03438             pointerValue non_null_pointers;
03439 
03440             for (memoryblock_set_cp q = points_to.begin();
03441                  q != points_to.end();
03442                  ++q)
03443               {
03444                 memoryBlock * target = *q;
03445 
03446                 if (target != Memory.null())
03447                   non_null_pointers.blocks.insert(target);
03448               }
03449 
03450             // -- Use assignment
03451 
03452             pointerValue temp(mb);
03453 
03454             assignment_operator(info, current, (stmtLocation *)0, temp, non_null_pointers, defs, uses, changes);
03455           }
03456 
03457           // OLD CODE: result.blocks = def->points_to();
03458         }
03459       }
03460 
03461       if(pointerOptions::Unification && _unification_based) { // TB_unify
03462         UnifyType *mb_type = mb->is_unify() ? mb->unifyType() : NULL;
03463         if(mb_type &&
03464            (!mb->decl()->type() ||
03465             mb->decl()->no_tdef_type()->typ()!=Ptr ||
03466             mb->decl()->no_tdef_type()->no_tdef_type()->typ()!=Func) &&
03467            (mb_type->objTyp()==SIMPLE || mb_type->objTyp()==OBJECT)) {
03468           Unify_ECR *defer = _unification_based->ecrDeref(mb_type);
03469           if(defer && defer->type()->block())
03470             result.blocks.insert( defer->type()->block() );
03471         }
03472       }
03473     }
03474 
03475   // -- Store the accuracy information
03476 
03477   if (current->kind() == Location::Statement) {
03478 
03479     stmtLocation * stmt_loc = (stmtLocation *) current;
03480     // _star_accuracy[stmt_loc] = count_accuracy_pair(1, (double) result.blocks.size());
03481   }
03482 }
03483 
03484 // Dot "." : For each operand, retrieve the block corresponding to the
03485 // field with the given name. Fields are created as necessary (on
03486 // demand).
03487 
03488 void Pointers::dot_operator(Location * current,
03489                             const string & field_name,
03490                             declNode * field_decl,
03491                             pointerValue & operand,
03492                             memoryuse_set & uses,
03493                             pointerValue & result)
03494 {
03495   if (operand.is_address) {
03496     if (pointerOptions::Verbose)
03497       cout << "ERROR: Cannot apply \".\" to address." << endl;
03498     return;
03499   }
03500 
03501   for (memoryblock_set_p p = operand.blocks.begin();
03502        p != operand.blocks.end();
03503        ++p)
03504     {
03505       memoryBlock * mb = *p;
03506 
03507       if(pointerOptions::Unification && _unification_based && // TB_unify
03508          /*mb->unifyType() &&
03509          mb->unifyType() != mb->unifyType()->ecr()->type()*/
03510          // above is used when we allow unified functions. Now we don't.
03511          !mb->is_unify/*Type*/() && mb->decl()->type() &&
03512          mb->decl()->type()->typ()==Func) {
03513         // mb represents a proc and its unifyType() is supposed to be
03514         // unified with another UnifyType. If that (correct) UnifyType is
03515         // also in operand, dot that instead of this block.
03516         /*
03517         memoryBlock *unified = mb->unifyType()->ecr()->type()->block();
03518         assert(unified); // verify
03519         assert(operand.blocks.find(unified) != operand.blocks.end()); // ?? */
03520         continue; // skip this block
03521       }
03522 
03523       
03524       if (mb == Memory.null()) {
03525         if (pointerOptions::Verbose)
03526           cout << "ERROR: Attempt to access memory at address zero." << endl;
03527       }
03528       else {
03529 
03530         // -- Update the uses information: "p.field" is a use of p.
03531 
03532         memoryUse * use = mb->current_use();
03533         if ( ! use)
03534           use = mb->use_at(current);
03535 
03536         if ( ! mb->is_return_value())
03537           uses.insert(use);
03538 
03539         if (pointerOptions::Ignore_fields) {
03540 
03541           // -- Option: struct/union field access is a no-op
03542 
03543           result.blocks.insert(mb);
03544 
03545           // -- Force weak updates..
03546 
03547           mb->set_indexed();
03548         }
03549         else {
03550 
03551           // -- Retrieve the field
03552 
03553           memoryBlock * block = *p;
03554 
03555           if (block->write_protected()) {
03556             if (pointerOptions::Verbose)
03557               cout << "ERROR at " << * current << ": attempt to access field " << field_name 
03558                    << " of write-protected block " << block->name() << endl;
03559           }
03560           else
03561             block->dot(field_name, field_decl, Memory, result.blocks);
03562         }
03563       }
03564 
03565       if(pointerOptions::Unification && _unification_based) { // TB_unify
03566         UnifyType *mb_type = mb->is_unify() ? mb->unifyType() : NULL;
03567         if(mb_type &&
03568            (!field_decl->type() ||
03569             field_decl->no_tdef_type()->typ()!=Ptr ||
03570             field_decl->no_tdef_type()->no_tdef_type()->typ()!=Func) &&
03571            (mb_type->objTyp()==STRUCTURE || mb_type->objTyp()==OBJECT)) {
03572           bool from_annotation;
03573           Unify_ECR *field = _unification_based->ecrField(mb_type, field_decl,
03574                                                           from_annotation);
03575           if(field && field->type()->block())
03576             result.blocks.insert( field->type()->block() );
03577         }
03578       }
03579     }
03580 
03581   // -- Copy all the dereferenced pointers
03582 
03583   result.dereferenced.insert(operand.dereferenced.begin(),
03584                              operand.dereferenced.end());
03585 #ifdef check_pt2_size
03586 if(pointerOptions::Unification) { // unify_debug
03587   int result_size = 0;
03588   if(result.blocks.size() > 1) {
03589     if(print_pt2_set) cout << "dot operand: ";
03590     for (memoryblock_set_p p=operand.blocks.begin();p!=operand.blocks.end();++p)
03591     { // if((*p)->decl()->decl_location() == declNode::ENUM) continue;
03592       if(print_pt2_set) cout << (*p)->name() << ", ";
03593     }
03594     if(print_pt2_set) cout << "\nresult: ";
03595     for (memoryblock_set_p p=result.blocks.begin(); p!=result.blocks.end(); ++p)
03596     { /* if((*p)->container() && (*p)->container()->decl() &&
03597          (*p)->container()->decl()->decl_location() == declNode::ENUM) continue;
03598       */
03599       if(print_pt2_set) cout << *p << " " << (*p)->name() << ", ";
03600       string s = (*p)->name();
03601       bool is_block = s.find("malloc_#") < s.length();
03602       if(! (*p)->property &&
03603          (is_block || (*p)->decl()->type()&& (*p)->decl()->type()->typ()!=Func))
03604         result_size++;
03605     }
03606     if(print_pt2_set) cout << endl;
03607   }
03608   if(result_size > 1) {
03609     if(UnificationBasedPtr::unify_points_to_max < result_size)
03610       UnificationBasedPtr::unify_points_to_max=result_size;
03611     if(print_pt2_set)
03612       cout << "Unification points-to=" << result_size << " (dot) max="
03613            << UnificationBasedPtr::unify_points_to_max << "\n";
03614     assert(UnificationBasedPtr::unify_points_to_max <p2MAX);
03615   }
03616 }
03617 #endif
03618 }
03619 
03626 void Pointers::struct_union_assignment(procedureInfo * info,
03627                                        stmtLocation * current,
03628                                        threeAddrNode *threeaddr,
03629                                        sueNode * suetype,
03630                                        pointerValue & left_hand_side,
03631                                        pointerValue & right_hand_side,
03632                                        memoryblock_set & defs,
03633                                        memoryuse_set & uses,
03634                                        memoryblock_set & changes)
03635 {
03636   // -- Visit each field in the struct/union definition
03637 
03638   suespecNode * spec = suetype->spec();
03639   
03640   if (spec) {
03641 
03642     if (pointerOptions::Verbose)
03643       cout << "Struct/Union assignment: type is " << spec->name() << endl;
03644 
03645     decl_list & fields = spec->fields();
03646 
03647     for (decl_list_p p = fields.begin();
03648          p != fields.end();
03649          ++p)
03650       {
03651         declNode * field = *p;
03652             
03653         // -- Get the field from the left-hand side
03654 
03655         pointerValue left_field;
03656 
03657         dot_operator(current, field->name(), field,
03658                      left_hand_side, uses, left_field);
03659 
03660         // -- Get the field from the right-hand side
03661 
03662         pointerValue right_field;
03663 
03664         dot_operator(current, field->name(), field,
03665                      right_hand_side, uses, right_field);
03666 
03667         generate_uses(info, current, uses, right_field);        
03668 
03669         // -- Assign the current objects
03670 
03671         assignment_operator(info, current, (stmtLocation *)0, left_field, right_field, 
03672                             defs, uses, changes);
03673 
03674         pointerValue ignore_result;
03675 
03676         // -- Constant propagation
03677 
03678         _constants.at_assignment(current, left_field, right_field,
03679                                  ignore_result, changes);
03680 
03681         // -- User-defined analysis
03682 
03683         if (Problem)
03684           Problem->at_assignment(current, left_field, right_field,
03685                                  ignore_result, changes);
03686 
03687         // -- If this field is itself a struct/union, then call this method
03688         // recursively
03689 
03690         typeNode * field_type = field->no_tdef_type();
03691 
03692         if ((field_type->typ() == Struct) ||
03693             (field_type->typ() == Union))
03694           {
03695             sueNode * field_suetype = (sueNode *) field_type;
03696 
03697             struct_union_assignment(info, current, threeaddr, field_suetype,
03698                                     left_field, right_field, defs, uses, changes);
03699           }
03700       }
03701   }
03702 }
03703 
03712 void Pointers::assignment_operator(procedureInfo * info,
03713                                    Location * current,
03714                                    stmtLocation * parameter_callsite,
03715                                    pointerValue & left_hand_side,
03716                                    pointerValue & right_hand_side,
03717                                    memoryblock_set & defs,
03718                                    memoryuse_set & uses,
03719                                    memoryblock_set & changes)
03720 {
03721   bool unique_lhs = false;
03722   bool changed = false;
03723   
03724   // -- Quick short-circuit
03725 
03726   if (left_hand_side.blocks.empty())
03727     return;
03728 
03729   // -- Get the right-hand-side constant value
03730 
03731   const constant * right_c = right_hand_side.constant_value;
03732 
03733   // -- Build the RHS set of pointers
03734 
03735   memoryblock_set rhs_points_to;
03736 
03737   // -- Precision analysis: keep track of may and must pointers
03738 
03739   int min_size = 999999;
03740   bool any_must_pointers = false;
03741   memoryblock_set complicit_pointers;
03742 
03743   // -- Handle the two different kinds of RHS
03744 
03745   if (right_hand_side.is_address) {
03746 
03747     // -- If the RHS is a list of addresses, then the new points-to set
03748     // just consists of the RHS objects themselves...
03749 
03750     memoryblock_set & rhs_blocks = right_hand_side.blocks;
03751 
03752     rhs_points_to.insert(rhs_blocks.begin(),
03753                          rhs_blocks.end());
03754 
03755     // -- Special case: for address objects, set any_must_pointers to true
03756 
03757     // any_must_pointers = true;
03758     min_size = 1; // rhs_blocks.size();
03759   }
03760   else {
03761 
03762     // Regular assignment: visit each RHS objects and collect the objects
03763     // that they point to.
03764 
03765     for (memoryblock_set_p q = right_hand_side.blocks.begin();
03766          q != right_hand_side.blocks.end();
03767          ++q)
03768       {
03769         memoryBlock * right = *q;
03770 
03771         // Look up a use entry -- NOTE: the reaching definition
03772         // should already be there from generate_uses.
03773 
03774         memoryUse * right_use = right->current_use();
03775         if ( ! right_use)
03776           right_use = right->use_at(current);
03777 
03778         // Find the last assignment to it, get points-to edges and
03779         // add them to the LHS.
03780 
03781         memoryDef * reaching_def = right_use->reaching_def();
03782         if (reaching_def) {
03783           const memoryblock_set & reaching_points_to = reaching_def->points_to();
03784 
03785           rhs_points_to.insert(reaching_points_to.begin(),
03786                                reaching_points_to.end());
03787 
03788           // -- Monitor: keep track of may and must pointers.
03789 
03790           if (pointerOptions::Monitor_precision) {
03791 
03792             int size = reaching_points_to.size();
03793             if (size < min_size)
03794               // any_must_pointers = true;
03795               min_size = size;
03796 
03797             if (size > 1)
03798               complicit_pointers.insert(right);
03799           }
03800           
03801         }
03802         else
03803           if (pointerOptions::Verbose) {
03804             cout << "WARNING: Variable " << right->name() <<
03805               " may not have a value at " << *current << endl;
03806             right->print_def_use(cout);
03807           }
03808 
03809         if(pointerOptions::Unification && _unification_based) { // TB_unify
03810           UnifyType *right_type = right->is_unify() ?
03811                                   right->unifyType() : NULL;
03812           if(right_type &&
03813              (!right->decl()->type() ||
03814               right->decl()->no_tdef_type()->typ()!=Ptr ||
03815               right->decl()->no_tdef_type()->no_tdef_type()->typ()!=Func) &&
03816              (right_type->objTyp()==SIMPLE || right_type->objTyp()==OBJECT)) {
03817             Unify_ECR *defer = _unification_based->ecrDeref(right_type);
03818             if(defer && defer->type()->block()) {
03819               rhs_points_to.insert( defer->type()->block() );
03820             }
03821           }
03822         }
03823 
03824       }
03825   }
03826 
03827   // -- If there is only one object on the left, then it is a strong
03828   // update.
03829 
03830   // TB: new 2nd clause below.
03831   if (left_hand_side.blocks.size() == 1 &&
03832       ! left_hand_side.blocks.front()->is_indexed())
03833     unique_lhs = true;
03834 
03835   // -- Store the accuracy information
03836 
03837   if (current->kind() == Location::Statement) {
03838 
03839     stmtLocation * stmt_loc = (stmtLocation *) current;
03840     // _def_accuracy[stmt_loc] = count_accuracy_pair(1, (double) left_hand_side.blocks.size());
03841   }
03842 
03843   // -- Save the size of the RHS points-to set
03844 
03845   int rhs_points_to_size = rhs_points_to.size();
03846 
03847   // -- Monitor: if the right-hand-side pointer value is larger than one,
03848   // even though there were must-pointers on the right-hand-side, then
03849   // we'll blame the dereferenced objects.
03850 
03851   // Example:  p = *q; where     /-> a --> b
03852   //                         q -<
03853   //                             \-> c --> d
03854 
03855   if (pointerOptions::Monitor_precision) {
03856 
03857     if ((rhs_points_to_size > 1) && (rhs_points_to_size > min_size)) // any_must_pointers)
03858       complicit_pointers.insert(right_hand_side.dereferenced.begin(),
03859                                 right_hand_side.dereferenced.end());
03860   }
03861 
03862   // -- Bidirectional assignment
03863 
03864   if (pointerOptions::Bidirectional_assignment) {
03865 
03866     // -- The way we implement "equality-based" analysis is sort of a hack:
03867     // we take all the objects on the right-hand side and force them to
03868     // also be on the left. For example, "y = x" becomes "{y,x} = x". This
03869     // essentially forces all of the objects to take on the same value.
03870 
03871     if ( ! right_hand_side.is_address) {
03872       left_hand_side.blocks.insert(right_hand_side.blocks.begin(),
03873                                    right_hand_side.blocks.end());
03874     }
03875 
03876     // -- Also, collect all the existing points-to sets from the left-hand
03877     // side objects.
03878 
03879     for (memoryblock_set_p p = left_hand_side.blocks.begin();
03880          p != left_hand_side.blocks.end();
03881          ++p)
03882       {
03883         memoryBlock * left = *p;
03884 
03885         memoryDef * def = left->find_def_at(current);
03886         if (def) {
03887           const memoryblock_set & points_to = def->points_to();
03888 
03889           rhs_points_to.insert(points_to.begin(),
03890                                points_to.end());
03891         }
03892       }
03893   }
03894 
03895   // -- For each object on the left
03896 
03897   for (memoryblock_set_p p = left_hand_side.blocks.begin();
03898        p != left_hand_side.blocks.end();
03899        ++p)
03900     {
03901       memoryBlock * left = *p;
03902 
03903       // -- Are we allowed to modify this object?
03904 
03905       if ( ! left->write_protected()) {
03906 
03907         // -- Look up or create a def entry
03908 
03909         bool is_new;
03910         memoryDef * left_def = left->def_at(current, is_new);
03911 
03912 #ifdef COLLECT_DEFS
03913         defs.insert(left);
03914 #endif
03915 
03916         // -- If we are actually computing the pointer info...
03917 
03918         if (computePointers) {
03919 
03920           // -- If the assignment resulted in a new memoryDef instance, then
03921           // it automatically is a "change".
03922 
03923           if (is_new) {
03924             changes.insert(left);
03925             changed = true;
03926           }
03927 
03928           // -- Save the current points-to edges. Here we don't mean the
03929           // incoming flow value, we mean the flow value at this point the
03930           // last time we visited it. We'll use this to test for convergence.
03931 
03932           memoryblock_set previous = left_def->points_to();
03933 
03934           // -- All this junk is only needed for flow-sensitive objects
03935 
03936           bool single_multiplicity = false;
03937           bool strong_update = true;
03938           memoryDef * reaching_def = 0;
03939           bool reaching_def_is_must_pointer = false;
03940 
03941           Multiplicity multiplicity = current_multiplicity(info, current, left, uses);
03942 
03943           if (left->is_flow_sensitive()) {
03944 
03945             // -- Figure out whether this is a strong or weak update. We can
03946             // perform a strong update when we have a single LHS object, and
03947             // that object is not a multi-object
03948 
03949             single_multiplicity = ((multiplicity == Unallocated) ||
03950                                    (multiplicity == Deallocated) ||
03951                                    (multiplicity == Single));
03952 
03953             strong_update = unique_lhs && single_multiplicity;
03954 
03955             // Standard version: strong_update = unique_lhs && (multiplicity == Single);
03956 
03957             // -- For weak updates, we include the points-to values before the
03958             // assignment; that is, we just accumulate points-to information at
03959             // each assignment.
03960             
03961             if ( ! strong_update) {
03962 
03963               // -- Find and set the previous reaching definition in
03964               // preparation for a weak def.
03965 
03966               reaching_def = nearest_def_at(info, left, current);
03967               // left_def->set_previous(reaching_def);
03968 
03969               // -- If the def wasn't weak and now it is, then that's a
03970               // change
03971 
03972               if ( ! left_def->is_weak()) {
03973                 changes.insert(left);
03974                 changed = true;
03975               }
03976 
03977               left->apply_weak_update(current, reaching_def, uses);
03978 
03979               // -- Record if the reaching was a must pointer
03980               /*
03981               if (reaching_def &&
03982                   (reaching_def->points_to().size() <= 1))
03983                 reaching_def_is_must_pointer = true;
03984               */
03985             }
03986           }
03987 
03988           // -- New way to handle null pointer: if the right-hand-side is
03989           // zero and the left object is a pointer type, then perform add
03990           // the null block.
03991 
03992           /*
03993           if (right_c &&
03994               (right_c->is_zero()) &&
03995               left->decl()->type() &&
03996               (left->decl()->type()->typ() == Ptr))
03997             {
03998               memoryblock_set temp;
03999               temp.insert(Memory.null());
04000               left_def->add_pointers(temp);
04001             }
04002           */
04003 
04004           // -- Perform the points-to assignment
04005 
04006           left_def->add_pointers(rhs_points_to);
04007 
04008           if(pointerOptions::Unification && _unification_based) { // TB_unify
04009             UnifyType *left_type = left->is_unify() ?
04010                                    left->unifyType() : NULL;
04011             if(left_type &&
04012                (!left->decl()->type() ||
04013                 left->decl()->no_tdef_type()->typ()!=Ptr ||
04014                 left->decl()->no_tdef_type()->no_tdef_type()->typ()!=Func) &&
04015                (left_type->objTyp()==SIMPLE || left_type->objTyp()==OBJECT)) {
04016               Unify_ECR *defer = _unification_based->ecrDeref(left_type);
04017               if(defer && defer->type()->block()) {
04018                 memoryblock_set left_point_to;
04019                 left_point_to.insert( defer->type()->block() );
04020                 left_def->add_pointers( left_point_to );
04021               }
04022             }
04023           }
04024 
04025           const memoryblock_set & lhs_points_to = left_def->points_to();
04026 
04027           /*
04028           if ((left->name() == "LISTSEPARATOR") ||
04029               (left->name() == "HandlePath::path") ||
04030               (left->name() == "yytext"))
04031             {
04032               cout << left->name();
04033               print_memoryblock_set(" : ", lhs_points_to, cout);
04034               cout << * current << endl;
04035             }
04036           */
04037 
04038           // -- Monitor: if the left-hand-side object ends up as a
04039           // may-pointer, figure out why and then store the destructive and
04040           // complicit assignment information.
04041 
04042           if (pointerOptions::Monitor_precision) {
04043 
04044             // -- If this is a parameter being passed, then record the
04045             // reaching defs.
04046 
04047             if ((parameter_callsite) &&
04048                 (current->kind() == Location::Procedure))
04049               {
04050                 procLocation * procloc = (procLocation *) current;
04051 
04052                 left->add_parameter_assignment(procloc->proc(),
04053                                                parameter_callsite,
04054                                                right_hand_side.blocks);
04055               }
04056 
04057             if (lhs_points_to.size() > 1) {
04058 
04059               // -- Any right-hand-side may-pointers are automatically complicit
04060 
04061               left->add_complicit_assignment(current, complicit_pointers);
04062 
04063               // -- Something bad happened: the left-hand side is larger
04064               // than the right-hande side:
04065 
04066               if (rhs_points_to_size < lhs_points_to.size()) {
04067 
04068                 // -- Check for strong or weak update...
04069 
04070                 if (strong_update) {
04071 
04072                   // -- Strong update: these kinds of assignments are only
04073                   // destructive if the right-hand-side evaluates to a single
04074                   // must-pointer value, but the left ends up as a may
04075                   // pointer.
04076 
04077                   if (current->kind() == Location::Statement) {
04078 
04079                     // -- Regular statement: this can only happend with an
04080                     // additive assignment caused by flow-insensitivity.
04081                     
04082                     left->add_destructive_assignment(current, memoryBlock::Additive);
04083                   }
04084 
04085                   if (current->kind() == Location::Procedure) {
04086 
04087                     // -- Parameter pass: this happens when the procedure
04088                     // is context-insensitive and it gets different values
04089                     // in the different contexts.
04090 
04091                     left->add_destructive_assignment(current, memoryBlock::Parameter_pass);
04092                   }
04093                 }
04094                 else {
04095 
04096                   // -- Weak update: see if it had a bad effect
04097 
04098                   if (reaching_def &&
04099                       (reaching_def->points_to().size() < lhs_points_to.size())) {
04100 
04101                     // -- If a weak update occured, check to see if it was caused by
04102                     // multiple left-hand-sides or by multiplicity.
04103 
04104                     if ( ! single_multiplicity) {
04105 
04106                       // -- High-multiplicity: this is an additive assignment
04107                       // because of allocation or array access. If the previous
04108                       // reaching def was a must pointer, then this is a
04109                       // destructive assignment.
04110 
04111                       // -- If this is a heap object, then blame the
04112                       // allocation information attached to the alloc
04113                       // object.
04114 
04115                       memoryBlock * alloc_object = left->allocation_object();
04116                       if (alloc_object)
04117                         left->add_complicit_assignment(current, alloc_object);
04118                       else
04119                         left->add_destructive_assignment(current, memoryBlock::Weak_update);
04120                     }
04121 
04122                     if ( ! unique_lhs) {
04123                     
04124                       // -- Multiple left-hand-sides: the problem is the
04125                       // left-hand dereferenced pointers.
04126 
04127                       left->add_complicit_assignment(current, left_hand_side.dereferenced);
04128                     }
04129                   }
04130                 }
04131               }
04132             }
04133           } // -- END monitor
04134 
04135           // -- Check for change
04136 
04137           if (lhs_points_to != previous) {
04138             changes.insert(left);
04139 #ifdef check_pt2_size
04140 if(pointerOptions::Unification) {// unify_debug
04141   bool is_ellipsis = false;
04142   int points_to_size = 0;
04143   if(lhs_points_to.size() > 1) {
04144     if(print_pt2_set) cout << "lhs_points_to: ";
04145     for(memoryblock_set_cp p=lhs_points_to.begin(); p!=lhs_points_to.end(); ++p)
04146     { /* if((*p)->decl()->type() && (*p)->decl()->type()->typ() == Enum ||
04147          (*p)->decl()->decl_location() == declNode::ENUM ||
04148          (*p)->container() && (*p)->container()->decl() &&
04149          (*p)->container()->decl()->decl_location() == declNode::ENUM) continue;
04150       */
04151       if(print_pt2_set) cout << (*p)->name() << ",";
04152       string s = (*p)->name();
04153       if(s.find("...")<s.length() || is_va_list((*p)->decl())) is_ellipsis=true;
04154       bool is_block = s.find("malloc_#") < s.length(),
04155            is_string = s.find("__string_") < s.length();
04156       if(! (*p)->property && !is_string &&
04157          (is_block ||!(*p)->decl()->type() ||(*p)->decl()->type()->typ()!=Func))
04158         points_to_size++;
04159     }
04160     if(print_pt2_set) cout << endl;
04161   }
04162   if(points_to_size > 1 && !is_ellipsis) {
04163     if(UnificationBasedPtr::unify_points_to_max < points_to_size)
04164       UnificationBasedPtr::unify_points_to_max=points_to_size;
04165     if(print_pt2_set)
04166       cout << "Unification points-to=" << points_to_size
04167            << " (lhs_points_to) max="
04168            << UnificationBasedPtr::unify_points_to_max << "\n";
04169     assert(UnificationBasedPtr::unify_points_to_max <p2MAX);
04170   }
04171 }
04172 #endif
04173             changed = true;
04174 
04175             /*
04176             if ( ! previous.empty()) {
04177               if (left->is_flow_sensitive())
04178                 cout << "FS-";
04179               else
04180                 cout << "FI-";
04181 
04182               if (current->kind() == Location::Statement)
04183                 cout << "ASSIGN:";
04184               else
04185                 cout << "PASS:";
04186 
04187               cout << " lost information about " 
04188                    << left->name() << " at " << * current << endl;
04189               print_memoryblock_set("    WAS: ", previous, cout);
04190               print_memoryblock_set("    NOW: ", lhs_points_to, cout);
04191             }
04192             */
04193           }
04194 
04195           if (pointerOptions::Verbose) {
04196 
04197             if (left->is_flow_sensitive()) {
04198               if (strong_update)
04199                 cout << "  Strong assign -- ";
04200               else
04201                 cout << "  Weak assign -- ";
04202             }
04203             else
04204               cout << "  Flow-insensitive assign -- ";
04205 
04206             memoryBlock::print_multiplicity(multiplicity, cout);
04207             cout << " -- ";
04208 
04209             if (changed)
04210               cout << "changed: ";
04211             else
04212               cout << "unchanged: ";
04213 
04214             cout << left->name() << endl;
04215             left_def->print(cout);
04216 
04217             if ( ! lhs_points_to.empty())
04218               print_memoryblock_set("      points-to NOW: ", lhs_points_to, cout);
04219 
04220             if (reaching_def) {
04221               cout << "    Reaching def at " << * (reaching_def->where());
04222               print_memoryblock_set(" before assignment: ", reaching_def->points_to(), cout);
04223             }
04224 
04225             if (changed && ( ! previous.empty()))
04226               print_memoryblock_set("      points-to WAS: ", previous, cout);
04227             
04228             cout << endl;
04229           }
04230         }
04231         else {
04232 
04233           // Not computing pointers...
04234 
04235           // -- Make sure that the "current_use" field is set for blocks that
04236           // have weak updates.
04237 
04238           if (left_def->is_weak()) {
04239             memoryUse * use = left->use_at(current);
04240             // uses.insert(use);
04241           }
04242 
04243           if (is_new) {
04244 
04245             if (pointerOptions::Verbose) {
04246               cout << "WARNING: in assignment: No new defs of " << left->name()
04247                    << " should be created at " << *current << " in ";
04248               Procedures.print_call_stack(cout);
04249               cout << endl;
04250             }
04251 
04252             changes.insert(left);
04253           }
04254         }
04255       }
04256     } /* END for all LHS */
04257 }
04258 
04259 void Pointers::merge_operator(procedureInfo * info,
04260                               Location * merge_point,
04261                               memoryBlock * block_to_merge,
04262                               memoryuse_list & phi_uses,
04263                               memoryblock_set & defs,
04264                               memoryuse_set & uses,
04265                               memoryblock_set & changes)
04266 {
04267   bool changed = false;
04268 
04269   // -- Are we allowed to modify this object?
04270 
04271   if (block_to_merge->write_protected())
04272     return;
04273 
04274   // -- Set up a def at the merge point
04275 
04276   bool is_new;
04277   memoryDef * def = block_to_merge->def_at(merge_point, is_new);
04278 
04279 #ifdef COLLECT_DEFS
04280   defs.insert(block_to_merge);
04281 #endif
04282 
04283   // -- If we are actually computing the pointer info...
04284 
04285   if (computePointers) {
04286 
04287     // -- If the merge resulted in a new memoryDef instance, then it
04288     // automatically is a "change".
04289 
04290     if (is_new) {
04291       changes.insert(block_to_merge);
04292       changed = true;
04293     }
04294 
04295     if (block_to_merge->is_allocation_object()) {
04296 
04297       // --------------------------------------------------
04298       //   Special behavior for allocation objects
04299 
04300       // -- Save the previous value
04301 
04302       Multiplicity old_multiplicity = def->multiplicity();
04303 
04304       // -- Compute the multiplicity of the new definition
04305 
04306       Multiplicity multiplicity = Unallocated;
04307 
04308       // -- Merge in the multiplicity values of each use
04309 
04310       Multiplicity min = Error;
04311 
04312       for (memoryuse_list_p use_p = phi_uses.begin();
04313            use_p != phi_uses.end();
04314            ++use_p)
04315         {
04316           memoryUse * use = *use_p;
04317 
04318           uses.insert(use);
04319 
04320           // -- Get the reaching value
04321 
04322           memoryDef * reaching_def = use->reaching_def();
04323           if (reaching_def) {
04324 
04325             // -- Include the multiplicity: we'll use max() as the meet
04326             // function because the Multiplicity enum is ordered so that
04327             // the conservative value is the largest.
04328 
04329             Multiplicity reaching_multiplicity = reaching_def->multiplicity();
04330 
04331             if (reaching_multiplicity > multiplicity)
04332               multiplicity = reaching_multiplicity;
04333 
04334             // -- Compute the min value as well. We need this for the
04335             // aggressive multiplicity mode.
04336 
04337             if (reaching_multiplicity < min)
04338               min = reaching_multiplicity;
04339           }
04340         }
04341 
04342       // -- Aggressive mode: if the new value is Single and the min value
04343       // is Deallocated, then just go to Unallocated. This is not sound,
04344       // but probably is correct in practice. Question: is there a way we
04345       // can make it sound?
04346 
04347       if (pointerOptions::Aggressive_multiplicity) {
04348 
04349         if ((multiplicity == Single) &&
04350             (min == Deallocated))
04351           multiplicity = Unallocated;
04352       }
04353 
04354       // -- Always meet with the old value
04355 
04356       if (old_multiplicity > multiplicity)
04357         multiplicity = old_multiplicity;
04358 
04359       // -- Set the new multiplicity
04360 
04361       def->set_multiplicity(multiplicity);
04362 
04363       // -- Check for change
04364 
04365       if (multiplicity != old_multiplicity) {
04366         changes.insert(block_to_merge);
04367         changed = true;
04368       }
04369 
04370       if (pointerOptions::Verbose) {
04371         cout << "Merge -- ";
04372 
04373         if (changed)
04374           cout << "changed: ";
04375         else
04376           cout << "unchanged: ";
04377 
04378         cout << block_to_merge->name() << " : ";
04379 
04380         memoryBlock::print_multiplicity(old_multiplicity, cout);
04381         cout << " -> ";
04382         memoryBlock::print_multiplicity(multiplicity, cout);
04383         cout << endl;
04384 
04385         def->print(cout);
04386         cout << endl;
04387       }
04388     }
04389     else {
04390 
04391       // --------------------------------------------------
04392       //   Regular objects
04393 
04394       // -- Save the previous points-to edges
04395 
04396       memoryblock_set previous = def->points_to();
04397 
04398       // -- Record if any of the reaching defs are must-pointers
04399 
04400       bool any_must_pointers = false;
04401 
04402       // -- Collect the new points-to set from the merge uses
04403 
04404       memoryblock_set merged_points_to;
04405 
04406       for (memoryuse_list_p use_p = phi_uses.begin();
04407            use_p != phi_uses.end();
04408            ++use_p)
04409         {
04410           memoryUse * use = *use_p;
04411 
04412           if (! use) {
04413 
04414             cout << "ERROR: block " << block_to_merge->name() << " at " << *merge_point << endl;
04415             cout << "    Num uses = " << phi_uses.size() << endl;
04416             block_to_merge->print_def_use(cout);
04417           }
04418 
04419           uses.insert(use);
04420 
04421           // -- Add the pointers from the reaching definition. It is
04422           // possible that there is no reaching definition on one or more
04423           // of the uses. This typically means that the variable being
04424           // merged is dead, but we arent' checking that right now.
04425 
04426           memoryDef * reaching_def = use->reaching_def();
04427           if (reaching_def) {
04428             const memoryblock_set & reaching_points_to = reaching_def->points_to();
04429 
04430             if (reaching_points_to.size() <= 1)
04431               any_must_pointers = true;
04432 
04433             merged_points_to.insert(reaching_points_to.begin(),
04434                                    reaching_points_to.end());
04435           }
04436         }
04437 
04438       // -- Add the merge points-to set
04439 
04440       def->add_pointers(merged_points_to);
04441 
04442       // -- Monitor: check for destructive merge
04443 
04444       if (pointerOptions::Monitor_precision) {
04445 
04446         if ((def->points_to().size() > 1) &&
04447             any_must_pointers) {
04448 
04449           // -- This merge caused must-pointers to be lost
04450 
04451           block_to_merge->add_destructive_assignment(merge_point, memoryBlock::Control_flow);
04452         }
04453       }
04454 
04455       // -- Check for change
04456 
04457       if (def->points_to() != previous) {
04458         changes.insert(block_to_merge);
04459         changed = true;
04460       }
04461 
04462       if (pointerOptions::Verbose) {
04463         cout << "Merge -- ";
04464 
04465         if (changed)
04466           cout << "changed: ";
04467         else
04468           cout << "unchanged: ";
04469 
04470         cout << block_to_merge->name() << endl;
04471         def->print(cout);
04472 
04473         if ( ! def->points_to().empty())
04474           print_memoryblock_set("      points-to: ", def->points_to(), cout);
04475         cout << endl;
04476       }
04477     }
04478   }
04479   else {
04480 
04481     // Not computing pointers...
04482 
04483     if (is_new) {
04484 
04485       if (pointerOptions::Verbose) {
04486         cout << "WARNING: in merge: No new defs of " << block_to_merge->name() <<
04487           " should be created at " << * merge_point << endl;
04488         Procedures.print_call_stack(cout);
04489 
04490         cout << endl;
04491 
04492         block_to_merge->print_def_use(cout);
04493 
04494         cout << endl;
04495       }
04496 
04497       changes.insert(block_to_merge);
04498     }
04499   }
04500 }
04501 
04508 void Pointers::self_assignment(Location * source,
04509                                Location * target,
04510                                memoryBlock * block,
04511                                memoryblock_set & changes)
04512 {
04513   bool changed = false;
04514 
04515   // -- Are we allowed to modify this object?
04516 
04517   if (block->write_protected())
04518     return;
04519 
04520   // -- Set up a def at the target location
04521 
04522   bool is_new;
04523   memoryDef * def = block->def_at(target, is_new);
04524 
04525   // -- Get the use from the source location. Note: any method calling
04526   // this one should probably set the reaching def on this use.
04527 
04528   memoryUse * use = block->use_at(source);
04529 
04530   // -- Record the special relationship:
04531 
04532   def->set_self_assign_use(use);
04533 
04534   // -- Get the reaching def
04535 
04536   memoryDef * reaching_def = use->reaching_def();
04537 
04538   // -- If we are actually computing the pointer info...
04539 
04540   if (computePointers) {
04541 
04542     // -- If the merge resulted in a new memoryDef instance, then it
04543     // automatically is a "change".
04544 
04545     if (is_new) {
04546       changes.insert(block);
04547       changed = true;
04548     }
04549 
04550     // -- Flow insensitive objects don't need self-assignment
04551 
04552     if ( ! block->is_flow_sensitive())
04553       return;
04554 
04555     // -- Record the self-assignment, if this is an input
04556 
04557     if ((target->kind() == Location::Procedure) &&
04558         (source->kind() == Location::Statement))
04559     {
04560       procLocation * procloc = (procLocation *) target;
04561       stmtLocation * callsite = (stmtLocation *) source;
04562 
04563       // -- Let Broadway handle property blocks
04564 
04565       if ( ! block->property)
04566         block->add_parameter_assignment(procloc->proc(),
04567                                         callsite,
04568                                         block);
04569     }
04570 
04571     if (block->is_allocation_object()) {
04572 
04573       // --------------------------------------------------
04574       //   Special behavior for allocation objects
04575 
04576       // -- Save the previous value
04577 
04578       Multiplicity old_multiplicity = def->multiplicity();
04579 
04580       // -- Get the reaching multiplicity value. If there isn't one, then
04581       // the value will be "Unallocated", which behaves like TOP.
04582 
04583       Multiplicity reaching_multiplicity = Unallocated;
04584       if (reaching_def)
04585         reaching_multiplicity = reaching_def->multiplicity();
04586 
04587       // -- Always meet with the old value (take the max)
04588 
04589       Multiplicity multiplicity;
04590 
04591       if (old_multiplicity > reaching_multiplicity)
04592         multiplicity = old_multiplicity;
04593       else
04594         multiplicity = reaching_multiplicity;
04595 
04596       // -- Set the new multiplicity
04597       
04598       def->set_multiplicity(multiplicity);
04599 
04600       // -- Monitor: check for parameter pass loss of allocation
04601       // information
04602 
04603       if (pointerOptions::Monitor_precision) {
04604 
04605         // -- A destructive assignment for the allocation object occurs
04606         // when the multiplicity value coming from different call sites is
04607         // different. The only case we care about is when one of the values
04608         // is Single and the other is Unbounded.
04609 
04610         if (((old_multiplicity == Single) && (reaching_multiplicity == Unbounded)) ||
04611             ((old_multiplicity == Unbounded) && (reaching_multiplicity == Single))) {
04612 
04613           /*
04614           cout << "DESTRUCTIVE " << block->name() << " at " << * target << " : ";
04615           memoryBlock::print_multiplicity(old_multiplicity, cout);
04616           cout << " -> ";
04617           memoryBlock::print_multiplicity(reaching_multiplicity, cout);
04618           cout << endl;
04619           */
04620 
04621           block->add_destructive_assignment(target, memoryBlock::Parameter_pass);
04622         }
04623       }
04624 
04625       // -- Check for change
04626 
04627       if (multiplicity != old_multiplicity) {
04628         changes.insert(block);
04629         changed = true;
04630       }
04631 
04632       if (pointerOptions::Verbose) {
04633         cout << "  Self-assign -- ";
04634 
04635         if (changed)
04636           cout << "changed: ";
04637         else
04638           cout << "unchanged: ";
04639 
04640         cout << block->name() << " : ";
04641 
04642         memoryBlock::print_multiplicity(old_multiplicity, cout);
04643         cout << " -> ";
04644         memoryBlock::print_multiplicity(multiplicity, cout);
04645         cout << endl;
04646 
04647         def->print(cout);
04648       }
04649     }
04650     else {
04651 
04652       // --------------------------------------------------
04653       //   Regular variables
04654 
04655       // -- Save the previous points-to edges
04656 
04657       memoryblock_set previous = def->points_to();
04658 
04659       // -- Add in points-to edges from the source
04660 
04661       if (reaching_def) {
04662 
04663         // -- Add the pointers
04664 
04665         def->add_pointers(reaching_def->points_to());
04666       }
04667 
04668       // -- Monitor: check for parameter pass loss of information
04669 
04670       if (pointerOptions::Monitor_precision) {
04671 
04672         memoryBlock * current = block;
04673 
04674         // -- Find the top-most object container
04675 
04676         while (current->container()) {
04677           if(_unification_based && current == current->container())
04678             break;
04679           current = current->container();
04680         }
04681 
04682         if (current->decl()->decl_location() == declNode::TOP) {
04683           if (reaching_def &&
04684               (previous.size() > 0) &&
04685               (reaching_def->points_to().size() > 0) &&
04686               (def->points_to().size() > reaching_def->points_to().size())) {
04687 
04688             // -- The reaching def was a must-pointer, but the assignment
04689             // resulted in a may-pointer.
04690 
04691             block->add_destructive_assignment(target, memoryBlock::Parameter_pass);
04692           }
04693         }
04694       }
04695 
04696       // -- Check for change
04697 
04698       if (def->points_to() != previous) {
04699         changes.insert(block);
04700         changed = true;
04701       }
04702 
04703       if (pointerOptions::Verbose) {
04704         cout << "  Self-assign -- ";
04705 
04706         if (changed)
04707           cout << "changed: ";
04708         else
04709           cout << "unchanged: ";
04710 
04711         cout << block->name() << endl;
04712         cout << "    From " << * source << " to " << * target << endl;
04713         def->print(cout);
04714 
04715         if ( ! def->points_to().empty())
04716           print_memoryblock_set("      points-to: ", def->points_to(), cout);
04717         cout << endl;
04718       }
04719     }
04720   }
04721   else {
04722 
04723     // Not computing pointers...
04724 
04725     if (is_new) {
04726 
04727       if (pointerOptions::Verbose) {
04728         cout << "ERROR in Self-assign: No new defs of " << block->name() <<
04729           " should be created at " << * target << endl;
04730         Procedures.print_call_stack(cout);
04731         cout << endl;
04732       }
04733       // Return the def so that the caller can access it...
04734 
04735       changes.insert(block);
04736     }
04737   }
04738 }
04739 
04740 
04741 void Pointers::call_operator(procedureInfo * caller,
04742                              stmtLocation * current,
04743                              operandNode * call,
04744                              operand_list & args,
04745                              memoryblock_set & defs,
04746                              memoryuse_set & uses,
04747                              memoryblock_set & changes,
04748                              pointerValue & result,
04749                              pointerValue & call_targets,
04750                              bool & never_returns)
04751 {
04752   // Evaluate the actual arguments, store the results in a list of
04753   // pointerValues.
04754 
04755   pointervalue_list actuals;
04756 
04757   for (operand_list_p p = args.begin();
04758        p != args.end();
04759        ++p)
04760     {
04761       operandNode * actual = * p;
04762       actuals.push_back(pointerValue());
04763       pointerValue & actual_results = actuals.back();
04764 
04765       // Evaluate the argument and save the results
04766 
04767       actual_results.is_a_use = true;
04768       eval(caller, current, actual, NULL,
04769            defs, uses, changes, actual_results, never_returns);
04770     }
04771 
04772   if (pointerOptions::Verbose) {
04773     cout << "  Arguments:" << endl;
04774     int count = 0;
04775     for (pointervalue_list_p p = actuals.begin();
04776          p != actuals.end();
04777          ++p)
04778       {
04779         cout << "    Arg " << count << " : ";
04780         if ((*p).is_address)
04781           cout << "pointer-to: ";
04782         print_memoryblock_set("", (*p).blocks, cout);
04783         count++;
04784       }
04785     cout << endl;
04786   }
04787 
04788   // -- Determine the target of the call
04789 
04790   determine_call_targets(caller, current, call, defs, uses, changes, call_targets);
04791 
04792   // -- Call the analyzer recursively. NOTE: all the special-case calls
04793   // (e.g., malloc and free) are handled in the procedure_call() method.
04794 
04795   if (call_targets.blocks.size() == 0) {
04796 
04797     if (pointerOptions::Verbose)
04798       cout << "WARNING: No call target at " << call->coord() << " -- " << * current << endl;
04799   }
04800   else {
04801 
04802     // -- NEW: call the analyzer for each target:
04803     /*
04804     if (call_targets.blocks.size() > 1) {
04805 
04806       cout << "WARNING: Multiple target call at " << * current << "(" << call->coord() << ")" << endl;
04807       for (memoryblock_set_p p = call_targets.blocks.begin();
04808            p != call_targets.blocks.end();
04809            ++p)
04810         {
04811           memoryBlock * current_target = *p;
04812           cout << "     + " << current_target->name() << endl;
04813         }
04814 
04815       return; // ROLLBACK
04816     }
04817 
04818     memoryBlock * current_target = * (call_targets.blocks.begin());
04819     procedure_call(caller, current,
04820                    call, call_targets, current_target, actuals,
04821                    defs, uses, changes, result, never_returns);
04822     */
04823 
04824     for (memoryblock_set_p p = call_targets.blocks.begin();
04825          p != call_targets.blocks.end();
04826          ++p)
04827       {
04828         memoryBlock * current_target = *p;
04829         bool local_never_returns = false;
04830 
04831         procedure_call(caller, current,
04832                        call, args, call_targets, current_target, actuals,
04833                        defs, uses, changes, result, local_never_returns);
04834 
04835         if (local_never_returns)
04836           never_returns = true;
04837       }
04838   }
04839 }
04840 
04841 void Pointers::determine_call_targets(procedureInfo * caller,
04842                                       stmtLocation * current,
04843                                       operandNode * call,
04844                                       memoryblock_set & defs,
04845                                       memoryuse_set & uses,
04846                                       memoryblock_set & changes,
04847                                       pointerValue & call_targets)
04848 {
04849   // Evaluate the name of the procedure being called (could be
04850   // pointer expression).
04851 
04852   pointerValue temp;
04853   bool exit_not_allowed_here;
04854   //TB: in case call->var() does not have decl (see eval case Id), need to this:
04855   if(! ((idNode*)call->var())->decl())
04856     temp.is_address = true;
04857   eval(caller, current, call, NULL,
04858        defs, uses, changes, temp, exit_not_allowed_here);
04859 
04860   // If necessary, dereference the pointers. This handles the
04861   // fact that if we have a pointer to a function we can call
04862   // it in two different ways:
04863 
04864   // (*f)(...)
04865   // f(...)
04866 
04867   // We distinguish this special case: if the call target is an
04868   // identifier that does not refer to a function, then
04869   // automatically dereference it.
04870 
04871   bool func_ptr = false;
04872 
04873   assert (((idNode*)call->var())->typ() == Id);
04874   if(call->star() || call->index() || !call->fields().empty())
04875     func_ptr = true;
04876   else {
04877     idNode * call_name = (idNode *) call->var();
04878     if (call_name->decl()->no_tdef_type()->typ() != Func)
04879       func_ptr = true;
04880   }
04881 
04882   // -- Use types for this:
04883 
04884   /* if ( call->no_tdef_type()->typ() == Ptr )
04885     deref = true; */
04886 
04887   /*if (pointerOptions::Verbose) {
04888     cout << "Call type: ";
04889     if (call->var()->type())
04890       print_walker::print(call->var()->no_tdef_type(), cout);
04891     else
04892       cout << "(no type)" << endl;
04893   }*/
04894 
04895   if (func_ptr) {
04896     temp.is_address = false; // TB: reset back
04897     // we already performed eval on the call operand to get temp. Do star only
04898     // if the result is not yet the functions.
04899     if(call->no_tdef_type()->typ() != Func)
04900       star_operator(caller, current, temp, defs, uses, changes, call_targets);
04901     else
04902       call_targets.copy_pointers_from(temp);
04903 
04904     if(_unification_based && pointerOptions::Unification) {
04905       // there could be more than one callee, but only one in call_targets.
04906       // to get more, need to access UnifyType's procs().
04907       assert(current && current->stmt()->typ() == ThreeAddr);
04908       int actuals = ((threeAddrNode*) current->stmt())->arg_list().size();
04909       memoryblock_set call_targets_blocks = call_targets.blocks;
04910       call_targets.blocks.clear();
04911       for (memoryblock_set_p c = call_targets_blocks.begin();
04912            c != call_targets_blocks.end(); c++) {
04913         string c_name = (*c)->name();
04914         if(c_name == "null" || c_name.find("__string_") < c_name.length())
04915           continue;
04916         UnifyType *one = (*c)->is_unify() ? (*c)->unifyType() : NULL;
04917 /*if(one) cout << *one << endl;
04918         assert(! one);*/
04919         if(! one) // else it is not representing a function.
04920           call_targets.blocks.insert(*c);
04921 
04922         /*if(one) {
04923           for(set<procNode*>::iterator p=one->procs().begin();
04924               p!=one->procs().end(); p++) {
04925             // check number of arguments.
04926             decl_list formals = ((funcNode*) (*p)->decl()->type())->args();
04927             int n = formals.size();
04928             bool contain_ellipsis = false;
04929             // if no arg, in formals there is still a decl with type=void.
04930             if(n==1 && formals.front()->type()->is_void()) n=0;
04931             else if(n>0 && (formals.back()->type()->is_ellipsis() ||
04932                             is_va_list(formals.back())))
04933               contain_ellipsis = true;
04934             if(!contain_ellipsis && n!=actuals ||
04935                contain_ellipsis && (actuals==0 || actuals+1<n))
04936               continue;
04937 
04938             UnifyType *proc_type = _unification_based->proctype(*p);
04939             assert(proc_type);
04940             if(!proc_type->block()) {
04941               // need to create block for procedure
04942               procLocation * cur_proc_loc = Location::procedure(current);
04943               procNode * cur_proc = cur_proc_loc->proc();
04944               _unification_based->createProcBlock(*p, Memory, cur_proc_loc);
04945             }
04946             call_targets.blocks.insert( proc_type->block() );
04947           }
04948         }*/
04949       }
04950     }
04951 
04952   } else { // !func_ptr
04953     if(! _unification_based)
04954       call_targets = temp;
04955     else {
04956       // the block in temp could represent the unify type of multiple
04957       // procesures, need to ensure we are using the right one.
04958       if(! temp.blocks.empty()) {
04959         assert(temp.blocks.size() == 1);
04960         UnifyType *one = temp.blocks.front()->is_unify() ?
04961                          temp.blocks.front()->unifyType() : NULL ;
04962         if(one) {
04963           for(set<procNode*>::iterator p=one->procs().begin();
04964               p!=one->procs().end(); p++)
04965             // must match name
04966             if((*p)->decl()->name() == ((idNode*)call->var())->name()) {
04967               UnifyType *proc_type = _unification_based->proctype(*p);
04968               assert(proc_type);
04969               if(!proc_type->block()) {
04970                 // need to create block for procedure
04971                 procLocation * cur_proc_loc = Location::procedure(current);
04972                 procNode * cur_proc = cur_proc_loc->proc();
04973                 _unification_based->createProcBlock(*p, Memory, cur_proc_loc);
04974               }
04975               call_targets.blocks.insert( proc_type->block() );
04976             }
04977           if(one->procs().empty()) call_targets = temp;
04978           assert(call_targets.blocks.size() <= 1);
04979         } else
04980           call_targets = temp;
04981       }
04982     }
04983   }
04984 
04985   if (pointerOptions::Verbose) {
04986     cout << "Call targets:" << endl;
04987     for (memoryblock_set_p p = call_targets.blocks.begin();
04988          p != call_targets.blocks.end();
04989          ++p) {
04990       cout << "  + " << (*p)->name() << endl;
04991     }
04992   }
04993 }
04994 
04995 void Pointers::generate_uses(procedureInfo * info,
04996                              Location * where,
04997                              memoryuse_set & uses,
04998                              pointerValue & pointer)
04999 {
05000   if ( ! pointer.is_address ) {
05001 
05002     for (memoryblock_set_p p = pointer.blocks.begin();
05003          p != pointer.blocks.end();
05004          ++p)
05005       {
05006         memoryBlock * block = (*p);
05007 
05008         // -- Find the memoryUse object for this location, creating one if
05009         // necessary.
05010 
05011         memoryUse * use = block->use_at(where);
05012 
05013         if ( ! block->is_return_value())
05014           uses.insert(use);
05015 
05016         // -- Context insensitive analysis: the reaching definition could
05017         // be in another context.
05018 
05019         if (computePointers) {
05020 
05021           // -- Look for a non-local reaching definition
05022 
05023           memoryDef * def = nearest_def_at(info, block, where);
05024           use->reaching_def(def);
05025         }
05026       }
05027   }
05028 }
05029 
05038 memoryDef * Pointers::nearest_def_at(procedureInfo * info,
05039                                      memoryBlock * block,
05040                                      Location * where)
05041 {
05042   if (pointerOptions::Verbose) {
05043     cout << " + Look for reaching def of " << block->name() << " at " << * where << endl;
05044     if (info)
05045       cout << "   (procedure is " << info->name() << ")" << endl;
05046     else
05047       cout << "   (no procedure)" << endl;
05048   }
05049 
05050   memoryDef * def = block->nearest_def_at(where);
05051   procedureInfo * current_info = 0;
05052   stmtLocation * current_callsite = 0;
05053 
05054   // -- Move up the call stack until we find a reaching def
05055 
05056   const procedurecall_stack & callstack = Procedures.callstack();
05057 
05058   procedurecall_stack_crp stack_p = callstack.rbegin();
05059 
05060   while ( ! def &&
05061           (stack_p != callstack.rend()))
05062     {
05063       current_callsite = (*stack_p).first;
05064       current_info = (*stack_p).second;
05065 
05066       // -- Short-circuit: don't both looking for a non-local def of a local
05067       // variable
05068 
05069       if (block->local_to() == current_info->proc())
05070         return 0;
05071 
05072       if (current_callsite &&
05073           current_info->is_context_insensitive()) {
05074 
05075         if (pointerOptions::Verbose)
05076           cout << "    --> Look for def dominating " << * current_callsite << endl;
05077 
05078         // -- See if there is a def that reaches the current callsite
05079 
05080         // -- OUT-DATED: YIKES: this was a major bug. Because of the
05081         // dominance rules for ancestors and descendants, it's critical
05082         // that we look for a dominator of the called procLocation, not the
05083         // callsite stmtLocation itself.
05084         
05085         def = block->nearest_def_at(current_callsite);
05086       }  
05087 
05088       // -- Move up the call stack
05089         
05090       stack_p++;
05091     }
05092 
05093   if (pointerOptions::Verbose)
05094     if (! def) {
05095       cout << "Pointers::nearest_def_at(" << block->name() << ", " << * where << ") -- Failed" << endl;
05096       block->print_def_use(cout);
05097     }
05098     
05099   return def;
05100 
05101 #if 0
05102 
05103     // ---- New version ----------------------------------------------
05104 
05105     // -- Simple case: look for a local def
05106 
05107     memoryDef * def = block->nearest_def_at(where);
05108 
05109     if (def)
05110       return def;
05111 
05112     // -- Already at the top of the callstack:
05113 
05114     if ( ! info)
05115       return 0;
05116 
05117     // -- We didn't find a local def: start moving up the call stack
05118 
05119     procedureInfo * current_callee = 0;
05120     stmtLocation * current_callsite = 0;
05121 
05122     // -- Move up the call stack to find the given procedure (could be
05123     // different from the bottom of the stack when called from
05124     // pass_one_external_input).
05125 
05126     const procedurecall_stack & callstack = Procedures.callstack();
05127 
05128     procedurecall_stack_crp stack_p = callstack.rbegin();
05129 
05130     while (stack_p != callstack.rend()) {
05131       current_callee = (*stack_p).second;
05132       
05133       if (current_callee == info)
05134         break;
05135 
05136       stack_p++;
05137     }
05138 
05139     // -- Now find the next context-insensitive procedure
05140 
05141     bool found = false;
05142 
05143     while (stack_p != callstack.rend()) {
05144 
05145       current_callsite = (*stack_p).first;
05146       current_callee = (*stack_p).second;
05147 
05148       // -- Short-circuit: if the block is local to a procedure and there is
05149       // no reaching def in that procedures, then there's no point looking
05150       // higher in the call stack.
05151 
05152       if (block->local_to() == current_callee->proc())
05153         return 0;
05154 
05155       // -- See if we are at the next CI-CS boundary. Checking the
05156       // current_callsite ensures that we won't try to go above main().
05157 
05158       if (current_callsite &&
05159           info->is_context_insensitive()) {
05160         found = true;
05161         break;
05162       }
05163 
05164       // -- Move up the call stack
05165 
05166       stack_p++;
05167     }
05168     
05169     if (found) {
05170 
05171       if (pointerOptions::Verbose)
05172         cout << "   -> No local def: try passing as external input to " << current_callee->name() 
05173              << " at " << * current_callsite << endl;
05174 
05175       // -- Found a CI-CS boundary: automatically add this block as an
05176       // external input
05177 
05178       if (computePointers)
05179         bool found_new_inputs = current_callee->add_external_input(block);
05180 
05181       // -- Get the parent
05182 
05183       stack_p++;
05184       procedureInfo * caller = (*stack_p).second;
05185 
05186       // -- Pass it as an external input right away. This will prevent us
05187       // from having to search up the tree the next time we encounter this
05188       // block.
05189 
05190       memoryblock_set ignore_changes;
05191       pass_one_external_input(current_callee, caller, current_callsite, block, ignore_changes);
05192 
05193       // -- The previous call should leave the current def (which is the
05194       // input def at the "input_location"), which is now the reaching def.
05195 
05196       def = block->current_def();
05197     }
05198 
05199     return def;
05200   }
05201 
05202 #endif
05203 }
05204 
05205 
05206 // ------------------------------------------------------------
05207 //  Conservative procedure call mechanics
05208 // ------------------------------------------------------------
05209 
05210 void Pointers::conservative_procedure_call(procedureInfo * info,
05211                                            stmtLocation * current,
05212                                            pointervalue_list & arguments,
05213                                            memoryblock_set & reachable,
05214                                            memoryblock_set & external_defs,
05215                                            memoryuse_set & external_uses,
05216                                            memoryblock_set & external_changes,
05217                                            pointerValue & return_val)
05218 {
05219   // -- Find all the memory blocks that could be reached throught the
05220   // formal parameters...
05221 
05222   memoryblock_list worklist;
05223 
05224   // -- Visit all the input arguments and build an initial worklist
05225 
05226   for (pointervalue_list_p p = arguments.begin();
05227        p != arguments.end();
05228        ++p)
05229     {
05230       pointerValue & pointer = (*p);
05231 
05232       for (memoryblock_set_p q = pointer.blocks.begin();
05233            q != pointer.blocks.end();
05234            ++q)
05235         {
05236           memoryBlock * arg = (*q);
05237 
05238           // -- Ignore the "null" node
05239 
05240           if (arg != Memory.null()) {
05241 
05242             // -- Put each block on the starting worklist
05243 
05244             worklist.push_back(arg);
05245 
05246             // -- For address arguments (e.g., "&x"), we can already assume
05247             // that the object is reachable.
05248 
05249             if (pointer.is_address)
05250               reachable.insert(arg);
05251           }
05252         }
05253     }
05254 
05255   // -- Generate the reachable blocks
05256 
05257   reachable_blocks(current, worklist, reachable);
05258 
05259   // -- Create uses and defs for these objects. We'll do this by setting up
05260   // an assignment that looks like this: for all variables V, V = &(any
05261   // other object).
05262 
05263   // BAIL OUT: This approach is too inefficient
05264 
05265   pointerValue left;
05266   pointerValue right;
05267 
05268   // -- Make pointerValue objects
05269 
05270   // left.blocks = reachable;
05271   right.blocks = reachable;
05272 
05273   // -- Generate uses
05274 
05275   generate_uses(info, current, external_uses, right);
05276 
05277   /* Don't do it this way
05278   // -- Now perform the assignment
05279   right.is_address = true;
05280   assignment_operator(current, left, right, external_changes);
05281   */
05282 
05283   // -- Just generate defs:
05284 
05285   for (memoryblock_set_p p = reachable.begin();
05286        p != reachable.end();
05287        ++p)
05288     {
05289       memoryBlock * block = *p;
05290 
05291       // -- Are we allowed to modify this object?
05292 
05293       if ( ! block->write_protected()) {
05294 
05295         bool is_new;
05296         memoryDef * def = block->def_at(current, is_new);
05297 
05298 #ifdef COLLECT_DEFS
05299         external_defs.insert(block);
05300 #endif
05301 
05302         if (is_new) {
05303           external_changes.insert(block);
05304         }
05305 
05306         // --- Ug: if it was previously a pointer, then it could point to
05307         // anything:
05308 
05309         memoryDef * reaching_def = block->current_use()->reaching_def();
05310         if (reaching_def &&
05311             ! reaching_def->points_to().empty()) {
05312           def->add_pointers(reaching_def->points_to());
05313         }
05314       }
05315     }
05316 
05317   if (pointerOptions::Verbose)
05318     print_memoryblock_def_set("  Potentially reachable:", reachable, cout);
05319 }
05320 
05326 void Pointers::reachable_blocks(Location * where,
05327                                 memoryblock_list & worklist,
05328                                 memoryblock_set & already_seen)
05329 {
05330   while ( ! worklist.empty()) {
05331 
05332     // -- Remove the first element from the worklist..
05333 
05334     memoryBlock * mb = worklist.front();
05335     worklist.pop_front();
05336 
05337     // -- Add all the immediately reachable blocks (that we haven't seen yet)
05338 
05339     mb->reachable_blocks(where, false, worklist, already_seen, Memory.null());
05340   }
05341 }
05342 
05343 // ------------------------------------------------------------
05344 // Manage the Heap
05345 // ------------------------------------------------------------
05346 
05347 memoryBlock * Pointers::at_allocation(const string & name,
05348                                       procedureInfo * info,
05349                                       stmtLocation * current,
05350                                       stmtNode * allocation_stmt,
05351                                       declNode * decl,
05352                                       memoryblock_set & defs,
05353                                       memoryuse_set & uses,
05354                                       memoryblock_set & changes,
05355                                       pointerValue & result)
05356 {
05357   bool changed;
05358   declNode * the_decl = decl;
05359   bool from_heap_map = false;
05360   string fullname = name;
05361 
05362   if (decl == 0) {
05363 
05364     // -- Lookup or create a declNode for this site
05365 
05366     from_heap_map = true;
05367 
05368     stmtNode * stmt = current->stmt();
05369     heap_map_p p = HeapMap.find(stmt);
05370     if (p == HeapMap.end()) {
05371 
05372       // -- Not there, create it.
05373 
05374       // -- Add a unique number onto the name
05375 
05376       char buf[50];
05377 
05378       sprintf(buf, "_#%d", Memory.counter());
05379 
05380       fullname = name + buf;
05381 
05382       // -- Create a synthetic declaration
05383 
05384       the_decl = new declNode(fullname.c_str(),
05385                               declNode::NONE,
05386                               (typeNode *)0,
05387                               (exprNode *)0,
05388                               (exprNode *)0);
05389 
05390       // -- Store it for future use
05391 
05392       HeapMap[stmt] = the_decl;
05393     }
05394     else {
05395 
05396       // -- Found it
05397 
05398       the_decl = (*p).second;
05399     }
05400   }
05401 
05402   // -- Look up the memoryBlock for this allocation site based on the
05403   // location and the given declaration. Ignore the context for regular
05404   // mallocs, if the flag indicates to do so. VERY IMPORTANT: we need to
05405   // pass from_heap_map = true which tells the memory model that this
05406   // declNode is synthetic, otherwise the adaptive algorithm can't set heap
05407   // objects flow sensitive.
05408 
05409   memoryBlock * block = Memory.lookup_heap_object(fullname, current, allocation_stmt,
05410                                                   the_decl, from_heap_map);
05411 
05412   if (pointerOptions::Verbose)
05413     cout << "  - At allocation: " << fullname << endl;
05414 
05415   // -- If the block is flow-sensitive and we are actually computing the
05416   // pointer info...
05417 
05418   if (computePointers) {  // && block->is_flow_sensitive()) {
05419 
05420     // -- Perform multiplicity analysis: this information is associated
05421     // with a separate allocation object.
05422 
05423     memoryBlock * alloc_object = block->get_allocation_object(Memory);
05424     if (alloc_object->is_flow_sensitive()) {
05425     
05426       // -- Looking up its nearest reaching definition of the alloc object
05427 
05428       memoryDef * previous_alloc_def = nearest_def_at(info, alloc_object, current);
05429 
05430       // -- Compute the new multiplicity
05431 
05432       Multiplicity new_multiplicity;
05433 
05434       new_multiplicity = alloc_object->at_allocation(current,
05435                                                      previous_alloc_def,
05436                                                      defs, uses, changes);
05437     }
05438   }
05439 
05440   // -- Return the allocated block
05441 
05442   result.blocks.insert(block);  
05443   result.is_address = true;
05444 
05445   return block;
05446 }
05447 
05448 void Pointers::at_deallocation(procedureInfo * info,
05449                                Location * current,
05450                                pointerValue & to_deallocate,
05451                                memoryblock_set & defs,
05452                                memoryuse_set & uses,
05453                                memoryblock_set & changes)
05454 {
05455   // -- For each block that need to be deallocated...
05456 
05457   for (memoryblock_set_p p = to_deallocate.blocks.begin();
05458        p != to_deallocate.blocks.end();
05459        ++p)
05460     {
05461       memoryBlock * block = *p;
05462       bool changed = false;
05463 
05464       if (block->write_protected()) {
05465 
05466         if (pointerOptions::Verbose)
05467           cout << "  Skip deallocation of write-protected object: " << block->name() << endl;
05468       }
05469       else {
05470         
05471         // -- Perform multiplicity analysis: check for a reaching definition of this
05472         // object, and decrease the multiplicity, if we can.
05473 
05474         // -- If we are actually computing the pointer info...
05475 
05476         if (computePointers) {  // && block->is_flow_sensitive()) {
05477 
05478           // -- Perform multiplicity analysis: this information is associated
05479           // with a separate allocation object.
05480 
05481           memoryBlock * alloc_object = block->get_allocation_object(Memory);
05482           if (alloc_object->is_flow_sensitive()) {
05483 
05484             // -- Looking up its nearest reaching definition of the alloc object
05485 
05486             memoryDef * previous_alloc_def = nearest_def_at(info, alloc_object, current);
05487 
05488             // -- Compute the new multiplicity
05489 
05490             Multiplicity new_multiplicity;
05491             
05492             new_multiplicity = alloc_object->at_deallocation(current,
05493                                                              previous_alloc_def,
05494                                                              defs, uses, changes);
05495           }
05496         }
05497       }
05498     }
05499 }
05500 
05501 Multiplicity Pointers::current_multiplicity(procedureInfo * info,
05502                                             Location * current,
05503                                             memoryBlock * block_in,
05504                                             memoryuse_set & uses)
05505 {
05506   Multiplicity multiplicity = Unallocated;
05507 
05508   // -- Get the top-level block
05509 
05510   memoryBlock * block = block_in;
05511   while (block->container()) {
05512     if(_unification_based && block == block->container()) break;
05513     block = block->container();
05514   }
05515 
05516   // -- Perform multiplicity analysis
05517 
05518   if (block->is_indexed())
05519     multiplicity = Bounded;
05520   else
05521     if (block->is_heap_object()) {
05522 
05523       // -- Multiplicity analysis only applies to flow sensitive heap
05524       // objects, and only when this option is turned on.
05525 
05526       if (// block->is_flow_sensitive() &&
05527           _use_multiplicity)
05528         {
05529           // -- Get the special allocation object
05530 
05531           memoryBlock * alloc_object = block->get_allocation_object(Memory);
05532           if (alloc_object->is_flow_sensitive()) {
05533 
05534             // -- Find it's reaching def
05535 
05536             memoryDef * alloc_def = nearest_def_at(info, alloc_object, current);
05537 
05538             // -- Reading the multiplicity is a use of the alloc object
05539 
05540             memoryUse * use = alloc_object->use_at(current);
05541             use->reaching_def(alloc_def);
05542             uses.insert(use);
05543         
05544             // -- Get the current multiplicity value
05545 
05546             if (alloc_def)
05547               multiplicity = alloc_def->multiplicity();
05548           }
05549           else {
05550 
05551             // -- Multiplicity not flow sensitive
05552 
05553             multiplicity = Unbounded;
05554           }
05555         }
05556       else {
05557 
05558         // -- Flow insensitive block, or multiplicity is turned off:
05559         // default to Unbounded
05560 
05561         multiplicity = Unbounded;
05562       }
05563     }
05564     else {
05565 
05566       // -- Regular variables are always "single"
05567 
05568       multiplicity = Single;
05569     }
05570 
05571   return multiplicity;
05572 }
05573 
05574 
05575 bool Pointers::is_allocation(pointerValue & call_targets)
05576 {
05577   if (call_targets.blocks.size() == 1) {
05578     memoryBlock * call = * call_targets.blocks.begin();
05579     declNode * decl = call->decl();
05580     if ((decl->name() == string("malloc")) ||
05581         (decl->name() == string("calloc")))
05582       return true;
05583   }
05584 
05585   return false;
05586 }
05587 
05588 bool Pointers::is_deallocation(pointerValue & call_targets)
05589 {
05590   if (call_targets.blocks.size() == 1) {
05591     memoryBlock * call = * call_targets.blocks.begin();
05592     declNode * decl = call->decl();
05593     if ((decl->name() == string("free")) ||
05594         (decl->name() == string("cfree")))
05595       return true;
05596   }
05597 
05598   return false;
05599 }
05600 
05601 bool Pointers::is_reallocation(pointerValue & call_targets)
05602 {
05603   if (call_targets.blocks.size() == 1) {
05604     memoryBlock * call = * call_targets.blocks.begin();
05605     declNode * decl = call->decl();
05606     if (decl->name() == string("realloc"))
05607       return true;
05608   }
05609 
05610   return false;
05611 }
05612 
05621 void Pointers::mark_as_indexed(memoryblock_set & blocks)
05622 {
05623   for (memoryblock_set_p p = blocks.begin();
05624        p != blocks.end();
05625        ++p)
05626     {
05627       memoryBlock * block = *p;
05628       block->set_indexed();
05629     }
05630 }
05631 
05632 // ------------------------------------------------------------
05633 // Misc
05634 // ------------------------------------------------------------
05635 
05636 // -- Print some statistics
05637 
05638 void Pointers::stats(ostream & out)
05639 {
05640   out << "Pointer analysis:" << endl;
05641   out << "  Number of procedure-level passes: " << _procedureCount << endl;
05642 
05643   Memory.stats(out);
05644 
05645   cout << "Number of pointerValue objects: " << pointerValue::count << endl;
05646 
05647   out << "Unknown procedures:" << endl;
05648   for (string_set_p p = _unknown_procedures.begin();
05649        p != _unknown_procedures.end();
05650        ++p)
05651     out << "  " << (*p) << endl;
05652 
05653   Procedures.stats(out);
05654 }
05655 
05656 void Pointers::uses_and_defs()
05657 {
05658   Memory.print(cout);
05659 }
05660 
05661 void Pointers::print_memoryblock_set(const string & label,
05662                                      const memoryblock_set & the_set,
05663                                      ostream & o)
05664 {
05665   cout << label;
05666   for (memoryblock_set_cp mbp = the_set.begin();
05667        mbp != the_set.end();
05668        ++mbp)
05669     {
05670       if (mbp != the_set.begin())
05671         cout << " , ";
05672       cout << (*mbp)->name();
05673     }
05674   cout << endl;
05675 }
05676 
05677 void Pointers::print_memorydef_set(const string & label,
05678                                    const memorydef_set & the_set,
05679                                    ostream & o)
05680 {
05681   cout << label << endl;
05682   for (memorydef_set_cp p = the_set.begin();
05683        p != the_set.end();
05684        ++p)
05685     {
05686       memoryBlock * owner = (*p)->owner();
05687       cout << "        " << owner->name() << " (def at " << * (*p)->where() << ")" << endl;
05688     }
05689   cout << endl;
05690 }
05691 
05692 void Pointers::print_memoryblock_def_set(const string & label,
05693                                          const memoryblock_set & the_set,
05694                                          ostream & o)
05695 {
05696   cout << label << endl;
05697   for (memoryblock_set_cp p = the_set.begin();
05698        p != the_set.end();
05699        ++p)
05700     {
05701       memoryBlock * owner = (*p);
05702       memoryDef * def = owner->current_def();
05703 
05704       if (def)
05705         cout << "        " << owner->name() << " (def at " << * def->where() << ")" << endl;
05706       else
05707         cout << "        " << owner->name() << " (Non-local def)" << endl;      
05708     }
05709   cout << endl;
05710 }
05711 
05712 // ----------------------------------------------------------------------
05713 //   Public methods
05714 // ----------------------------------------------------------------------
05715 
05716 // -- Lookup a procedure
05717 
05718 procedureInfo * Pointers::lookup_procedure(procNode * proc)
05719 {
05720   return Procedures.lookup(proc);
05721 }
05722 
05723 
05724 bool Pointers::is_pointer_expression(operandNode * operand)
05725 {
05726   if(operand->star() || operand->addr() || !operand->fields().empty())
05727     return true;
05728   return false;
05729 }
05730 
05731 // ----------------------------------------------------------------------
05732 //  Exit/abort calls
05733 // ----------------------------------------------------------------------
05734 
05735 bool Pointers::is_exit(pointerValue & call_targets)
05736 {
05737   if (call_targets.blocks.size() == 1) {
05738     memoryBlock * call = * call_targets.blocks.begin();
05739     declNode * decl = call->decl();
05740     if ((decl->name() == string("exit")) ||
05741         (decl->name() == string("_exit")) ||
05742         (decl->name() == string("abort")))
05743       return true;
05744   }
05745 
05746   return false;
05747 }
05748 
05749 
05750 // ----------------------------------------------------------------------
05751 //  Var args
05752 // ----------------------------------------------------------------------
05753 
05754 void Pointers::setup_va_list_variables(procedureInfo * info,
05755                                        procLocation * callee_path, 
05756                                        stmtLocation * parameter_callsite,
05757                                        procNode * callee,
05758                                        memoryBlock * ellipsis)
05759 {
05760   memoryblock_set defs;
05761   memoryuse_set uses;
05762   memoryblock_set changes;
05763   pointerValue rhs(ellipsis);
05764   rhs.is_address = true;
05765 
05766   decl_list & local_vars = callee->body()->decls();
05767   for (decl_list_p lvp = local_vars.begin();
05768        lvp != local_vars.end();
05769        ++lvp)
05770     {
05771       declNode * cur_lv = *lvp;
05772 
05773       // -- Look for variables whose type is typedef va_list
05774 
05775       if (is_va_list(cur_lv)) {
05776 
05777         // -- Found one, perform the assignment like below
05778 
05779         memoryBlock * left = Memory.lookup_variable(callee_path, cur_lv, callee);
05780         pointerValue lhs(left);
05781 
05782         assignment_operator(info, callee_path, parameter_callsite, lhs, rhs, defs, uses, changes);
05783 
05784         // -- Here's a trick: we'll prevent these pointers from
05785         // being overwritten by marking the va_list variable with
05786         // the "numerous" flag.
05787           
05788         left->set_indexed();
05789 
05790         // -- Constant propagation
05791 
05792         _constants.at_parameter_pass(callee_path, lhs, rhs, changes);
05793 
05794         // -- User-defined analysis
05795         
05796         if (Problem)
05797           Problem->at_parameter_pass(callee_path, parameter_callsite, lhs, rhs, changes);
05798       }
05799     }
05800 }
05801 
05802 // Right now, this stuff is Linux-specific
05803 
05804 bool Pointers::is_va_arg(pointerValue & call_targets)
05805 {
05806   if (call_targets.blocks.size() == 1) {
05807     memoryBlock * call = * call_targets.blocks.begin();
05808     declNode * decl = call->decl();
05809     if (decl->name() == "__builtin_va_arg")
05810       return true;
05811   }
05812 
05813   return false;
05814 }
05815 
05816 bool Pointers::is_va_start(pointerValue & call_targets)
05817 {
05818   if (call_targets.blocks.size() == 1) {
05819     memoryBlock * call = * call_targets.blocks.begin();
05820     declNode * decl = call->decl();
05821     if (decl->name() == "__builtin_next_arg")
05822       return true;
05823   }
05824 
05825   return false;
05826 }
05827 
05828 bool Pointers::is_va_end(pointerValue & call_targets)
05829 {
05830   return false;
05831 }
05832 
05833 bool Pointers::is_va_list(declNode * decl)
05834 {
05835   // -- Look for variables whose type is typedef va_list
05836 
05837   if (decl->type() && (decl->type()->typ() == Tdef)) {
05838         tdefNode * tdef = (tdefNode *) decl->type();
05839         if (tdef->name() == "va_list")
05840           return true;
05841         if (tdef->name() == "__builtin_va_alist_t")
05842           return true;
05843         if (tdef->name() == "__gnuc_va_list")
05844           return true;
05845   }
05846 
05847   return false;
05848 }
05849 
05850 bool Pointers::is_va_list(exprNode * expr)
05851 {
05852   if (expr->typ() == Id) {
05853     idNode * id = (idNode *) expr;
05854     if (id->decl())
05855       return is_va_list(id->decl());
05856   }
05857 
05858   return false;
05859 }
05860 
05861 void Pointers::progress_meter(procedureInfo * info, bool skipped)
05862 {
05863   if (skipped)
05864     _skipCount++;
05865 
05866   _procedureCount++;
05867 
05868   bool show_now = false;
05869 
05870   if (_procedureCount < 50000)
05871     show_now = ((_procedureCount % 5000) == 0);
05872   else
05873     show_now = ((_procedureCount % 10000) == 0);
05874 
05875   if (_show_progress && show_now) {
05876     if (info->is_context_insensitive())
05877       cout << "Progress (I): ";
05878     else
05879       cout << "Progress (S): ";
05880 
05881     cout << _procedureCount << "/" << _skipCount << " at ";
05882     Procedures.progress_meter(cout);
05883     cout << endl;
05884   }
05885 }
05886 
05887 void Pointers::show_accuracy()
05888 {
05889   double defs = compute_accuracy(_def_accuracy);
05890 
05891   cout << "STAT-accuracy-pointers-defs " << defs << endl;
05892 
05893   double star = compute_accuracy(_star_accuracy);
05894 
05895   cout << "STAT-accuracy-pointers-star " << star << endl;
05896   
05897   // -- Clear information
05898 
05899   _def_accuracy.clear();
05900   _star_accuracy.clear();
05901 }
05902 
05903 double Pointers::compute_accuracy(accuracy_map & accuracy_data)
05904 {
05905   // -- Compute accuracy
05906 
05907   typedef map< stmtNode *, count_accuracy_pair > stmt_accuracy_map;
05908   typedef stmt_accuracy_map::iterator stmt_accuracy_map_p;
05909 
05910   stmt_accuracy_map by_statement;
05911 
05912   for (accuracy_map_p p = accuracy_data.begin();
05913        p != accuracy_data.end();
05914        ++p)
05915     {
05916       stmtLocation * where = (*p).first;
05917       count_accuracy_pair & cap = (*p).second;
05918 
05919       // -- Count the number of ways to reach this location.
05920 
05921       procLocation * cur = Location::procedure(where);
05922 
05923       // -- Look up the procedure
05924 
05925       procedureInfo * info = lookup_procedure(cur->proc());
05926 
05927       // -- Now get the context count
05928 
05929       int count = info->count_calling_contexts();
05930 
05931       // -- Construct accuracy information that takes into account the
05932       // number of contexts.
05933 
05934       count_accuracy_pair new_cap;
05935 
05936       new_cap.first  = cap.first * count;
05937       new_cap.second = cap.second * ((double)count);
05938 
05939       // -- Get the statement itself
05940 
05941       stmtNode * stmt = where->stmt();
05942 
05943       // -- Add the values in to the total
05944 
05945       stmt_accuracy_map_p w = by_statement.find(stmt);
05946       if (w == by_statement.end())
05947         by_statement[stmt] = new_cap;
05948       else {
05949         count_accuracy_pair & existing_cap = (*w).second;
05950 
05951         existing_cap.first  += new_cap.first;
05952         existing_cap.second += new_cap.second;
05953       }
05954     }
05955 
05956   // -- Print out the results, according to the call site and compute
05957   // aggregate accuracy
05958 
05959   double total = 0.0;
05960   int count = 0;
05961 
05962   for (stmt_accuracy_map_p p = by_statement.begin();
05963          p != by_statement.end();
05964        ++p)
05965     {
05966       stmtNode * stmt = (*p).first;
05967       count_accuracy_pair & cap = (*p).second;
05968 
05969       double local_accuracy = (cap.second) / ((double) cap.first);
05970 
05971       // cout << "ACCURACY: Pointers at " << stmt->coord() << " = " << local_accuracy << endl;
05972 
05973       count++;
05974       total += local_accuracy;
05975     }
05976 
05977   return (total / ((double)count));
05978 }

Generated on August 27, 2003
Back to the C-Breeze home page