Java编译器的内部架构

时间:2015-09-25 09:36:10

标签: java javacompiler

我已经在Java工作了8年多。

上周,在我公司的一次小型会议上,我的一位同事问我Java Compiler到底有多确切?我没有回答。

我尝试解释,就像Java Compiler一个接一个地接受语句并将它们转换为不是针对任何OS而是针对JVM的字节代码。

即使是我,也没有人对这个答案感到满意。

现在主要问题是java编译器的工作原理。即,在编译Java文件时,编译器将完成多少步骤或阶段或阶段。

Java's compiler架构究竟是什么?

如果同一.java文件中有多个Java classes,该怎么办?然后将编译多少个类。

如果有导入指向未编译的Java类怎么办?然后编译或忽略未编译的类?

我用Google搜索了半天以上,所有人都提供了与我给同事相同的答案。

但最后我找到了一些有用的教程here

但是教程也不太深入,我无法想象该教程。

我仍然不满意并渴望从你那里学到更多关于此事的信息。

因此,如果任何人比我和上述博客更了解某些内容,那么我可以使用哪些内容可以直观地了解Java Compiler的内部架构,请解释一下。

2 个答案:

答案 0 :(得分:8)

一些基本步骤:

  1. parse:读取一组* .java源文件并映射生成的令牌 序列为AST(抽象语法树)-Nodes。
  2. enter:将定义的符号输入符号表。
  3. 流程注释:如果请求,则处理在中找到的注释 指定的编译单元。
  4. attribute:属性语法树。此步骤包括名称 分辨率,类型检查和常数折叠。
  5. flow:对上一步中的树执行数据流分析。 这包括检查分配和可达性。
  6. desugar:重写AST并翻译一些语法糖。
  7. generate:生成源文件或类文件。
  8. 更多细节:

    1. Lex - 将源文件分解为单个单词或标记。
    2. Parse - 分析程序的短语结构。
    3. 语义操作 - 构建一个与每个短语对应的抽象语法树。
    4. 语义分析 - 确定每个短语的含义,将变量用于其定义,检查表达式的类型,请求翻译每个短语。
    5. 帧布局 - 以与机器相关的方式将变量,函数参数等放入激活记录(堆栈帧)。
    6. 翻译 - 生成中间表示树(IR树),一种表示法 与任何特定的源语言或targetmachine架构无关。
    7. Canonicalize - 提升表达式的副作用,并清理条件分支,以方便下一阶段。
    8. 指令选择 - 将IR树节点分组为与目标机器指令的操作相对应的块。
    9. 控制流分析 - 将指令序列分析到控制流程图中,该控制流程图显示程序可能的所有控制流程 在执行时跟随。

    10. 数据流分析 - 通过程序变量收集有关信息流的信息;例如,活跃度分析计算每个程序变量保持一个仍然需要的值(是实时的)的位置。

    11. 注册分配 - 选择一个寄存器来保存程序使用的每个变量和临时值;变量不是同时存在的 可以共享相同的注册表。

    12. 代码发射 - 用每个机器指令替换临时名称 机器注册。

    13. 有一本好书:

        

      Java中的现代编译器实现

      您可能需要查看javac代码:

      Javac Documentation

      OpenJDK source code

      Hacker's guide to javac

      Don't Panic! To help newcomers to javac navigate their way around the code base

      JVM JLS

答案 1 :(得分:6)

编译器有不同的步骤,但这里最重要的是:

词法分析 第一步是词法分析。基本上这个步骤从java代码(关键字,运算符,分隔符,注释,变量名......)中提取标记

语法分析(解析器) 第二步是语法分析。将标记作为词法分析的输入,并组合成表达式和指令。

优化并转换为字节代码 最后一个宏步骤是将上一步转换为字节代码。这里的代码可以修改为与原始代码等效,但效率更高。

注意:此过程与java无关,但对所有编译器都是通用的。也是不生成中间字节代码但是生成机器代码的编译器(比如C或C ++的编译器)。

通常有创建词法分析器和语法分析器的工具,因为这些步骤在不同语言之间有许多公共部分。

开源词汇分析器是flex 一个有用的句法分析器是yacc

两者都使用C和C ++作为最常用的语言来创建编译器(java和其他语言),但也有其他编程语言的类似替代方法(用另一种语言创建编译器 ,而不是 另一种语言)。基本上编写编译器的语言与编译器编译的语言无关。