javac 实现原理

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     }

 

posted on 2017-11-19 20:31  邱心  阅读(5600)  评论(1编辑  收藏  举报

导航