zoukankan      html  css  js  c++  java
  • 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: // '01'
    419                     case 2: // '02'
    420                     default:
    421                         break;
    422 
    423                     case 0: // ''
    424                         if (!batchenvironment.dependencies())
    425                             continue;
    426                         // fall through
    427 
    428                     case 3: // '03'
    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: // '04'
    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: // '05'
    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     }
  • 相关阅读:
    vue(5)
    vue(4)
    vue(3)-防止闪烁
    vue(2)
    bootstrap 模态框
    2017年上半年工作总结和计划
    vue(1)
    文本框数量加减功能
    meta 控制移动端页面的缩放
    题解 P1550 【[USACO08OCT]打井Watering Hole】
  • 原文地址:https://www.cnblogs.com/jueyoq/p/7861560.html
Copyright © 2011-2022 走看看