Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

/ray/src/vm/input/linker.cc

Go to the documentation of this file.
00001 /*
00002  * vm/input/linker.cc
00003  * 
00004  * VM (assembler) linker. 
00005  * 
00006  * Copyright (c) 2004 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 
00007  * 
00008  * This file may be distributed and/or modified under the terms of the 
00009  * GNU General Public License version 2 as published by the Free Software 
00010  * Foundation. (See COPYING.GPL for details.)
00011  * 
00012  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00013  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00014  * 
00015  */
00016 
00017 #include "linker.h"
00018 #include <lib/message/message.h>
00019 #include "classinfo.h"
00020 #include <lib/tl/sort.h>
00021 #include <lib/tl/binsearch.h>
00022 #include <lib/lex/strtreedump.h>
00023 
00024 
00025 namespace VM
00026 {
00027 
00028 NamespaceInfo::SymbolEntryE *VMLinker::SymbolProvideMap::AddNode(
00029     NamespaceInfo::SymbolEntryE *s)
00030 {
00031     NamespaceInfo::SymbolEntryE *known=NULL;
00032     if(map.store(s,/*allow_update=*/0,/*oldval=*/&known))
00033     {
00034         Assert(known);
00035         return(known);
00036     }
00037     return(NULL);
00038 }
00039 
00040 //------------------------------------------------------------------------------
00041 
00042 // Used for binary search by offset in member vars. 
00043 struct MemberVarEntryOffsetOperators
00044 {
00045     static inline bool lt(ClassInfo::MemberVarEntry const &a,Offset const &b)
00046         {  return(a.off<b);   }
00047     static inline bool eq(ClassInfo::MemberVarEntry const &a,Offset const &b)
00048         {  return(a.off==b);  }
00049     
00050     template<typename I>static inline const ClassInfo::MemberVarEntry &idx(
00051         const ClassInfo::MemberVarEntry *array,I i)
00052         {  return(array[i]);  }
00053 };
00054 
00055 
00056 SymRef VMLinker::_SQPush(NamespaceInfo::SymbolEntryE *se,
00057     NamespaceInfo::SymbolEntryB **update_se,LSymbol::SFlag sflag)
00058 {
00059     if(se->symref<0)
00060     {
00061         // Internal symbols may not be pushed. 
00062         Assert(0);
00063         Assert(!update_se);
00064         return(se->symref);
00065     }
00066     
00067     SymRef symref;
00068     if(sflag==LSymbol::SStart)
00069     {  symref=0;  }
00070     else
00071     {  symref=master_SymRef_cnt;  }
00072     LSymbol symb(se,symref,update_se,sflag);
00073     
00074     // Make sure we do not add the symbol twice. 
00075     LSymbol known;
00076     int rv=sq.store(symb,/*allow_update=*/0,/*oldval=*/&known);
00077     if(rv)  // already in the queue
00078     {
00079         Assert(known.se);
00080         return(known.symref);
00081     }
00082     
00083     Warning("added %s ($%d) to symbol queue",se->CompleteName().str(),
00084         (int)symref);
00085     
00086     if(symref==master_SymRef_cnt)
00087     {  ++master_SymRef_cnt;  }
00088     
00089     return(symb.symref);
00090 }
00091 
00092 SymRef VMLinker::_SQQuery(NamespaceInfo::SymbolEntryE *se)
00093 {
00094     Assert(se->symref>=0);
00095     
00096     LSymbol key(se,0,NULL,LSymbol::SNone);
00097     LSymbol *known=sq.search(key);
00098     if(known)
00099     {  return(known->symref);  }
00100     else
00101     {  return(master_SymRef_cnt++);  }
00102 }
00103 
00104 void VMLinker::_SQPop(/*LSymbol &ls*/)
00105 {
00106     /*int rv=sq.RemoveSmallest(&ls);
00107     return(rv==0);*/
00108     sq.RemoveSmallest(NULL);
00109 }
00110 
00111 bool VMLinker::_SQPeek(LSymbol &ls)
00112 {
00113     LSymbol *s=sq.GetSmallest();
00114     if(s) ls=*s;
00115     return(s);
00116 }
00117 
00118 
00119 VMLinker::FileNode *VMLinker::_GetDefinitionFile(NamespaceInfo *from_here)
00120 {
00121     FileNode *fn=NULL;
00122     
00123     // First, we need to find the file this NamespaceInfo is from. 
00124     // FIXME: We could avoid this lookup by using explicit FileNode pointers 
00125     //        in the NamespaceInfo. 
00126     // Therefore, first traverse to the root and then search the root 
00127     // in the file list. 
00128     NamespaceInfo *walker=from_here;
00129     for(; walker->parent; walker=walker->parent);
00130     
00131     for(FileNode *fni=flist.first(); fni; fni=fni->next)
00132     {
00133         if(fni->f->nspc_root==walker)
00134         {  fn=fni;  break;  }
00135     }
00136     
00137     // We MUST have found the namespace info somewhere. In case this assert 
00138     // fails, *from_here was probably from the master tree which is illegal. 
00139     Assert(fn);
00140     
00141     return(fn);
00142 }
00143 
00144 
00145 NamespaceInfo *VMLinker::_MergeNamespaceInfo_Recursive(
00146     NamespaceInfo **head_list,uint nheads)
00147 {
00148     if(!nheads)  return(NULL);
00149     
00150     // NOTE: Cannot use CompleteName() and the like on the elements of 
00151     //       the tree being built up (i.e. "dest") as the tree is built 
00152     //       bottom-up and hence cannot be traversed to the root yet. 
00153     //       Hence, always use CompleteName() on the source nodes in 
00154     //       head_list[]. 
00155     
00156     //Warning("MNIR: nheads=%u:",nheads);
00157     //for(uint i=0; i<nheads; i++)
00158     //{  Warning("  %s",head_list[i]->CompleteName().str());  }
00159     
00160     // Join all elements from the head_list. 
00161     NamespaceInfo *dest=NULL;
00162     if(nheads==1)
00163     {
00164         // Trivial case. "Merge" all information from one single node. 
00165         // This is an optimized version of the below code. 
00166         switch(head_list[0]->nstype)
00167         {
00168             case NamespaceInfo::NSNamespace:
00169             {
00170                 NamespaceInfo *s=head_list[0];
00171                 dest = new NamespaceInfo(/*name=*/s->name,
00172                     /*parent=*/NULL/*for now*/);
00173                 // Symbol information is not copied as it is per-file 
00174                 // "map/need" information. 
00175                 //dest->symbol is NOT s->symbol;
00176             }   break;
00177             case NamespaceInfo::NSClass:
00178             {
00179                 ClassInfo *s = static_cast<ClassInfo*>(head_list[0]);
00180                 ClassInfo *d = new ClassInfo(/*name=*/s->name,
00181                     /*TypeID=*/master_TypeID_cnt++,
00182                     /*parent=*/NULL/*for now*/);
00183                 // Symbol information is not copied as it is per-file 
00184                 // "map/need" information. 
00185                 //d->symbol is NOT s->symbol;
00186                 d->size=s->size;
00187                 d->nvirtuals=s->nvirtuals;
00188                 // base and vtable contain per-file data and are not yet 
00189                 // copied but resolved lateron when the namespace hierarchy 
00190                 // is built. 
00191                 d->membvar=s->membvar;  // copy content
00192                 dest=d;
00193             }   break;
00194             default: Assert(0);
00195         }
00196         head_list[0]->linked=dest;
00197     }
00198     else
00199     {
00200         NamespaceInfo::NSType dest_type=head_list[0]->nstype;
00201         for(uint i=1 /*<--correct*/; i<nheads; i++)
00202         {
00203             if(dest_type==head_list[i]->nstype)  continue;
00204             Error(head_list[i]->asm_loc,
00205                 "%s \"%s\" redefined as %s",
00206                 NamespaceInfo::NSType2String(dest_type),
00207                 head_list[0]->CompleteName().str(),
00208                 NamespaceInfo::NSType2String(head_list[i]->nstype));
00209             Error(head_list[0]->asm_loc,
00210                 "  this is the location of the first definition");
00211             ++n_errors;
00212             // Use simplest possible type for now. 
00213             dest_type=NamespaceInfo::NSNamespace;
00214             break;
00215         }
00216         
00217         switch(dest_type)
00218         {
00219             case NamespaceInfo::NSNamespace:
00220             {
00221                 dest = new NamespaceInfo(/*name=*/head_list[0]->name,
00222                     /*parent=*/NULL/*for now*/);
00223                 // Symbol information is not copied as it is per-file 
00224                 // "map/need" information. 
00225                 // Hence, there is nothing left to be dealt with yet, 
00226                 // for namespace info. 
00227                 //for(uint i= >1?<; i<nheads; i++)
00228                 //{
00229                 //  NamespaceInfo *s=head_list[i];
00230                 //}
00231             }   break;
00232             case NamespaceInfo::NSClass:
00233             {
00234                 ClassInfo *d = new ClassInfo(/*name=*/head_list[0]->name,
00235                     /*TypeID=*/master_TypeID_cnt++,
00236                     /*parent=*/NULL/*for now*/);
00237                 
00238                 // Add a new entry to the map. This is not needed for linking 
00239                 // but we should probably have the info in the output file. 
00240                 if(!cfg.abandon_out_maps)
00241                 {
00242                     ClassInfo _unused_ *known=out->tid2classinfo.AddNode(d);
00243                     Assert(!known);
00244                 }
00245                 
00246                 dest=d;
00247                 // Only the cotent which is not dependent on the file 
00248                 // is merged here. Hence, no sybols, base, vtable. 
00249                 // For the member vars, we use the one with the most entries 
00250                 // as master and check all the others against it. We could 
00251                 // do more fancy here but this is not (yet) needed. 
00252                 NonResizeableArray<ClassInfo::MemberVarEntry,uint32> 
00253                     *most_members=NULL;
00254                 for(uint i=0; i<nheads; i++)
00255                 {
00256                     Assert(head_list[i]->nstype==NamespaceInfo::NSClass);
00257                     ClassInfo *s = static_cast<ClassInfo*>(head_list[i]);
00258                     
00259                     if(!i)  // First run. 
00260                     {
00261                         d->size=s->size;
00262                         d->nvirtuals=s->nvirtuals;
00263                         most_members=&s->membvar;
00264                     }
00265                     else
00266                     {
00267                         if(most_members->n()<s->membvar.n())
00268                         {  most_members=&s->membvar;  }
00269                         
00270                         const char *what=NULL;
00271                         
00272                         if(d->size!=s->size)  what="size";
00273                         else if(d->nvirtuals!=s->nvirtuals)  what="nvirtuals";
00274                         
00275                         if(what)
00276                         {
00277                             Error(s->asm_loc,
00278                                 "mismatch of %s property in %s \"%s\"",
00279                                 what,
00280                                 NamespaceInfo::NSType2String(dest_type),
00281                                 s->CompleteName().str());
00282                             Error(head_list[0]->asm_loc,
00283                                 "  this is the location of the first "
00284                                 "occurance");
00285                             ++n_errors;
00286                             break;  // Stop complaining now. 
00287                         }
00288                     }
00289                 }
00290                 
00291                 // Now the member vars: 
00292                 d->membvar=*most_members;  // copy content
00293                 for(uint i=0; i<nheads; i++)
00294                 {
00295                     Assert(head_list[i]->nstype==NamespaceInfo::NSClass);
00296                     ClassInfo *s = static_cast<ClassInfo*>(head_list[i]);
00297                     
00298                     // Skip master: Checking it against itself would just 
00299                     // be a waste of time. 
00300                     if(&s->membvar==most_members)  continue;
00301                     
00302                     // Note that the membvars are sorted by offset (checked 
00303                     // by the parser) so that we can efficiently search. 
00304                     // However, in case both have the same number of entries, 
00305                     // using the same index is good guess which will normally 
00306                     // hit. 
00307                     bool guess_first = d->membvar.n()==s->membvar.n();
00308                     // We could do some better than just reporting error with 
00309                     // number of mismatches but OTOH, this should not happen 
00310                     // anyways. 
00311                     uint n_mismatches=0;
00312                     uint n_missing=0;
00313                     for(uint j=0,jend=s->membvar.n(); j<jend; j++)
00314                     { // LOOP: SRC
00315                         ClassInfo::MemberVarEntry *se=&s->membvar[j];
00316                         ClassInfo::MemberVarEntry *de=NULL;
00317                         if(guess_first && se->off==d->membvar[j].off)
00318                         {  de=&d->membvar[j];  }
00319                         else
00320                         {
00321                             ssize_t idx=TLBinarySearch(
00322                                 d->membvar.ptr(),d->membvar.n(),
00323                                 se->off,MemberVarEntryOffsetOperators());
00324                             if(idx>=0)  de=&d->membvar[idx];
00325                         }
00326                         
00327                         if(!de)
00328                         {
00329                             // Entry in source but not in dest (master). 
00330                             ++n_missing;
00331                             // Pointer types MUST be specified; simple 
00332                             // ones can be ignored if told so. 
00333                             if(se->vtype.IsPointerType() || 
00334                                 !cfg.ignore_simple_type_missing)
00335                             {  ++n_mismatches;  }
00336                             continue;
00337                         }
00338                         if(de->vtype!=se->vtype)  ++n_mismatches;
00339                         if(se->name)
00340                         {
00341                             if(!de->name)  de->name=se->name;
00342                             else if(de->name!=se->name)  ++n_mismatches;
00343                         }
00344                     }
00345                     
00346                     // Still need to check if required entries in dest 
00347                     // (pointers) are also in source. Can leave away this 
00348                     // check if we know that we looked at all values in 
00349                     // dest. 
00350                     if(s->membvar.n()-n_missing!=d->membvar.n())
00351                         for(uint j=0,jend=d->membvar.n(); j<jend; j++)
00352                     { // LOOP: DEST
00355                         //   already been looked up; these can be skipped here. 
00356                         ClassInfo::MemberVarEntry *se=NULL;
00357                         ClassInfo::MemberVarEntry *de=&d->membvar[j];
00358                         if(guess_first && de->off==s->membvar[j].off)
00359                         {  se=&s->membvar[j];  }
00360                         else
00361                         {
00362                             ssize_t idx=TLBinarySearch(
00363                                 s->membvar.ptr(),s->membvar.n(),
00364                                 de->off,MemberVarEntryOffsetOperators());
00365                             if(idx>=0)  se=&s->membvar[idx];
00366                         }
00367                         
00368                         // We need only look at the cases where the info is 
00369                         // in the master and NOT in the src; all the others 
00370                         // have already been treated. 
00371                         if(se)  continue;  // <-- NOT if(!se) !!
00372                         
00373                         // Entry in dest (master) but not in src. 
00374                         if(de->vtype.IsPointerType() || 
00375                             !cfg.ignore_simple_type_missing)
00376                         {  ++n_mismatches;  }
00377                         else
00378                         {
00379                             // In this case must add the information to the 
00380                             // master so that it can be compared to subsequent 
00381                             // occurances. As arrays are used, this is slow. 
00382                             // OTOH, this should not happen frequently as we 
00383                             // already use the node with the most entries as 
00384                             // master. 
00385                             // NOTE that this means that we also have to 
00386                             // check the previous files again as this may just 
00387                             // have produced a mismatch with older files. 
00388                             // Maybe, replace with a gather-stage followed by 
00389                             // a check stage. 
00390                             CritAssert(!"not yet implemented");  // FIXME. 
00391                         }
00392                     }
00393                     
00394                     if(n_mismatches)
00395                     {
00396                         Error(s->asm_loc,
00397                             "while merging member var info in %s \"%s\": "
00398                             "%u mismatches",
00399                             NamespaceInfo::NSType2String(dest_type),
00400                             s->CompleteName().str(),
00401                             n_mismatches);
00402                         ++n_errors;
00403                         break;  // Stop complaining now. 
00404                     }
00405                 }
00406             }   break;
00407             default: Assert(0);
00408         }
00409         
00410         for(uint i=0; i<nheads; i++)
00411         {  head_list[i]->linked=dest;  }
00412     }
00413     Assert(dest);
00414     
00415     // Create new "list" with all children of all heads: 
00416     uint nchld=0;
00417     for(uint i=0; i<nheads; i++)
00418     {  nchld+=head_list[i]->down.count();  }
00419     if(nchld)
00420     {
00423         NamespaceInfo **chld_list=ALLOC<NamespaceInfo*>(nchld);
00424         nchld=0;
00425         for(uint i=0; i<nheads; i++)
00426             for(NamespaceInfo *j=head_list[i]->down.first(); j; j=j->next)
00427                 chld_list[nchld++]=j;
00428         
00429         // All children of all heads are now in chld_list. 
00430         // Sort it by names: 
00431         // (Using heap sort to not get trapped when the input is already 
00432         // sorted.)
00433         if(nchld<=16)
00434         {
00435             InsertionSort<NamespaceInfo*,
00436                 const NamespaceInfo::PtrListOperators<NamespaceInfo> >(
00437                 chld_list,nchld,
00438                     NamespaceInfo::PtrListOperators<NamespaceInfo>());
00439         }
00440         else
00441         {
00442             HeapSort<NamespaceInfo*,
00443                 const NamespaceInfo::PtrListOperators<NamespaceInfo> >(
00444                 chld_list,nchld,
00445                     NamespaceInfo::PtrListOperators<NamespaceInfo>());
00446         }
00447         
00448         //Warning("    nchld=%u:",nchld);
00449         //for(uint i=0; i<nchld; i++)
00450         //{  Warning("      %s",chld_list[i]->CompleteName().str());  }
00451         
00452         // Find equally named children. As the list is sorted, this is easy. 
00453         TLString name=chld_list[0]->name;
00454         for(uint i0=0,i=1;;i++)
00455         {
00456             if(i<nchld && name==chld_list[i]->name)  continue;
00457             
00458             // Names i0..i-1 are equal. We need to recurse even if i-i0==1 
00459             // in order to not loose information. "Merging" will, however, 
00460             // clearly be trivial in this case. 
00461             NamespaceInfo *c=_MergeNamespaceInfo_Recursive(
00462                 chld_list+i0,i-i0);
00463             dest->AddChild(c);   // AddChild(NULL) is a no-op. Will not happen. 
00464             
00465             if(i>=nchld) break;
00466             name=chld_list[i]->name;
00467             i0=i;  // do not move
00468         }
00469         
00470         FREE(chld_list);
00471     }
00472     
00473     //Warning("MNIR: POP");
00474     
00475     return(dest);
00476 }
00477 
00478 
00479 void VMLinker::_CheckNamespaceInfo_Recursive(FileNode *fn,NamespaceInfo *ni)
00480 {
00481     do {
00482         // This should be set; only reason for it to be NULL is an error 
00483         // earlier during linking. 
00484         Assert(ni->linked);
00485         if(!ni->linked)  break;
00486         
00487         NamespaceInfo *master=ni->linked;
00488         Assert(ni->nstype==master->nstype);
00489         //Error("_CNIR: %d %s %s",(int)master->link_info_set,
00490         //  fn->f->filename.path().str(),ni->CompleteName().str());
00491         switch(master->nstype)
00492         {
00493             case NamespaceInfo::NSClass:
00494             {
00495                 ClassInfo *cmaster = static_cast<ClassInfo*>(master);
00496                 ClassInfo *cni = static_cast<ClassInfo*>(ni);
00497                 
00498                 // For the first occurance: Copy the values. 
00499                 if(!cmaster->link_info_set)
00500                 {
00501                     // BASE ENTRIES. 
00502                     cmaster->base.alloc(cni->base.n());
00503                     for(uint32 i=0,iend=cni->base.n(); i<iend; i++)
00504                     {
00505                         ClassInfo::BaseEntry *d=&cmaster->base[i];
00506                         ClassInfo::BaseEntry *s=&cni->base[i];
00507                         d->off=s->off;
00508                         // s->ci may only be NULL if an error occured during 
00509                         // lookup. In this case we should have bailed out 
00510                         // already. 
00511                         Assert(s->ci);
00512                         // Internal entries are simply to be copied. 
00513                         ClassInfo *sci=s->ci->ci();
00514                         if(sci)
00515                         {
00516                             // Non-internal. 
00517                             d->ci=static_cast<ClassInfo*>(sci->linked);
00518                             // d->ci (s->ci->linked) may only be NULL in case 
00519                             // of an error in the tree merging; we should have 
00520                             // bailed out already in this case. 
00521                             Assert(d->ci);
00522                             Assert(d->ci->ci());
00523                             Assert(d->ci->ci()->nstype=NamespaceInfo::NSClass);
00524                         }
00525                         else
00526                         {
00527                             // Internal. Simply allocate a new one; this works 
00528                             // much like internal_symbols. 
00529                             d->ci=out->internal_classes.LookupStore(
00530                                 s->ci->class_tid);
00531                         }
00532                     }
00533                     
00534                     // VTABLE ENTRIES. 
00535                     cmaster->vtable.alloc(cni->vtable.n());
00536                     for(uint32 i=0,iend=cni->vtable.n(); i<iend; i++)
00537                     {
00538                         ClassInfo::VTableEntry *d=&cmaster->vtable[i];
00539                         ClassInfo::VTableEntry *s=&cni->vtable[i];
00540                         
00541                         // Much the same as s->ci in the BASE entries above. 
00542                         Assert(s->se);
00543                         
00544                         // The problem here is that symbols are not yet 
00545                         // merged/linked. This means, we now use pointers 
00546                         // into the non-master tree until resolving. 
00547                         d->se=s->se;
00548                         Assert(!d->se->ep() || d->se->ep()->nspc->linked);
00549                     }
00550                     
00551                     //cmaster->link_info_set=1; <-- Done below to allow 
00552                     //   for link_info_set checks in "case"s further down. 
00553                 }
00554                 else
00555                 {
00556                     // BASE ENTRIES. 
00557                     uint n_mismatches=0;
00558                     if(cni->base.n()!=cmaster->base.n())
00559                     {  ++n_mismatches;  }
00560                     else for(uint32 i=0,iend=cmaster->base.n(); i<iend; i++)
00561                     {
00562                         ClassInfo::BaseEntry *d=&cmaster->base[i];
00563                         ClassInfo::BaseEntry *s=&cni->base[i];
00564                         
00565                         // Compare offset: 
00566                         if(d->off!=s->off)  ++n_mismatches;
00567                         
00568                         // Compare TypeID...
00569                         Assert(s->ci);  // see above ("first occurance" branch)
00570                         ClassInfo *ssci=s->ci->ci();
00571                         ClassInfo *dsci=d->ci->ci();
00572                         if(ssci && dsci)
00573                         {
00574                             // Both non-internal. 
00575                             ClassInfo *sci_lnk=static_cast<ClassInfo*>(
00576                                 ssci->linked);
00577                             // see above ("first occurance" branch)
00578                             Assert(sci_lnk); 
00579                             Assert(sci_lnk->nstype=NamespaceInfo::NSClass);
00580                             
00581                             if(sci_lnk!=dsci)  ++n_mismatches;
00582                         }
00583                         else if(!ssci && !dsci)
00584                         {
00585                             // Both internal. 
00586                             if(s->ci->class_tid!=d->ci->class_tid)
00587                             {  ++n_mismatches;  }
00588                         }
00589                         else  // Internal versus external. 
00590                         {  ++n_mismatches;  }
00591                     }
00592                     if(n_mismatches)
00593                     {
00594                         Error(cni->asm_loc,
00595                             "while merging base class info in %s \"%s\": "
00596                             "%u mismatches",
00597                             NamespaceInfo::NSType2String(master->nstype),
00598                             master->CompleteName().str(),
00599                             n_mismatches);
00600                         ++n_errors;
00601                     }
00602                     
00603                     // VTABLE ENTRIES. 
00604                     n_mismatches=0;
00605                     if(cni->vtable.n()!=cmaster->vtable.n())
00606                     {  ++n_mismatches;  }
00607                     else for(uint32 i=0,iend=cmaster->vtable.n(); i<iend; i++)
00608                     {
00609                         // Look at the vtable(s). Their symbol names and 
00610                         // types must match. 
00611                         ClassInfo::VTableEntry *du=&cmaster->vtable[i];
00612                         ClassInfo::VTableEntry *su=&cni->vtable[i];
00613                         
00614                         // This will compare type and name: 
00615                         // Also works for internal symbols. 
00616                         if(!du->se->CompareTo(*su->se))  ++n_mismatches;
00617                         // Still have to compare namespaces for non-internal 
00618                         // symbols. 
00619                         if(du->se->ep())
00620                         {
00621                             NamespaceInfo::SymbolEntryE *d=du->se->ep();
00622                             NamespaceInfo::SymbolEntryE *s=su->se->ep();
00623                             //Assert(d->nspc->linked); <- Known already.
00624                             Assert(s->nspc->linked);
00625                             if(d->nspc->linked!=s->nspc->linked)
00626                             {  ++n_mismatches;  }
00627                         }
00628                     }
00629                     if(n_mismatches)
00630                     {
00631                         Error(cni->asm_loc,
00632                             "while merging vtable class info in %s \"%s\": "
00633                             "%u mismatches",
00634                             NamespaceInfo::NSType2String(master->nstype),
00635                             master->CompleteName().str(),
00636                             n_mismatches);
00637                         ++n_errors;
00638                     }
00639                 }
00640             }   // NO BREAK; fall through. 
00641             case NamespaceInfo::NSNamespace:
00642                 // Nothing to do. 
00643                 break;
00644             default: Assert(0);
00645         }
00646         
00647         master->link_info_set=1;  // do not move
00648     } while(0);
00649     
00650     // Call recursively on children: 
00651     for(NamespaceInfo *j=ni->down.first(); j; j=j->next)
00652         _CheckNamespaceInfo_Recursive(fn,j);
00653 }
00654 
00655 
00656 int VMLinker::_CheckBaseRecursion(ClassInfo *cni)
00657 {
00658     Assert(cni->nstype==NamespaceInfo::NSClass);
00659     
00660     int errcnt=0;
00661     
00662     // In this case we have a recursion in the base classes. 
00663     if(cni->recursion_flag)
00664     {  ++errcnt;  return(errcnt);  }
00665     
00666     cni->recursion_flag=1;
00667     for(uint32 i=0,iend=cni->base.n(); i<iend; i++)
00668     {
00669         ClassInfoIE *cii=cni->base[i].ci;
00670         Assert(cii);
00671         ClassInfo *ci=cii->ci();
00672         if(!ci)  continue;  // Ignore internal base classes. 
00673         errcnt+=_CheckBaseRecursion(ci);
00674     }
00675     cni->recursion_flag=0;
00676     
00677     return(errcnt);
00678 }
00679 
00680 
00681 void VMLinker::_CheckBaseRecursion_Recursive(FileNode *fn,NamespaceInfo *ni)
00682 {
00683     if(ni->nstype==NamespaceInfo::NSClass && 
00684         _CheckBaseRecursion(static_cast<ClassInfo*>(ni)))
00685     {
00686         Error(ni->asm_loc,
00687             "recursion in base class hierarchy of \"%s\""
00688             " (what'chew doin' to me, Willis?!)",
00689             ni->CompleteName().str());
00690         ++n_errors;
00691     }
00692     
00693     // Call recursively on children: 
00694     for(NamespaceInfo *j=ni->down.first(); j; j=j->next)
00695         _CheckBaseRecursion_Recursive(fn,j);
00696 }
00697 
00698 
00699 void VMLinker::_MergeNamespaceAndVTableInfo()
00700 {
00701     Assert(!out->nspc_root);
00702     
00703     // *** Merge namespace info. ***
00704     uint nheads=0;
00705     for(FileNode *fn=flist.first(); fn; fn=fn->next)
00706     {
00707         NamespaceInfo *f_nspc_root=fn->f->nspc_root;
00708         if(!f_nspc_root)  continue;
00709         ++nheads;
00710     }
00711     
00712     if(nheads)
00713     {
00714         NamespaceInfo **head_list=ALLOC<NamespaceInfo*>(nheads);
00715         
00716         nheads=0;
00717         for(FileNode *fn=flist.first(); fn; fn=fn->next)
00718         {
00719             NamespaceInfo *f_nspc_root=fn->f->nspc_root;
00720             if(!f_nspc_root)  continue;
00721             head_list[nheads++]=f_nspc_root;
00722         }
00723         
00724         out->nspc_root=_MergeNamespaceInfo_Recursive(head_list,nheads);
00725         
00726         FREE(head_list);
00727     }
00728     
00729     // It is important that we bail out on error here. 
00730     // Otherwise, we may dereference some NULL pointers. 
00731     if(n_errors)  return;
00732     
00733     // Okay, now the nspc_root tree is built up and we can do the second 
00734     // part of the merging/checking. Note that the TypeIDs and VTableIDs 
00735     // in the namespace tree are already looked up. 
00736     
00737     for(FileNode *fn=flist.first(); fn; fn=fn->next)
00738     {
00739         NamespaceInfo *f_nspc_root=fn->f->nspc_root;
00740         if(!f_nspc_root)  continue;
00741         _CheckNamespaceInfo_Recursive(fn,f_nspc_root);
00742     }
00743     
00744     // Bail out before we do ugly and confusing things. 
00745     if(n_errors)  return;
00746     
00747     // Finally, check for recursion in the base classes. In case we 
00748     // have recursion, this is lethal for usage flag propagation so 
00749     // we need to add to n_errors and rely on bailing out before 
00750     // the actual linker symbol resolve loop. 
00751     for(FileNode *fn=flist.first(); fn; fn=fn->next)
00752     {
00753         NamespaceInfo *f_nspc_root=fn->f->nspc_root;
00754         if(!f_nspc_root)  continue;
00755         _CheckBaseRecursion_Recursive(fn,f_nspc_root);
00756     }
00757 }
00758 
00759 
00760 void VMLinker::_GenerateSymbolProvideMap_AddGlobal(FileNode *fn,
00761     AssemblerFile::_GlobVars *gvar)
00762 {
00763     for(AssemblerFile::GlobalVarList::Iterator i(gvar->globvarq); i; i++)
00764     {
00765         NamespaceInfo::SymbolEntryE *se=(*i)->se;
00766         NamespaceInfo::SymbolEntryE *known=symbol_provide_map.AddNode(se);
00767         if(known)
00768         {
00769             Error(fn->f->filename,
00770                 "duplicate variable symbol \"%s\"",se->CompleteName().str());
00771             if(known->nspc)
00772             {  Error(known->nspc->asm_loc,"  this is the location of the "
00773                 "previous occurance");  }
00774             ++n_errors;
00775             // This means that the symbol names are duplicate in different 
00776             // files because we already checked for same files at 
00777             // parse time. 
00778         }
00779         
00780         Warning(fn->f->filename,"%s added to provide map",
00781             se->CompleteName().str());
00782     }
00783 }
00784 
00785 
00786 void VMLinker::_GenerateSymbolProvideMap()
00787 {
00788     symbol_provide_map.clear();  // be sure...
00789     
00790     for(FileNode *fn=flist.first(); fn; fn=fn->next)
00791     {   
00792         NamespaceInfo *f_nspc_root=fn->f->nspc_root;
00793         if(!f_nspc_root)  continue;
00794         
00795         for(ProgramStorage::Function *i=fn->f->program.FirstFunction(); 
00796             i; i=i->next)
00797         {
00798             NamespaceInfo::SymbolEntryE *known=
00799                 symbol_provide_map.AddNode(i->se);
00800             if(known)
00801             {
00802                 // This means that the symbol names are duplicate in different 
00803                 // files because we already checked for same files at 
00804                 // parse time. There may exist only one function with this 
00805                 // name which is exported. In case a non-exported one is 
00806                 // there as well, it must be one of the both: 
00807                 // *known or *i->se. 
00808                 // We could try and solve this problem by attaching a 
00809                 // different name on the non-exported one. This is, however, 
00810                 // dangerous as the names are also references by some maps 
00811                 // (BTrees; notably symbol_provide_map and map_name2symbol) 
00812                 // and changing the name is likely to require re-insertion 
00813                 // into these maps. 
00814                 // Instead, the problem is solved in the input stage by 
00815                 // attaching a unique suffix to non-exported symbols. 
00816                 // Hence, it is an internal error if we collide with a 
00817                 // non-exported symbol here. 
00818                 // FIXME: We could support non-exported variables in 
00819                 //        global storage in the same way. 
00820                 Error(i->loc,
00821                     "duplicate function symbol \"%s\"",
00822                     i->se->CompleteName().str());
00823                 if(known->nspc)
00824                 {  Error(known->nspc->asm_loc,"  this is the location "
00825                     "of the previous occurance");  }
00826                 ++n_errors;
00827                 
00828                 if(known->extid==NamespaceInfo::SymbolEntryE::ExtFunction && 
00829                     i->se->extid==NamespaceInfo::SymbolEntryE::ExtFunction && 
00830                     (!known->ftype.exported || !i->se->ftype.exported))
00831                 {  Assert(0);  }  // <-- Read large comment above. 
00832             }
00833             
00834             Warning(i->loc,"%s added to provide map",
00835                 i->se->CompleteName().str());
00836         }
00837         
00838         _GenerateSymbolProvideMap_AddGlobal(fn,&fn->f->gvar_v);
00839         _GenerateSymbolProvideMap_AddGlobal(fn,&fn->f->gvar_p);
00840     }
00841 }
00842 
00843 
00844 void VMLinker::_LinkGlobalStorage(FileNode *fn,AssemblerFile::_GlobVars *gvar,
00845     AssemblerFile::_GlobVars *dest,char which)
00846 {
00847     Warning(fn->f->filename,"linking %cglobal storage (%u bytes)",
00848         which,(uint)gvar->size);
00849     
00850     // Accumulate size. 
00851     Offset base=dest->size;
00852     dest->size+=gvar->size;
00853     
00854     for(AssemblerFile::GlobalVarList::Iterator i(gvar->globvarq); i; i++)
00855     {
00856         AssemblerFile::GlobalVarEntry *s=(*i);
00857         
00858         dest->globvarq.PushHead(*s);  // copy
00859         AssemblerFile::GlobalVarEntry *dest_ent=dest->globvarq.head();
00860         // Add offset into global storage. 
00861         dest_ent->off+=base;
00862         // Need to use linked symbol entry. Let's see...
00863         dest_ent->se=NULL;
00864         
00865         // Of course, the var symbol may not yet be linked. 
00866         // If this assert fails "legally", we can replace it with an error. 
00867         Assert(!s->se->linked);
00868         // Only non-internal entries are allowed, of course. 
00869         Assert(s->se->symref>=0);
00870         // The global var must be in the provide map of the file, obviously. 
00871         Assert(fn->f->symref2globvar.lookup(s->se->symref));
00872         
00873         // Add entry in the linked namespace. 
00874         NamespaceInfo *master_parent=s->se->nspc->linked;
00875         Assert(master_parent);
00876         Assert(!master_parent->linked);  // master_parent in master tree. 
00877         // Push a copy of the symbol entry, we will modify some entries below. 
00878         master_parent->symbol.PushHead(/*a copy of:*/*s->se);
00879         NamespaceInfo::SymbolEntryE *master_se=master_parent->symbol.head();
00880         master_se->nspc=master_parent;
00881         master_se->symref=_SQQuery(s->se);
00882         master_se->linked=NULL;   // We're in the master tree. 
00883         
00884         // Link the symbol entry: 
00885         s->se->linked=master_se;
00886         // Set symbol entry pointer for entry in global vars of linked output. 
00887         dest_ent->se=master_se;
00888         
00889         // Still add entry to the mapping: 
00890         NamespaceInfo::SymbolEntryE *known=NULL;
00891         Assert(master_se->symref>=0);  // Non-internal ones, only. 
00892         int srv=master_parent->map_name2symbol.store(master_se,
00893             /*allow_update=*/0,/*old_val=*/&known);
00894         if(srv)
00895         {
00896             Assert(known);
00897             Assert(!known->linked);
00898             Error(fn->f->filename,
00899                 "global variable symbol \"%s\" defined multiple times",
00900                 master_se->CompleteName().str());
00901             ++n_errors;
00902             // Unfortunately, we do not know where as *known in the master 
00903             // tree does not have source information. 
00904             // We can find it by searching throuh the provide map. 
00905             // This here is not a particularly fast way as we have O(log(n)) 
00906             // for each symbol while we could do with O(log(n)+k) with 
00907             // k = "number of symbols with same name" as B-trees conserve the 
00908             // order. But, OTOH, errors need not be fast and O(log(n)) is 
00909             // still worst-case optimal searching...
00910         // FIXME: Do it; probably in an own function. 
00911         //NamespaceInfo::SymbolEntry **prev,**next;  // <-- Not set up. 
00912         //symbol_provide_map.SearchNeighbours(
00913         }
00914         
00915         if(!cfg.abandon_out_maps)
00916         {
00917             NamespaceInfo::SymbolEntryE _unused_ *known=
00918                 out->symref2symbol.AddNode(master_se);
00919             Assert(!known);
00920             
00921             bool is_known;  // not set up
00922             out->symref2globvar.AddNode(dest_ent->se->symref,dest_ent,&is_known);
00923             Assert(!is_known);
00924         }
00925     }
00926 }
00927 
00928 
00929 void VMLinker::_LinkerFileNeeded(FileNode *fn)
00930 {
00931     // If the file is already marked as needed, we need not do any more here. 
00932     if(fn->needed)  return;
00933     
00934     // Mark the file as needed and process the global and .init content. 
00935     // .start need not be processed as this was already done. 
00936     fn->needed=1;
00937     
00938     if(fn->f->slabel_init.pfunc)
00939     {
00940         _SQPush(&fn->f->slabel_init.se);
00941     }
00942     
00943     _LinkGlobalStorage(fn,&fn->f->gvar_v,&out->gvar_v,'v');
00944     _LinkGlobalStorage(fn,&fn->f->gvar_p,&out->gvar_p,'p');
00945 }
00946 
00947 
00948 void VMLinker::_LinkFunction(FileNode *fn,ProgramStorage::Function *psf,
00949     NamespaceInfo::SymbolEntryE *se_linked)
00950 {
00951     Assert(se_linked);
00952     
00953     bool is_start_func=(se_linked==&out->slabel_start.se);
00954     // Make sure symref is set (>0): 
00955     Assert(is_start_func || se_linked->symref>0);
00956     
00957     ProgramStorage::Function *dest = new ProgramStorage::Function(
00958         se_linked->symref,psf->loc,psf->length());
00959     dest->se=se_linked;
00960     
00961     // Scan through the instructions and resolve TypeIDs and SymRefs. 
00962     for(PrgAdr adr=0; adr<psf->length(); )
00963     {
00964         const INST::DescEntry *ide=INST::Desc(psf->InstructionAt(adr));
00965         if(!ide)
00966         {
00967             Error(psf->loc,
00968                 "illegal instruction at address 0x%x in \"%s\"",
00969                 (uint)adr,psf->se->CompleteName().str());
00970             ++n_errors;
00971             break;  // No use to go on; we cannto compute the size of the skip. 
00972         }
00973         
00974         // Copy instruction to destination (linked) memory. 
00975         char *inst_base_src=&psf->index(adr);
00976         dest->append(inst_base_src,ide->size);
00977         char *inst_base_dest=&dest->index(adr);
00978         
00979         // Only instructions with a TypeID or SymRef are interesting. 
00980         if(ide->typeid_off)
00981         {
00982             // Extract TypeID from program memory: 
00983             TypeID val=*(TypeID*)(inst_base_src+ide->typeid_off);
00984             
00985             // Internal TypeIDs stay unchanged. 
00986             TypeID new_val;
00987             if(val<0)
00988             {  new_val=val;  }
00989             else
00990             {
00991                 // Look up TypeID: 
00992                 ClassInfo *found=fn->f->tid2classinfo.lookup(val);
00993                 if(!found)
00994                 {
00995                     Error(dest->loc,
00996                         "undeclared TypeID %d at address 0x%x",
00997                         (int)val,(uint)adr);
00998                     ++n_errors;
00999                     new_val=0;
01000                 }
01001                 else
01002                 {
01003                     Assert(found->linked);
01004                     Assert(found->linked->nstype==NamespaceInfo::NSClass);
01005                     
01006                     ClassInfo *ci=static_cast<ClassInfo*>(found->linked);
01007                     // See for what we need the class. 
01008                     switch(psf->InstructionAt(adr))
01009                     {
01010                         case INST::ONEW:
01011                             if(!ci->need_construct)
01012                             {  _LinkerNeedClassConstruct(ci);  }
01013                             break;
01014                         case INST::SCAST:
01015                         case INST::DCAST:
01016                             if(!ci->need_cast)
01017                             {  ci->need_cast=1;  }
01018                             break;
01019                         default: Assert(0);
01020                     }
01021                     
01022                     new_val=ci->class_tid;
01023                     Assert(new_val);
01024                 }
01025             }
01026             
01027             // Write result back into program memory. 
01028             *(TypeID*)(inst_base_dest+ide->typeid_off)=(TypeID)new_val;
01029         }
01030         
01031         if(ide->symref_off)
01032         {
01033             // Extract SymRef from program memory: 
01034             SymRef val=*(SymRef*)(inst_base_src+ide->symref_off);
01035             
01036             // Look up SymRef: Internal symrefs stay unchanged. 
01037             SymRef new_val;
01038             if(val<0)
01039             {  new_val=val;  }
01040             else
01041             {
01042                 NamespaceInfo::SymbolEntryE *found=
01043                     fn->f->symref2symbol.lookup(val);
01044                 if(!found)
01045                 {
01046                     Error(dest->loc,
01047                         "undeclared SymRef $%d at address 0x%x",
01048                         (int)val,(uint)adr);
01049                     ++n_errors;
01050                     new_val=0;
01051                 }
01052                 else
01053                 {
01054                     // So, it is the symbol entry *found which may or may not 
01055                     // yet be linked. 
01056                     if(found->linked)
01057                     {
01058                         // Already linked. This is easy. 
01059                         new_val=found->linked->symref;
01060                     }
01061                     else
01062                     {
01063                         // See if it is in the symbol queue already and if not, 
01064                         // push it. 
01065                         new_val=_SQPush(found);
01066                     }
01067                     
01068                     Assert(new_val);
01069                 }
01070             }
01071             
01072             //fprintf(stderr,"symref subst %d -> %d +++++++++++\n",val,new_val);
01073             
01074             // Write result back into program memory. 
01075             *(SymRef*)(inst_base_dest+ide->symref_off)=(SymRef)new_val;
01076             
01077             //val=*(SymRef*)(inst_base_src+ide->symref_off);
01078             //new_val=*(SymRef*)(inst_base_dest+ide->symref_off);
01079             //fprintf(stderr,"NOW %d -> %d +++++++++++\n",val,new_val);
01080         }
01081         
01082         // Skip to next instruction. 
01083         adr+=ide->size;
01084     }
01085     
01086     /*static_cast<AssemblerFile_Plaintext*>(out)->WriteFunctionProgram(stderr,
01087         psf);
01088     static_cast<AssemblerFile_Plaintext*>(out)->WriteFunctionProgram(stderr,
01089         dest);*/
01090     
01091     // Important: Add function to (linked, master) program storage: 
01092     out->program.AddFunction(dest);
01093     if(is_start_func)
01094     {  out->slabel_start.pfunc=dest;  }
01095     
01096     if(!cfg.abandon_out_maps && !is_start_func)
01097     {
01098         bool is_known;  // not set up. 
01099         out->symref2function.AddNode(se_linked->symref,dest,&is_known);
01100         Assert(!is_known);
01101     }
01102 }
01103 
01104 
01105 void VMLinker::_LinkerNeedClassConstruct(ClassInfo *ci)
01106 {
01107     // We are in master tree. 
01108     Assert(!ci->linked);
01109     
01110     // Avoid doing things twice. 
01111     if(ci->need_construct)  return;
01112     ci->need_construct=1;
01113     
01114     Warning("processing %u vtable entries of %s",
01115         (uint)ci->vtable.n(),ci->CompleteName().str());
01116     
01117     // This means, we need the vtables. 
01118     // NOTE: Up to here, the vtable entries in the master tree point 
01119     //       to SymbolEntries in NON-master tree. The reason is that 
01120     //       these symbols simply do not yet exist in the master tree. 
01121     for(uint32 i=0,iend=ci->vtable.n(); i<iend; i++)
01122     {
01123         ClassInfo::VTableEntry *ve=&ci->vtable[i];
01124         Assert(ve->se);
01125         
01126         if(ve->se->ep())
01127         {
01128             // Non-internal symbols here. 
01129             NamespaceInfo::SymbolEntryE *vese=ve->se->ep();
01130             Assert(vese->nspc->linked);
01131             
01132             // We will put NULL in the *se pointer in the master tree until we 
01133             // resolve the symbol. 
01134             if(vese->linked)
01135             {
01136                 // Symbol already linked. 
01137                 ve->se=vese->linked;
01138             }
01139             else
01140             {
01141                 // Symbol not yet resolved. 
01142                 _SQPush(vese,&ve->se);
01143                 ve->se=NULL;
01144             }
01145         }
01146         else
01147         {
01148             // Internal symbols here. 
01149             // This means: we need to allocate an internal symbol entry 
01150             // and assign it. If the internal symbol entry is already 
01151             // allocated, a lookup is enough. This is done by 
01152             // InternalSymbolList's LookupStore(). 
01153             ve->se=out->internal_symbols.LookupStore(ve->se->symref);
01154             // Nothing more to do. 
01155         }
01156     }
01157 }
01158 
01159 
01160 void VMLinker::_DoPropagateUseFlags(ClassInfo *from,ClassInfo *cni)
01161 {
01162     // NOTE: If we need a class for construction, then the need_construct is 
01163     //       not set on the bases because we do not need the vtables of the 
01164     //       bases. 
01165     if(from->need_construct || from->need_cast)
01166     {
01167         cni->need_cast=1;
01168     }
01169     
01170     // Recurse up the base hierarchy: 
01171     for(uint32 i=0,iend=cni->base.n(); i<iend; i++)
01172     {
01173         ClassInfoIE *cii=cni->base[i].ci;
01174         Assert(cii);
01175         ClassInfo *ci=cii->ci();
01176         if(!ci)  continue;  // Ignore internal base classes. 
01177         _DoPropagateUseFlags(from,ci);
01178     }
01179 }
01180 
01181 void VMLinker::_PropagateUseFlags_Recursive(NamespaceInfo *ni)
01182 {
01183     if(ni->nstype==NamespaceInfo::NSClass)
01184     {
01185         ClassInfo *ci=static_cast<ClassInfo*>(ni);
01186         
01187         if(ci->need_construct || ci->need_cast)
01188         {  _DoPropagateUseFlags(ci,ci);  }
01189     }
01190     
01191     // Call recursively on children: 
01192     for(NamespaceInfo *j=ni->down.first(); j; j=j->next)
01193         _PropagateUseFlags_Recursive(j);
01194 }
01195 
01196 
01197 void VMLinker::_CreateInitFunction()
01198 {
01199     // Create the ".init" function for this file by emitting CALL 
01200     // instructions for the .init functions in the source files. 
01201     ProgramStorage::Function *inifunc=new ProgramStorage::Function(
01202         /*symref=*/0,SCLocation());
01203     
01204     int n_added=0;
01205     for(FileNode *fn=flist.first(); fn; fn=fn->next)
01206     {
01207         if(!fn->needed)  continue;
01208         if(!fn->f->slabel_init.pfunc)  continue;
01209         
01210         // Init function of needed file must have been linked. 
01211         Assert(fn->f->slabel_init.se.linked);
01212         
01213         SymRef symref=fn->f->slabel_init.se.linked->symref;
01214         inifunc->append(INST::CALL,symref);
01215         ++n_added;
01216     }
01217     if(!n_added)
01218     {
01219         // Do not need an init function. 
01220         DELETE(inifunc);
01221     }
01222     else
01223     {
01224         // Append return instruction...
01225         inifunc->append(INST::RET);
01226         
01227         // Add init function to program memory. 
01228         out->program.AddFunction(inifunc);
01229         inifunc->se=&out->slabel_init.se;
01230         
01231         // Create a nice SymbolEntryE for the init function. 
01232         out->slabel_init.pfunc=inifunc;
01233         out->slabel_init.se.extid=NamespaceInfo::SymbolEntryE::ExtFunction;
01234         out->slabel_init.se.ftype=FuncType(FuncType::Function,/*exported=*/0);
01235         out->slabel_init.se.name=".init";
01236         out->slabel_init.se.nspc=out->nspc_root;
01237         out->slabel_init.se.linked=NULL;
01238     }
01239 }
01240 
01241 int VMLinker::LinkAll(AssemblerFile *_out)
01242 {
01243     // Well, then let's start...
01244     DELETE(out);
01245     out=_out;
01246     n_errors=0;
01247     
01248     // Be sure to start at "zero". 
01249     symbol_provide_map.clear();
01250     master_TypeID_cnt=1;
01251     master_SymRef_cnt=1;
01252     sq.clear();
01253     
01254     // Something to base debugging and testing on: Complete namespace 
01255     // tree dump of all input files: 
01256     for(FileNode *fn=flist.first(); fn; fn=fn->next)
01257     {   
01258         NamespaceInfo *f_nspc_root=fn->f->nspc_root;
01259         if(!f_nspc_root)  continue;
01260         
01261         StringTreeDump dump;
01262         dump.append("------------<"+fn->f->filename.path()+
01263             ">------------\n");
01264         f_nspc_root->DumpTree(dump,/*IDs_resolved=*/0);
01265         dump.write(stdout);
01266     }
01267     
01268     // First, find the file which has the start symbol. 
01269     // If there is more than one, this is an error. 
01270     FileNode *start_fn=NULL;
01271     FileNode *abi_version_fn=NULL;
01272     for(FileNode *fn=flist.first(); fn; fn=fn->next)
01273     {
01274         fn->needed=0;  // be sure...
01275         
01276         if(fn->f->slabel_start.pfunc)
01277         {
01278             if(!start_fn)
01279             {  start_fn=fn;  }
01280             else
01281             {
01282                 Error(fn->f->filename,
01283                     "multiple start labels; previous definition in %s",
01284                     start_fn->f->filename.path().str());
01285                 ++n_errors;
01286             }
01287         }
01288         
01289         if(fn->f->abi_version)
01290         {
01291             if(!abi_version_fn)
01292             {  abi_version_fn=fn;  }
01293             else if(abi_version_fn->f->abi_version!=fn->f->abi_version)
01294             {
01295                 Error(fn->f->filename,
01296                     "incompatible ABI versions: \"%s\" vs \"%s\" in %s",
01297                     fn->f->abi_version.str(),
01298                     abi_version_fn->f->abi_version.str(),
01299                     abi_version_fn->f->filename.path().str());
01300                 ++n_errors;
01301             }
01302         }
01303         else
01304         {
01305             Warning(fn->f->filename,
01306                 "ABI version information missing; assuming compatible");
01307         }
01308     }
01309     if(!start_fn)
01310     {  Error("no start label present");  ++n_errors;  }
01311     if(n_errors)
01312     {
01313         Error("bailing out at stage 0 (find start)");
01314         return(n_errors);
01315     }
01316     
01317     // Set output ABI version: 
01318     out->abi_version=abi_version_fn->f->abi_version;
01319     
01320     // Okay, start_file contains the start label. 
01321     // We need to determine which file (of all the passed ones) we 
01322     // actually need and throw away those which we do not need without 
01323     // investing too much work into those. 
01324     
01325     // To see which files are needed, we must look up all symbols in those 
01326     // files which are needed until now. If the new symbol is in a file 
01327     // which is not yet needed, then this must be marked as needed. 
01328     // If a symbol which we need appars more than once, this is an error. 
01329     // If an unneeded symbol appears more than once, we can ignore that. 
01330     
01331     // Look up all the TypeIDs and VTableIDs in the namespace part of all 
01332     // files (not the code part). Also, resolve the SymRefs. 
01333     for(FileNode *fn=flist.first(); fn; fn=fn->next)
01334     {
01335         if(fn->f->ResolveIDsNamespaceLocal())
01336         {  ++n_errors;  }
01337     }
01338     if(n_errors)
01339     {
01340         Error("bailing out at stage 1 (resolve IDs local)");
01341         return(n_errors);
01342     }
01343     
01344     // First join all the namespaces (including class names, TypeIDs and 
01345     // VTableIDs) and make sure that classes have equal definitions. 
01346     _MergeNamespaceAndVTableInfo();
01347     if(n_errors)
01348     {
01349         Error("bailing out at stage 2 (merge namespaces)");
01350         return(n_errors);
01351     }
01352     
01353     // Set up the symbol_provide_map. 
01354     _GenerateSymbolProvideMap();
01355     // It is important that we quit here on duplicate symbols. 
01356     if(n_errors)
01357     {
01358         Error("bailing out at stage 3 (create symbol map)");
01359         return(n_errors);
01360     }
01361     
01362     // Okay, do the actual linking of the symbols and the program. 
01363     // We put all symbols which we need into a queue. All entries in the 
01364     // queue are processed and when processing those results in new symbols 
01365     // needed, then they are again added to the queue. 
01366     
01367     // We start with the fact that we need the .start function. 
01368     // Anything else is walking the dependencies. 
01369     out->slabel_start.pfunc=NULL;
01370     _SQPush(&start_fn->f->slabel_start.se,NULL,LSymbol::SStart);
01371     
01372     // This is the main symbol lookup linker loop. 
01373     LSymbol ls;
01374     while(_SQPeek(ls))
01375     {
01376         Warning("Looking up %s...",ls.se->CompleteName().str());
01377         
01378         // So, we need symbol >ls<... 
01379         FileNode *definition_fn=NULL;
01380         if(ls.se->linked || ls.se->symref<0)
01381         {
01382             // Oops, an already linked symbol in the queue. 
01383             // Or, an internal symbol in the queue. 
01384             // Both these may not happen. 
01385             Assert(0);
01386         }
01387         else
01388         {
01389             // Only non-internal symbols here. 
01390             // The symbol must be in a namespace which must have been 
01391             // merged already. We actually did the latter above. 
01392             Assert(ls.se->nspc);
01393             NamespaceInfo *linked=ls.se->nspc->linked;
01394             Assert(linked);
01395             
01396             NamespaceInfo::SymbolEntryE *found=NULL;
01397             do {
01398                 // Go searching in the provide map. 
01399                 found=symbol_provide_map.lookup(ls.se);
01400                 if(found)
01401                 {
01402                     // Get the file in which the symbol is defined in. 
01403                     definition_fn=_GetDefinitionFile(found->nspc);
01404                     
01405                     // See if already linked. 
01406                     if(found->linked)
01407                     {
01408                         // Just update the link pointer so that we do not 
01409                         // look that up again. 
01410                         ls.se->linked=found->linked;  // WAS: found
01411                         
01412                         break;
01413                     }
01414                     
01415                     // We need the file in which the symbol is defined in 
01416                     // case we did not yet process it. This will put the 
01417                     // necessary things into the queue. 
01418                     _LinkerFileNeeded(definition_fn);
01419                     
01420                     // See if it is now linked (after calling 
01421                     // _LinkerFileNeeded() which will link the global vars). 
01422                     if(found->linked)
01423                     {
01424                         // Just update the link pointer so that we do not 
01425                         // look that up again. 
01426                         ls.se->linked=found->linked;  // WAS: found
01427                         
01428                         break;
01429                     }
01430                     
01431                     // Found, but not in master tree. 
01432                     // Add to our linked destination symbols. 
01433                     NamespaceInfo *master_parent=found->nspc->linked;
01434                     Assert(master_parent);
01435                     
01436                     // This will make a new copy of the SymbolEntryE for the 
01437                     // master tree: 
01438                     if(ls.sflag==LSymbol::SStart)
01439                     {
01440                         out->slabel_start.se=*found;  // C++ assignment
01441                         found=&out->slabel_start.se;
01442                     }
01443                     else
01444                     {
01445                         master_parent->symbol.PushHead(*found);
01446                         found=master_parent->symbol.head();
01447                     }
01448                     
01449                     // Update tree info for master tree: 
01450                     found->nspc=master_parent;
01451                     found->linked=NULL;   // (unused in master tree)
01452                     found->symref=ls.symref;
01453                     
01454                     // ...and "link" it: 
01455                     ls.se->linked=found;
01456                     
01457                     // Still add entry to the mapping: 
01458                     Assert(found->symref>=0);  // Non-internal ones, only. 
01459                     int _unused_ srv=master_parent->map_name2symbol.store(
01460                         found,/*allow_update=*/0);
01461                     // If this assert "legally" fails, then we need to replace 
01462                     // it with an error. 
01463                     Assert(!srv);
01464                     
01465                     if(!cfg.abandon_out_maps)
01466                     {
01467                         NamespaceInfo::SymbolEntryE _unused_ *known=
01468                             out->symref2symbol.AddNode(found);
01469                         Assert(!known);
01470                     }
01471                 }
01472                 
01473                 // (Try more possibilites for lookup here.) 
01474             } while(0);
01475             
01476             if(!found)
01477             {
01478                 Error(ls.se->nspc->asm_loc,"undefined symbol \"%s\"",
01479                     ls.se->CompleteName().str());
01480                 ++n_errors;
01481             }
01482         }
01483         
01484         // Update the symbol entry pointer if specified. We update with NULL 
01485         // in case resolving failed. 
01486         if(ls.update_se)
01487         {  *ls.update_se=ls.se->linked;  }
01488         
01489         // Now, remove symbol rom the queue. 
01490         _SQPop();
01491         
01492         if(!ls.se->linked)
01493         {
01494             // Symbol could not be found. Give up and take next one. 
01495             continue;
01496         }
01497         
01498         // We must know the file where the symbol is defined if we found it. 
01499         Assert(definition_fn);
01500         
01501         switch(ls.se->extid)
01502         {
01503             case NamespaceInfo::SymbolEntryE::ExtFunction:
01504             {
01505                 Warning(ls.se->nspc->asm_loc,"get code for function %s "
01506                     "(symref $%d)",
01507                     ls.se->CompleteName().str(),(int)ls.se->symref);
01508                 Warning(definition_fn->f->filename,"  looking in this file");
01509                 
01510                 // Get program code for function. 
01511                 ProgramStorage::Function *pfunc;
01512                 if(ls.se==&definition_fn->f->slabel_init.se)
01513                 {  pfunc=definition_fn->f->slabel_init.pfunc;  }
01514                 else if(ls.se==&definition_fn->f->slabel_start.se)
01515                 {  pfunc=definition_fn->f->slabel_start.pfunc;  }
01516                 else
01517                 {  pfunc=definition_fn->f->symref2function.lookup(
01518                     ls.se->symref);  }
01519                 
01520                 // The SymRef MUST be known...
01521                 Assert(pfunc);
01522                 
01523                 Assert(ls.se->linked->symref==ls.symref);
01524                 _LinkFunction(definition_fn,pfunc,ls.se->linked);
01525             }   break;
01526             case NamespaceInfo::SymbolEntryE::ExtVariable:
01527                 // Currently nothing to do. 
01528                 // The global storage has already been linked. 
01529                 if(ls.se->symref>=0)  // Only non-internal symbols. 
01530                 {  Assert(ls.se->linked->nspc->map_name2symbol.search(
01531                     ls.se->name));  }
01532                 //fprintf(stderr,"VAR SYMBOL: %s %d\n",
01533                 //  ls.se->name.str(),ls.symref);
01534                 break;
01535             default: Assert(0);
01536         }
01537     }
01538     
01539     if(n_errors)
01540     {
01541         Error("bailing out at stage 4 (resolve symbols)");
01542         return(n_errors);
01543     }
01544     
01545     if(out->nspc_root)
01546     {
01547         _PropagateUseFlags_Recursive(out->nspc_root);
01548         
01549         _CreateInitFunction();
01550     }
01551     
01552     // Warn user about not needed input files. 
01553     for(FileNode *fn=flist.first(); fn; fn=fn->next)
01554     {
01555         if(!fn->needed)
01556         {  Warning(fn->f->filename,"input file not needed");  }
01557     }
01558     
01559     // Produce a dump of the master namespace for debugging. 
01560     if(out->nspc_root)
01561     {
01562         StringTreeDump dump;
01563         out->nspc_root->DumpTree(dump,/*IDs_resolved=*/1);
01564         dump.write(stdout);
01565     }
01566     
01567     return(n_errors);
01568 }
01569 
01570 
01571 int VMLinker::AddFile(AssemblerFile *afile)
01572 {
01573     if(!afile)  return(0);
01574     
01575     FileNode *n=new FileNode(afile);
01576     flist.append(n);
01577     
01578     return(0);
01579 }
01580 
01581 
01582 VMLinker::VMLinker() : 
01583     cfg(),
01584     flist(),
01585     n_errors(0),
01586     sq(/*m=*/8),  // <-- 4 or 8 as we do lots of RemoveSmallest(). 
01587     master_TypeID_cnt(1),  // <-- start with 1
01588     master_SymRef_cnt(1),  // start with 1
01589     symbol_provide_map(/*m=16*/),
01590     out(NULL)
01591 {
01592     
01593 }
01594 
01595 VMLinker::~VMLinker()
01596 {
01597     // Delete output file if non-NULL. 
01598     DELETE(out);
01599     
01600     // Kill all files (and all their content). 
01601     while(!flist.IsEmpty())
01602     {  delete flist.PopFirst();  }
01603 }
01604 
01605 //------------------------------------------------------------------------------
01606 
01607 VMLinker::Config::Config()
01608 {
01609     ignore_simple_type_missing=0;
01610     abandon_out_maps=0;
01611 }
01612 
01613 }  // end of namespace VM
01614 
01615 
01616 #if 1  /* Small test program: "test linker" */
01617 
01618 #include <lib/message/manager.h>
01619 #include <lib/message/handler_console.h>
01620 #include <vm/input/tasm/tasm-file.h>
01621 
01622 
01623 static int _DoParseFile(const char *file,VM::AssemblerFile_Plaintext *asmfile,
01624     uint32 cnt)
01625 {
01626     SError error;
01627     
01628     int rv=asmfile->ParseFile(file,error,cnt);
01629     if(rv)
01630     {
01631         if(error)
01632         {  Error("parsing %s: %s",file,error.msg().str());  }
01633         else
01634         {  Error("%d lexer/parser errors",rv);  }
01635         return(1);
01636     }
01637     
01638     return(0);
01639 }
01640 
01641 int main(int argc,char **arg)
01642 {
01643     MessageManager::init();
01644     MessageHandler_Console cons_hdl(
01645         Message::MTAll,
01646         //Message::MTAllNonDebug,
01647         /*use_color=*/0);
01648     
01649     VM::VMLinker linker;
01650     
01651     int fail=0;
01652     for(int i=1; i<argc; i++)
01653     {
01654         VM::AssemblerFile_Plaintext *asmfile = 
01655             new VM::AssemblerFile_Plaintext();
01656         int rv=_DoParseFile(arg[i],asmfile,i);
01657         if(rv)
01658         {  DELETE(asmfile);  ++fail;  }
01659         else
01660         {  linker.AddFile(asmfile);  }
01661     }
01662     
01663     if(!fail)
01664     {
01665         VM::AssemblerFile *output=new VM::AssemblerFile_Plaintext();
01666         
01667         fail=linker.LinkAll(output);
01668         if(!fail)
01669         {
01670             SError error;
01671             fail=output->WriteFile("linker.out",error);
01672         }
01673     }
01674     
01675     MessageManager::cleanup();
01676     return(fail);
01677 }
01678 
01679 #endif

Generated on Sat Feb 19 22:33:47 2005 for Ray by doxygen 1.3.5