1 /* 2 * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 import java.io.*; 26 import java.util.*; 27 28 public class Database { 29 private MacroDefinitions macros; 30 // allFiles is kept in lexicographically sorted order. See get(). 31 private FileList allFiles; 32 // files that have implicit dependency on platform files 33 // e.g. os.hpp: os_<os_family>.hpp os_<os_arch>.hpp but only 34 // recorded if the platform file was seen. 35 private FileList platformFiles; 36 private FileList outerFiles; 37 private FileList indivIncludes; 38 private FileList grandInclude; // the results for the grand include file 39 private HashMap<String,String> platformDepFiles; 40 private long threshold; 41 private int nOuterFiles; 42 private boolean missingOk; 43 private Platform plat; 44 /** These allow you to specify files not in the include database 45 which are prepended and appended to the file list, allowing 46 you to have well-known functions at the start and end of the 47 text segment (allows us to find out in a portable fashion 48 whether the current PC is in VM code or not upon a crash) */ 49 private String firstFile; 50 private String lastFile; 51 52 public Database(Platform plat, long t) { 53 this.plat = plat; 54 macros = new MacroDefinitions(); 55 allFiles = new FileList("allFiles", plat); 56 platformFiles = new FileList("platformFiles", plat); 57 outerFiles = new FileList("outerFiles", plat); 58 indivIncludes = new FileList("IndivIncludes", plat); 59 grandInclude = new FileList(plat.getGIFileTemplate().nameOfList(), plat); 60 platformDepFiles = new HashMap<String,String>(); 61 62 threshold = t; 63 nOuterFiles = 0; 64 missingOk = false; 65 firstFile = null; 66 lastFile = null; 67 }; 68 69 public FileList getAllFiles() { 70 return allFiles; 71 } 72 73 public Iterator getMacros() { 74 return macros.getMacros(); 75 } 76 77 public void canBeMissing() { 78 missingOk = true; 79 } 80 81 public boolean hfileIsInGrandInclude(FileList hfile, FileList cfile) { 82 return ((hfile.getCount() >= threshold) && (cfile.getUseGrandInclude())); 83 } 84 85 /** These allow you to specify files not in the include database 86 which are prepended and appended to the file list, allowing 87 you to have well-known functions at the start and end of the 88 text segment (allows us to find out in a portable fashion 89 whether the current PC is in VM code or not upon a crash) */ 90 public void setFirstFile(String fileName) { 91 firstFile = fileName; 92 } 93 94 public void setLastFile(String fileName) { 95 lastFile = fileName; 96 } 97 98 public void get(String platFileName, String dbFileName) 99 throws FileFormatException, IOException, FileNotFoundException { 100 macros.readFrom(platFileName, missingOk); 101 102 BufferedReader reader = null; 103 try { 104 reader = new BufferedReader(new FileReader(dbFileName)); 105 } catch (FileNotFoundException e) { 106 if (missingOk) { 107 return; 108 } else { 109 throw(e); 110 } 111 } 112 System.out.println("\treading database: " + dbFileName); 113 String line; 114 int lineNo = 0; 115 do { 116 line = reader.readLine(); 117 lineNo++; 118 if (line != null) { 119 StreamTokenizer tokenizer = 120 new StreamTokenizer(new StringReader(line)); 121 tokenizer.slashSlashComments(true); 122 tokenizer.wordChars('_', '_'); 123 tokenizer.wordChars('<', '>'); 124 // NOTE: if we didn't have to do this line by line, 125 // we could trivially recognize C-style comments as 126 // well. 127 // tokenizer.slashStarComments(true); 128 int numTok = 0; 129 int res; 130 String unexpandedIncluder = null; 131 String unexpandedIncludee = null; 132 do { 133 res = tokenizer.nextToken(); 134 if (res != StreamTokenizer.TT_EOF) { 135 if (numTok == 0) { 136 unexpandedIncluder = tokenizer.sval; 137 } else if (numTok == 1) { 138 unexpandedIncludee = tokenizer.sval; 139 } else { 140 throw new FileFormatException( 141 "invalid line: \"" + line + 142 "\". Error position: line " + lineNo 143 ); 144 } 145 numTok++; 146 } 147 } while (res != StreamTokenizer.TT_EOF); 148 149 if ((numTok != 0) && (numTok != 2)) { 150 throw new FileFormatException( 151 "invalid line: \"" + line + 152 "\". Error position: line " + lineNo 153 ); 154 } 155 156 if (numTok == 2) { 157 // Non-empty line 158 String includer = macros.expand(unexpandedIncluder); 159 String includee = macros.expand(unexpandedIncludee); 160 161 if (includee.equals(plat.generatePlatformDependentInclude())) { 162 MacroDefinitions localExpander = macros.copy(); 163 MacroDefinitions localExpander2 = macros.copy(); 164 localExpander.setAllMacroBodiesTo("pd"); 165 localExpander2.setAllMacroBodiesTo(""); 166 167 // unexpanded_includer e.g. thread_<os_arch>.hpp 168 // thread_solaris_i486.hpp -> _thread_pd.hpp.incl 169 170 FileName pdName = 171 plat.getInclFileTemplate().copyStem( 172 localExpander.expand(unexpandedIncluder) 173 ); 174 175 // derive generic name from platform specific name 176 // e.g. os_<arch_os>.hpp => os.hpp. We enforce the 177 // restriction (imperfectly) noted in includeDB_core 178 // that platform specific files will have an underscore 179 // preceding the macro invocation. 180 181 // First expand macro as null string. 182 183 String newIncluder_temp = 184 localExpander2.expand(unexpandedIncluder); 185 186 // Now find "_." and remove the underscore. 187 188 String newIncluder = ""; 189 190 int len = newIncluder_temp.length(); 191 int count = 0; 192 193 for ( int i = 0; i < len - 1 ; i++ ) { 194 if (newIncluder_temp.charAt(i) == '_' && newIncluder_temp.charAt(i+1) == '.') { 195 count++; 196 } else { 197 newIncluder += newIncluder_temp.charAt(i); 198 } 199 } 200 newIncluder += newIncluder_temp.charAt(len-1); 201 202 if (count != 1) { 203 throw new FileFormatException( 204 "Unexpected filename format for platform dependent file.\nline: \"" + line + 205 "\".\nError position: line " + lineNo 206 ); 207 } 208 209 FileList p = allFiles.listForFile(includer); 210 p.setPlatformDependentInclude(pdName.dirPreStemSuff()); 211 212 // Record the implicit include of this file so that the 213 // dependencies for precompiled headers can mention it. 214 platformDepFiles.put(newIncluder, includer); 215 216 // Add an implicit dependency on platform 217 // specific file for the generic file 218 219 p = platformFiles.listForFile(newIncluder); 220 221 // if this list is empty then this is 1st 222 // occurance of a platform dependent file and 223 // we need a new version of the include file. 224 // Otherwise we just append to the current 225 // file. 226 227 PrintWriter pdFile = 228 new PrintWriter( 229 new FileWriter(pdName.dirPreStemSuff(), 230 !p.isEmpty()) 231 ); 232 pdFile.println("# include \"" + includer + "\""); 233 pdFile.close(); 234 235 // Add the platform specific file to the list 236 // for this generic file. 237 238 FileList q = allFiles.listForFile(includer); 239 p.addIfAbsent(q); 240 } else { 241 FileList p = allFiles.listForFile(includer); 242 if (isOuterFile(includer)) 243 outerFiles.addIfAbsent(p); 244 245 if (includee.equals(plat.noGrandInclude())) { 246 p.setUseGrandInclude(false); 247 } else { 248 FileList q = allFiles.listForFile(includee); 249 p.addIfAbsent(q); 250 } 251 } 252 } 253 } 254 } while (line != null); 255 reader.close(); 256 257 // Keep allFiles in well-known order so we can easily determine 258 // whether the known files are the same 259 allFiles.sortByName(); 260 261 // Add first and last files differently to prevent a mistake 262 // in ordering in the include databases from breaking the 263 // error reporting in the VM. 264 if (firstFile != null) { 265 FileList p = allFiles.listForFile(firstFile); 266 allFiles.setFirstFile(p); 267 outerFiles.setFirstFile(p); 268 } 269 270 if (lastFile != null) { 271 FileList p = allFiles.listForFile(lastFile); 272 allFiles.setLastFile(p); 273 outerFiles.setLastFile(p); 274 } 275 } 276 277 public void compute() { 278 System.out.println("\tcomputing closures\n"); 279 // build both indiv and grand results 280 for (Iterator iter = outerFiles.iterator(); iter.hasNext(); ) { 281 indivIncludes.add(((FileList) iter.next()).doCFile()); 282 ++nOuterFiles; 283 } 284 285 if (!plat.haveGrandInclude()) 286 return; // nothing in grand include 287 288 // count how many times each include is included & add em to grand 289 for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) { 290 FileList indivInclude = (FileList) iter.next(); 291 if (!indivInclude.getUseGrandInclude()) { 292 continue; // do not bump count if my files cannot be 293 // in grand include 294 } 295 indivInclude.doFiles(grandInclude); // put em on 296 // grand_include list 297 for (Iterator incListIter = indivInclude.iterator(); 298 incListIter.hasNext(); ) { 299 ((FileList) incListIter.next()).incrementCount(); 300 } 301 } 302 } 303 304 // Not sure this is necessary in Java 305 public void verify() { 306 for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) { 307 if (iter.next() == null) { 308 plat.abort(); 309 } 310 } 311 } 312 313 public void put() throws IOException { 314 writeIndividualIncludes(); 315 316 if (plat.haveGrandInclude()) 317 writeGrandInclude(); 318 319 writeGrandUnixMakefile(); 320 } 321 322 private void writeIndividualIncludes() throws IOException { 323 System.out.println("\twriting individual include files\n"); 324 325 for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) { 326 FileList list = (FileList) iter.next(); 327 System.out.println("\tcreating " + list.getName()); 328 list.putInclFile(this); 329 } 330 } 331 332 private void writeGrandInclude() throws IOException { 333 System.out.println("\twriting grand include file\n"); 334 PrintWriter inclFile = 335 new PrintWriter(new FileWriter(plat.getGIFileTemplate().dirPreStemSuff())); 336 plat.writeGIPragma(inclFile); 337 for (Iterator iter = grandInclude.iterator(); iter.hasNext(); ) { 338 FileList list = (FileList) iter.next(); 339 if (list.getCount() >= threshold) { 340 inclFile.println("# include \"" + 341 plat.getGIFileTemplate().getInvDir() + 342 list.getName() + 343 "\""); 344 } 345 } 346 inclFile.println(); 347 inclFile.close(); 348 } 349 350 private void writeGrandUnixMakefile() throws IOException { 351 if (!plat.writeDeps()) 352 return; 353 354 System.out.println("\twriting dependencies file\n"); 355 PrintWriter gd = 356 new PrintWriter(new FileWriter( 357 plat.getGDFileTemplate().dirPreStemSuff()) 358 ); 359 gd.println("# generated by makeDeps"); 360 gd.println(); 361 362 363 // HACK ALERT. The compilation of ad_<arch> files is very slow. 364 // We want to start compiling them as early as possible. The compilation 365 // order on unix is dependent on the order we emit files here. 366 // By sorting the output before emitting it, we expect 367 // that ad_<arch> will be compiled early. 368 boolean shouldSortObjFiles = true; 369 370 if (shouldSortObjFiles) { 371 ArrayList sortList = new ArrayList(); 372 373 // We need to preserve the ordering of the first and last items 374 // in outerFiles. 375 int size = outerFiles.size() - 1; 376 String firstName = removeSuffixFrom(((FileList)outerFiles.get(0)).getName()); 377 String lastName = removeSuffixFrom(((FileList)outerFiles.get(size)).getName()); 378 379 for (int i=1; i<size; i++) { 380 FileList anOuterFile = (FileList)outerFiles.get(i); 381 String stemName = removeSuffixFrom(anOuterFile.getName()); 382 sortList.add(stemName); 383 } 384 Collections.sort(sortList); 385 386 // write Obj_Files = ... 387 gd.println("Obj_Files = \\"); 388 gd.println(firstName + plat.objFileSuffix() + " \\"); 389 for (Iterator iter = sortList.iterator(); iter.hasNext(); ) { 390 gd.println(iter.next() + plat.objFileSuffix() + " \\"); 391 } 392 gd.println(lastName + plat.objFileSuffix() + " \\"); 393 gd.println(); 394 gd.println(); 395 } else { 396 // write Obj_Files = ... 397 gd.println("Obj_Files = \\"); 398 for (Iterator iter = outerFiles.iterator(); iter.hasNext(); ) { 399 FileList anOuterFile = (FileList) iter.next(); 400 401 String stemName = removeSuffixFrom(anOuterFile.getName()); 402 gd.println(stemName + plat.objFileSuffix() + " \\"); 403 } 404 gd.println(); 405 gd.println(); 406 } 407 408 // write Precompiled_Files = ... 409 gd.println("Precompiled_Files = \\"); 410 for (Iterator iter = grandInclude.iterator(); iter.hasNext(); ) { 411 FileList list = (FileList) iter.next(); 412 if (list.getCount() >= threshold) { 413 gd.println(list.getName() + " \\"); 414 String platformDep = platformDepFiles.get(list.getName()); 415 if (platformDep != null) { 416 // make sure changes to the platform dependent file will 417 // cause regeneration of the pch file. 418 gd.println(platformDep + " \\"); 419 } 420 } 421 } 422 gd.println(); 423 gd.println(); 424 425 gd.println("DTraced_Files = \\"); 426 for (Iterator iter = outerFiles.iterator(); iter.hasNext(); ) { 427 FileList anOuterFile = (FileList) iter.next(); 428 429 if (anOuterFile.hasListForFile("dtrace.hpp")) { 430 String stemName = removeSuffixFrom(anOuterFile.getName()); 431 gd.println(stemName + plat.objFileSuffix() + " \\"); 432 } 433 } 434 gd.println(); 435 gd.println(); 436 437 { 438 // write each dependency 439 440 for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) { 441 442 FileList anII = (FileList) iter.next(); 443 444 String stemName = removeSuffixFrom(anII.getName()); 445 String inclFileName = 446 plat.getInclFileTemplate().copyStem(anII.getName()). 447 preStemSuff(); 448 449 gd.println(stemName + plat.objFileSuffix() + " " + 450 stemName + plat.asmFileSuffix() + ": \\"); 451 452 printDependentOn(gd, anII.getName()); 453 // this gets the include file that includes all that 454 // this file needs (first level) since nested includes 455 // are skipped to avoid cycles. 456 printDependentOn(gd, inclFileName); 457 458 if ( plat.haveGrandInclude() ) { 459 printDependentOn(gd, 460 plat.getGIFileTemplate().preStemSuff()); 461 } 462 463 for (Iterator iiIter = anII.iterator(); iiIter.hasNext(); ) { 464 FileList hfile = (FileList) iiIter.next(); 465 if (!hfileIsInGrandInclude(hfile, anII) || 466 plat.writeDependenciesOnHFilesFromGI()) { 467 printDependentOn(gd, hfile.getName()); 468 } 469 if (platformFiles.hasListForFile(hfile.getName())) { 470 FileList p = 471 platformFiles.listForFile(hfile.getName());; 472 for (Iterator hiIter = p.iterator(); 473 hiIter.hasNext(); ) { 474 FileList hi2 = (FileList) hiIter.next(); 475 if (!hfileIsInGrandInclude(hi2, p)) { 476 printDependentOn(gd, hi2.getName()); 477 } 478 } 479 } 480 } 481 482 if (plat.includeGIDependencies() 483 && anII.getUseGrandInclude()) { 484 gd.println(" $(Precompiled_Files) \\"); 485 } 486 gd.println(); 487 gd.println(); 488 } 489 } 490 491 gd.close(); 492 } 493 494 public void putDiffs(Database previous) throws IOException { 495 System.out.println("\tupdating output files\n"); 496 497 if (!indivIncludes.compareLists(previous.indivIncludes) 498 || !grandInclude.compareLists(previous.grandInclude)) { 499 System.out.println("The order of .c or .s has changed, or " + 500 "the grand include file has changed."); 501 put(); 502 return; 503 } 504 505 Iterator curIter = indivIncludes.iterator(); 506 Iterator prevIter = previous.indivIncludes.iterator(); 507 508 try { 509 while (curIter.hasNext()) { 510 FileList newCFileList = (FileList) curIter.next(); 511 FileList prevCFileList = (FileList) prevIter.next(); 512 if (!newCFileList.compareLists(prevCFileList)) { 513 System.out.println("\tupdating " + newCFileList.getName()); 514 newCFileList.putInclFile(this); 515 } 516 } 517 } 518 catch (Exception e) { 519 throw new InternalError("assertion failure: cur and prev " + 520 "database lists changed unexpectedly."); 521 } 522 523 writeGrandUnixMakefile(); 524 } 525 526 private void printDependentOn(PrintWriter gd, String name) { 527 gd.print(" "); 528 gd.print(plat.dependentPrefix() + name); 529 } 530 531 private boolean isOuterFile(String s) { 532 int len = s.length(); 533 String[] suffixes = plat.outerSuffixes(); 534 for (int i = 0; i < suffixes.length; i++) { 535 String suffix = suffixes[i]; 536 int suffLen = suffix.length(); 537 if ((len >= suffLen) && 538 (plat.fileNameStringEquality(s.substring(len - suffLen), 539 suffix))) { 540 return true; 541 } 542 } 543 return false; 544 } 545 546 private String removeSuffixFrom(String s) { 547 int idx = s.lastIndexOf('.'); 548 if (idx <= 0) 549 plat.abort(); 550 return s.substring(0, idx); 551 } 552 }