javac 概述
javac 是jdk bin目錄下的一個腳本。 用於編譯 java程序的源代碼,但是 其實現的本質 是基於 jdk 標准類庫中的 javac類庫實現,所以java的編譯器實質上是一個 java程序。
javac腳本 僅是一個便於啟動以及傳遞參數的腳本文件,其內部依舊運行了 java程序。
javac 又被稱作前端編譯器,僅負責 源代碼 與 字節碼之間的轉換,而在jvm內部 還存在 一個后置編譯器,根據熱點探測技術 可以將最有價值的 字節碼轉換為 機器碼執行從而提升java程序的運行效率。
javac 的意義就在於 將源碼編譯為字節碼,同時 做一些 詞法,語法,語義上的檢查,最后生成可供jvm運行的字節碼文件。
javac 源碼
在 lib 中的 tools jar 包中 sun.tools.javac; 包下管理者 java前端編譯器 的class文件。 Main 類 中的 main 方法的執行 是javac程序的執行入口。
1 public static void main(String args[]) 2 {
//將標准錯誤流獲取 3 PrintStream printstream = System.err; 4 if (Boolean.getBoolean("javac.pipe.output")) 5 printstream = System.out;
//創建 編譯器對象 6 Main main1 = new Main(printstream, "javac");
//調用編譯器的 compile方法進行 編譯 並接受 args 為參數,該參數就是 javac 后面攜帶的參數 7 System.exit(main1.compile(args) ? 0 : main1.exitStatus); 8 }
compile方法的 編譯過程 概括性的分析:
1.解析與填充符號表
解析: 對java源代碼的字節流進行讀取解析,進行兩個大致的步驟,詞法解析以及語法解析
詞法解析: 識別 java源碼中存在的表達語義的邏輯單元,列如 關鍵字 變量名 參數名 每一個邏輯單元 稱為 標量。
語法解析:將各個獨立的 標量按照java語法規范形成 java語法數,語法樹的每一個節點代表一個操作,運算,或者 方法調用。
填充符號表: 解析后的語法樹最頂級的節點將被用來填充在符號表中,符號表存儲着各個語法樹的最頂級節點,填充后的符號表最終形成 待處理表。
符號表就是一個遵從java語法的結構規范,用於組織語法樹的邏輯順序。
2.插入式注解處理器
jdk1.5后引入注解功能,注解是一種應用字節碼 屬性中類的元數據進行操作的一種編程機制。
處理表形成后 會自動檢測是否有注解器需要執行,若有則執行注解處理器。注解處理器實現了在可插入式的編譯期改變編譯過程的功能。
其本質就是 再次修改 處理表中的語法樹。 一旦語法樹被修改,則將再次進行 詞法,語法分析並填充符號表的過程。
3.語義分析並生成字節碼
語義分析: 再次對語法樹中的節點進行校驗。對數據類型以及控制邏輯進行檢測。
標量檢測: 檢驗關鍵字是否使用正確,類型轉換是否正確等。
數據與控制流分析: 對控制流程的邏輯進行校驗。
語法糖解析: 編程語言為了 增加代碼的可讀性,以及減少編程出錯率,提供了一些並不影響程序運行期僅在編譯期有效的編程機制。
java語言中語法糖 有 泛型,拆箱與裝箱,foreach循環,可變參數,switch,枚舉等,在編譯期將轉換為字節碼遵守的規范形式。
泛型使用類型擦出,拆裝箱調用了valueOf與xxValue方法,foreach是迭代器 可變參數是數組,switch本質是 if else 的嵌套。
字節碼替換: 在生成類的字節碼之時,編譯器后做一些默認性質的操作,當沒有顯示聲明的構造器,則會創建默認的無參構造器,構造器分為 實例構造器與類構造器
在字節碼層面 類構造器 是指多個static代碼塊中的語句 收斂生成的<cinit>指令。而構造代碼塊與顯示的構造器將收斂生成實例構造器。
同時還會將 String類型的 +與+= 操作,默認替換為 對 StringBuffer或 StrignBudiuer的操作。
最后生成字節碼。
代碼如下:
1 public synchronized boolean compile(String as[]) 2 { 3 String s = null; 4 String s1 = null; 5 String s2 = null; 6 String s3 = null; 7 boolean flag = false; 8 String s4 = null; 9 short word0 = 45; 10 short word1 = 3; 11 File file = null; 12 File file1 = null; 13 String s5 = "-Xjcov"; 14 String s6 = "-Xjcov:file="; 15 int i = 0x41004; 16 long l = System.currentTimeMillis(); 17 Vector vector = new Vector(); 18 boolean flag1 = false; 19 Object obj = null; 20 String s7 = null; 21 String s8 = null; 22 String s9 = null; 23 exitStatus = 0; 24 try 25 { 26 as = CommandLine.parse(as); 27 } 28 catch (FileNotFoundException filenotfoundexception) 29 { 30 error("javac.err.cant.read", filenotfoundexception.getMessage()); 31 System.exit(1); 32 } 33 catch (IOException ioexception) 34 { 35 ioexception.printStackTrace(); 36 System.exit(1); 37 } 38 label0: 39 for (int j = 0; j < as.length; j++) 40 { 41 if (as[j].equals("-g")) 42 { 43 if (s8 != null && !s8.equals("-g")) 44 error("main.conflicting.options", s8, "-g"); 45 s8 = "-g"; 46 i |= 0x1000; 47 i |= 0x2000; 48 i |= 0x40000; 49 continue; 50 } 51 if (as[j].equals("-g:none")) 52 { 53 if (s8 != null && !s8.equals("-g:none")) 54 error("main.conflicting.options", s8, "-g:none"); 55 s8 = "-g:none"; 56 i &= 0xffffefff; 57 i &= 0xffffdfff; 58 i &= 0xfffbffff; 59 continue; 60 } 61 if (as[j].startsWith("-g:")) 62 { 63 if (s8 != null && !s8.equals(as[j])) 64 error("main.conflicting.options", s8, as[j]); 65 s8 = as[j]; 66 String s10 = as[j].substring("-g:".length()); 67 i &= 0xffffefff; 68 i &= 0xffffdfff; 69 i &= 0xfffbffff; 70 do 71 { 72 do 73 { 74 if (s10.startsWith("lines")) 75 { 76 i |= 0x1000; 77 s10 = s10.substring("lines".length()); 78 } else 79 if (s10.startsWith("vars")) 80 { 81 i |= 0x2000; 82 s10 = s10.substring("vars".length()); 83 } else 84 if (s10.startsWith("source")) 85 { 86 i |= 0x40000; 87 s10 = s10.substring("source".length()); 88 } else 89 { 90 error("main.bad.debug.option", as[j]); 91 usage_error(); 92 return false; 93 } 94 if (s10.length() == 0) 95 continue label0; 96 } while (!s10.startsWith(",")); 97 s10 = s10.substring(",".length()); 98 } while (true); 99 } 100 if (as[j].equals("-O")) 101 { 102 if (s9 != null && !s9.equals("-O")) 103 error("main.conflicting.options", s9, "-O"); 104 s9 = "-O"; 105 continue; 106 } 107 if (as[j].equals("-nowarn")) 108 { 109 i &= -5; 110 continue; 111 } 112 if (as[j].equals("-deprecation")) 113 { 114 i |= 0x200; 115 continue; 116 } 117 if (as[j].equals("-verbose")) 118 { 119 i |= 1; 120 continue; 121 } 122 if (as[j].equals("-nowrite")) 123 { 124 flag1 = true; 125 continue; 126 } 127 if (as[j].equals("-classpath")) 128 { 129 if (j + 1 < as.length) 130 { 131 if (s1 != null) 132 error("main.option.already.seen", "-classpath"); 133 s1 = as[++j]; 134 } else 135 { 136 error("main.option.requires.argument", "-classpath"); 137 usage_error(); 138 return false; 139 } 140 continue; 141 } 142 if (as[j].equals("-sourcepath")) 143 { 144 if (j + 1 < as.length) 145 { 146 if (s != null) 147 error("main.option.already.seen", "-sourcepath"); 148 s = as[++j]; 149 } else 150 { 151 error("main.option.requires.argument", "-sourcepath"); 152 usage_error(); 153 return false; 154 } 155 continue; 156 } 157 if (as[j].equals("-sysclasspath")) 158 { 159 if (j + 1 < as.length) 160 { 161 if (s2 != null) 162 error("main.option.already.seen", "-sysclasspath"); 163 s2 = as[++j]; 164 } else 165 { 166 error("main.option.requires.argument", "-sysclasspath"); 167 usage_error(); 168 return false; 169 } 170 continue; 171 } 172 if (as[j].equals("-bootclasspath")) 173 { 174 if (j + 1 < as.length) 175 { 176 if (s2 != null) 177 error("main.option.already.seen", "-bootclasspath"); 178 s2 = as[++j]; 179 } else 180 { 181 error("main.option.requires.argument", "-bootclasspath"); 182 usage_error(); 183 return false; 184 } 185 continue; 186 } 187 if (as[j].equals("-extdirs")) 188 { 189 if (j + 1 < as.length) 190 { 191 if (s3 != null) 192 error("main.option.already.seen", "-extdirs"); 193 s3 = as[++j]; 194 } else 195 { 196 error("main.option.requires.argument", "-extdirs"); 197 usage_error(); 198 return false; 199 } 200 continue; 201 } 202 if (as[j].equals("-encoding")) 203 { 204 if (j + 1 < as.length) 205 { 206 if (s7 != null) 207 error("main.option.already.seen", "-encoding"); 208 s7 = as[++j]; 209 } else 210 { 211 error("main.option.requires.argument", "-encoding"); 212 usage_error(); 213 return false; 214 } 215 continue; 216 } 217 if (as[j].equals("-target")) 218 { 219 if (j + 1 < as.length) 220 { 221 if (s4 != null) 222 error("main.option.already.seen", "-target"); 223 s4 = as[++j]; 224 int k = 0; 225 do 226 { 227 if (k >= releases.length) 228 break; 229 if (releases[k].equals(s4)) 230 { 231 word0 = majorVersions[k]; 232 word1 = minorVersions[k]; 233 break; 234 } 235 k++; 236 } while (true); 237 if (k == releases.length) 238 { 239 error("main.unknown.release", s4); 240 usage_error(); 241 return false; 242 } 243 } else 244 { 245 error("main.option.requires.argument", "-target"); 246 usage_error(); 247 return false; 248 } 249 continue; 250 } 251 if (as[j].equals("-d")) 252 { 253 if (j + 1 < as.length) 254 { 255 if (file != null) 256 error("main.option.already.seen", "-d"); 257 file = new File(as[++j]); 258 if (!file.exists()) 259 { 260 error("main.no.such.directory", file.getPath()); 261 usage_error(); 262 return false; 263 } 264 } else 265 { 266 error("main.option.requires.argument", "-d"); 267 usage_error(); 268 return false; 269 } 270 continue; 271 } 272 if (as[j].equals(s5)) 273 { 274 i |= 0x40; 275 i &= 0xffffbfff; 276 i &= 0xffff7fff; 277 continue; 278 } 279 if (as[j].startsWith(s6) && as[j].length() > s6.length()) 280 { 281 file1 = new File(as[j].substring(s6.length())); 282 i &= 0xffffbfff; 283 i &= 0xffff7fff; 284 i |= 0x40; 285 i |= 0x80; 286 continue; 287 } 288 if (as[j].equals("-XO")) 289 { 290 if (s9 != null && !s9.equals("-XO")) 291 error("main.conflicting.options", s9, "-XO"); 292 s9 = "-XO"; 293 i |= 0x4000; 294 continue; 295 } 296 if (as[j].equals("-Xinterclass")) 297 { 298 if (s9 != null && !s9.equals("-Xinterclass")) 299 error("main.conflicting.options", s9, "-Xinterclass"); 300 s9 = "-Xinterclass"; 301 i |= 0x4000; 302 i |= 0x8000; 303 i |= 0x20; 304 continue; 305 } 306 if (as[j].equals("-Xdepend")) 307 { 308 i |= 0x20; 309 continue; 310 } 311 if (as[j].equals("-Xdebug")) 312 { 313 i |= 2; 314 continue; 315 } 316 if (as[j].equals("-xdepend") || as[j].equals("-Xjws")) 317 { 318 i |= 0x400; 319 if (out == System.err) 320 out = System.out; 321 continue; 322 } 323 if (as[j].equals("-Xstrictdefault")) 324 { 325 i |= 0x20000; 326 continue; 327 } 328 if (as[j].equals("-Xverbosepath")) 329 { 330 flag = true; 331 continue; 332 } 333 if (as[j].equals("-Xstdout")) 334 { 335 out = System.out; 336 continue; 337 } 338 if (as[j].equals("-X")) 339 { 340 error("main.unsupported.usage"); 341 return false; 342 } 343 if (as[j].equals("-Xversion1.2")) 344 { 345 i |= 0x800; 346 continue; 347 } 348 if (as[j].endsWith(".java")) 349 { 350 vector.addElement(as[j]); 351 } else 352 { 353 error("main.no.such.option", as[j]); 354 usage_error(); 355 return false; 356 } 357 } 358 359 if (vector.size() == 0 || exitStatus == 2) 360 { 361 usage_error(); 362 return false; 363 } 364 BatchEnvironment batchenvironment = BatchEnvironment.create(out, s, s1, s2, s3); 365 if (flag) 366 output(getText("main.path.msg", batchenvironment.sourcePath.toString(), batchenvironment.binaryPath.toString())); 367 batchenvironment.flags |= i; 368 batchenvironment.majorVersion = word0; 369 batchenvironment.minorVersion = word1; 370 batchenvironment.covFile = file1; 371 batchenvironment.setCharacterEncoding(s7); 372 String s11 = getText("main.no.memory"); 373 String s12 = getText("main.stack.overflow"); 374 batchenvironment.error(0L, "warn.class.is.deprecated", "sun.tools.javac.Main"); 375 try 376 { 377 for (Enumeration enumeration = vector.elements(); enumeration.hasMoreElements();) 378 { 379 File file2 = new File((String)enumeration.nextElement()); 380 try 381 { 382 batchenvironment.parseFile(new ClassFile(file2)); 383 } 384 catch (FileNotFoundException filenotfoundexception1) 385 { 386 batchenvironment.error(0L, "cant.read", file2.getPath()); 387 exitStatus = 2; 388 } 389 } 390 391 Object obj1 = batchenvironment.getClasses(); 392 do 393 { 394 if (!((Enumeration) (obj1)).hasMoreElements()) 395 break; 396 ClassDeclaration classdeclaration = (ClassDeclaration)((Enumeration) (obj1)).nextElement(); 397 if (classdeclaration.getStatus() == 4 && !classdeclaration.getClassDefinition().isLocal()) 398 try 399 { 400 classdeclaration.getClassDefinition(batchenvironment); 401 } 402 catch (ClassNotFound classnotfound) { } 403 } while (true); 404 obj1 = new ByteArrayOutputStream(4096); 405 boolean flag2; 406 do 407 { 408 flag2 = true; 409 batchenvironment.flushErrors(); 410 Enumeration enumeration1 = batchenvironment.getClasses(); 411 do 412 { 413 if (!enumeration1.hasMoreElements()) 414 break; 415 ClassDeclaration classdeclaration1 = (ClassDeclaration)enumeration1.nextElement(); 416 switch (classdeclaration1.getStatus()) 417 { 418 case 1: // '\001' 419 case 2: // '\002' 420 default: 421 break; 422 423 case 0: // '\0' 424 if (!batchenvironment.dependencies()) 425 continue; 426 // fall through 427 428 case 3: // '\003' 429 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (SOURCE): loading, ").append(classdeclaration1).toString()); 430 flag2 = false; 431 batchenvironment.loadDefinition(classdeclaration1); 432 if (classdeclaration1.getStatus() != 4) 433 { 434 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (SOURCE): not parsed, ").append(classdeclaration1).toString()); 435 continue; 436 } 437 // fall through 438 439 case 4: // '\004' 440 if (classdeclaration1.getClassDefinition().isInsideLocal()) 441 { 442 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (PARSED): skipping local class, ").append(classdeclaration1).toString()); 443 continue; 444 } 445 flag2 = false; 446 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (PARSED): checking, ").append(classdeclaration1).toString()); 447 SourceClass sourceclass = (SourceClass)classdeclaration1.getClassDefinition(batchenvironment); 448 sourceclass.check(batchenvironment); 449 classdeclaration1.setDefinition(sourceclass, 5); 450 // fall through 451 452 case 5: // '\005' 453 SourceClass sourceclass1 = (SourceClass)classdeclaration1.getClassDefinition(batchenvironment); 454 if (sourceclass1.getError()) 455 { 456 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (CHECKED): bailing out on error, ").append(classdeclaration1).toString()); 457 classdeclaration1.setDefinition(sourceclass1, 6); 458 continue; 459 } 460 flag2 = false; 461 ((ByteArrayOutputStream) (obj1)).reset(); 462 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (CHECKED): compiling, ").append(classdeclaration1).toString()); 463 sourceclass1.compile(((OutputStream) (obj1))); 464 classdeclaration1.setDefinition(sourceclass1, 6); 465 sourceclass1.cleanup(batchenvironment); 466 if (sourceclass1.getNestError() || flag1) 467 continue; 468 String s14 = classdeclaration1.getName().getQualifier().toString().replace('.', File.separatorChar); 469 String s15 = (new StringBuilder()).append(classdeclaration1.getName().getFlatName().toString().replace('.', '$')).append(".class").toString(); 470 File file3; 471 if (file != null) 472 { 473 if (s14.length() > 0) 474 { 475 file3 = new File(file, s14); 476 if (!file3.exists()) 477 file3.mkdirs(); 478 file3 = new File(file3, s15); 479 } else 480 { 481 file3 = new File(file, s15); 482 } 483 } else 484 { 485 ClassFile classfile = (ClassFile)sourceclass1.getSource(); 486 if (classfile.isZipped()) 487 { 488 batchenvironment.error(0L, "cant.write", classfile.getPath()); 489 exitStatus = 2; 490 continue; 491 } 492 file3 = new File(classfile.getPath()); 493 file3 = new File(file3.getParent(), s15); 494 } 495 try 496 { 497 FileOutputStream fileoutputstream = new FileOutputStream(file3.getPath()); 498 ((ByteArrayOutputStream) (obj1)).writeTo(fileoutputstream); 499 fileoutputstream.close(); 500 if (batchenvironment.verbose()) 501 output(getText("main.wrote", file3.getPath())); 502 } 503 catch (IOException ioexception1) 504 { 505 batchenvironment.error(0L, "cant.write", file3.getPath()); 506 exitStatus = 2; 507 } 508 if (batchenvironment.print_dependencies()) 509 sourceclass1.printClassDependencies(batchenvironment); 510 break; 511 } 512 } while (true); 513 } while (!flag2); 514 } 515 catch (OutOfMemoryError outofmemoryerror) 516 { 517 batchenvironment.output(s11); 518 exitStatus = 3; 519 return false; 520 } 521 catch (StackOverflowError stackoverflowerror) 522 { 523 batchenvironment.output(s12); 524 exitStatus = 3; 525 return false; 526 } 527 catch (Error error1) 528 { 529 if (batchenvironment.nerrors == 0 || batchenvironment.dump()) 530 { 531 error1.printStackTrace(); 532 batchenvironment.error(0L, "fatal.error"); 533 exitStatus = 4; 534 } 535 } 536 catch (Exception exception) 537 { 538 if (batchenvironment.nerrors == 0 || batchenvironment.dump()) 539 { 540 exception.printStackTrace(); 541 batchenvironment.error(0L, "fatal.exception"); 542 exitStatus = 4; 543 } 544 } 545 int i1 = batchenvironment.deprecationFiles.size(); 546 if (i1 > 0 && batchenvironment.warnings()) 547 { 548 int j1 = batchenvironment.ndeprecations; 549 Object obj2 = batchenvironment.deprecationFiles.elementAt(0); 550 if (batchenvironment.deprecation()) 551 { 552 if (i1 > 1) 553 batchenvironment.error(0L, "warn.note.deprecations", new Integer(i1), new Integer(j1)); 554 else 555 batchenvironment.error(0L, "warn.note.1deprecation", obj2, new Integer(j1)); 556 } else 557 if (i1 > 1) 558 batchenvironment.error(0L, "warn.note.deprecations.silent", new Integer(i1), new Integer(j1)); 559 else 560 batchenvironment.error(0L, "warn.note.1deprecation.silent", obj2, new Integer(j1)); 561 } 562 batchenvironment.flushErrors(); 563 batchenvironment.shutdown(); 564 boolean flag3 = true; 565 if (batchenvironment.nerrors > 0) 566 { 567 String s13 = ""; 568 if (batchenvironment.nerrors > 1) 569 s13 = getText("main.errors", batchenvironment.nerrors); 570 else 571 s13 = getText("main.1error"); 572 if (batchenvironment.nwarnings > 0) 573 if (batchenvironment.nwarnings > 1) 574 s13 = (new StringBuilder()).append(s13).append(", ").append(getText("main.warnings", batchenvironment.nwarnings)).toString(); 575 else 576 s13 = (new StringBuilder()).append(s13).append(", ").append(getText("main.1warning")).toString(); 577 output(s13); 578 if (exitStatus == 0) 579 exitStatus = 1; 580 flag3 = false; 581 } else 582 if (batchenvironment.nwarnings > 0) 583 if (batchenvironment.nwarnings > 1) 584 output(getText("main.warnings", batchenvironment.nwarnings)); 585 else 586 output(getText("main.1warning")); 587 if (batchenvironment.covdata()) 588 { 589 Assembler assembler = new Assembler(); 590 assembler.GenJCov(batchenvironment); 591 } 592 if (batchenvironment.verbose()) 593 { 594 l = System.currentTimeMillis() - l; 595 output(getText("main.done_in", Long.toString(l))); 596 } 597 return flag3; 598 }
