什么是基线编译器?
What is a baseline compiler?
我一直在努力寻找 baseline compiler 和 baseline interpreter 的定义,我很惊讶它没有在任何地方被提及。
如果我没记错的话,基线编译器会将代码编译成字节码而不是依赖于体系结构的机器码,对吗?
在深入研究了很多文章和书籍之后,我能够推断出“基线编译器”的含义。
基本上,基线编译器的工作是尽可能快地生成字节码或机器码。但是,此输出代码(机器代码或中间代码)并未针对处理器进行优化,因此效率非常低且 运行 时间很慢。
另一方面,优化编译器 生成高效的代码,但这样做需要更长的时间。
因此,基线编译器 在您想要尽快加载和 运行 您的应用程序并稍后使用 优化来优化代码时很有用后台编译器。
我在 JavaScript 运行时引擎的上下文中找到了一些关于该主题的信息,专门针对 Web 浏览器:简而言之,基线编译器是运行时引擎执行代码期间的某个阶段。它将非常快速地生成机器代码,但不会对代码实际运行的机器进行优化。所以它实际上是 just-in-time (JIT) compilation 更广泛概念中的一种方法,因此在概念上介于代码解释和代码编译之间。
This article 给出了一些关于 JavaScript JIT 编译的背景:
In summary, after JavaScript code is loaded, the source code is
transformed into a tree representation called Abstract Syntax Tree or
AST. After, depending on the engine/operational system/platform,
either a baseline version of this code is compiled, or a bytecode is
created to be interpreted. [...]
When a piece of code is executed multiple times, [...],
the interpreter loses his performance since it needs to
interpret the same piece of code over and over again, when this
happens, the profiler marks this piece of code as warm and baseline
compiler comes to action.
When this code section is executed [...],
the JIT only needs to take this compiled piece again. When a
warm code is called several times in the same manner (like same
types), it’s marked as hot. [...]
When a piece of code is marked as hot, the optimizer compiler
generates an even faster version of this code.
Here is another source 解释“热”代码的概念和代码执行的不同层次。
This (older) announcement 谈论 Mozilla(当时)的新 JavaScript 引擎以及包含的基线编译器解决的问题。
This other Mozilla blog article 提供了有关代码执行的非常详细的信息,由于新的要求和条件,甚至更多地改变了概念:
However, the modern web has such large codebases that even the
relatively fast Baseline JIT Compiler spent a lot of time compiling.
To address this, Firefox 70 adds a new tier called the Baseline
Interpreter to the pipeline
另一方面,Chromium 似乎有 introduced the concept in 2010 in its V8 engine (calling it a base compiler), and to have dropped it again in 2017。
分享我的发现
关于 Jikes RVM
The goal of the baseline compiler is to efficiently generate code that is ”obviously correct”. It also needs to be easy to port to a new platform and self contained (the entire baseline compiler must be included in all Jikes RVM boot images to support dynamically loading other compilers).
参考:Jikes RVM Chapter 13 Compilers
‘Baseline’ compiler, which exists for debugging and verification purposes; it produces native code that directly implements JVML’s stack model as closely as possible and is in many ways comparable to an interpreter.
参考:Quantifying the Benefits of SSA-Based Mobile Code
关于JavaScript
第一个解释
When the code starts to run, it is processed by the Interpreter. In the background, the Baseline compiler generates code containing profile information. This Baseline code is later invoked. As it executes and popular functions are discovered, they are recompiled by the more advanced DFG compiler. Finally, for the really hot functions, the most advanced compiler (FTL) creates very specialized, high-performance code.
参考:NoMap: Speeding-Up JavaScript Using Hardware Transactional Memory
第二种解释
参考:Server-Side Type Profiling for OptimizingClient-Side JavaScript Engines
要回答您的问题,您必须了解 Javascript 语言的内部工作原理,了解它的历史和最近的发展。
JavaScript is defined as an interpreted language but also as compiled on the fly (JIT-Compiled).
JavaScript 规范本身缺乏信息,进一步加剧了混乱。
执行JavaScript时,浏览器的JavaScript引擎(Chrome上的V8,Firefox上的SpiderMonkey)或服务器(Node.js上的V8)必须将源代码转换成计算机可以理解的格式。
有两种方法可以做到这一点:解释或编译源代码。
Interpretation: The program is translated into machine language during its execution (runtime). Each line is processed on the fly without waiting for a preliminary processing phase.
反之,当一行代码被执行N次时(比如一个循环),解释器必须重做N次机器语言翻译。
Compilation: Requires a preliminary phase of translation into machine language in order to be able to be executed. All the code is compiled and optimized beforehand by the compiler so that the program can be executed. It is a quid pro quo to alleviate the concern related to the interpreters mentioned above.
90年代中期出现,JavaScript很少使用,我们在标签中找到了一些指令和对onclick或alert等函数的调用。
解释要简单得多,并且为当时的用例提供了完全足够的性能。
在 2000 年代,一场关于 Web 浏览器性能的竞赛非常激烈,以至于被称为浏览器 war。这是主要网络播放器(Mozilla,Google)尝试最大限度优化其浏览器的时期。
因此,Firefox 推出了 SpiderMonkey,这是第一个 JIT 编译器,与旧版本的 JavaScript 引擎相比,它的性能提高了大约 20% 到 40%。
在此过程中,Google 提供了 Chrome 浏览器及其 V8 执行引擎,包括编译阶段。后者通常被称为“准时制”或 JIT。
其他浏览器(Edge 等)也通过添加编译阶段更改了它们的 JavaScript 引擎。这一发展将 JavaScript 的速度提高了 10 倍,并成为将其用于以前无法想象的平台(例如面向服务器的编程 (Node.js))的杠杆。
“及时”与编译
A JIT compiler combines the speed of execution of an interpreter with the optimization provided by a compiler.
JavaScript 包含 JIT 的引擎通常由 4 个基本构建块组成:
扮演指挥角色的班长(profiler)
执行源代码(运行时)的解释器
执行一些基本优化的所谓 "basic" 编译器
名为 "optimizer" 的编译器会在必要时负责进一步优化。
(简化)执行过程如下:
1)监视器调用解释器执行代码。它会即时分析所进行的函数调用。
2)如果解释器多次调用同一个函数,监视器将"tag"它作为一个warm函数。
3)一旦一个函数是warm,监视器就会与基线编译器通信,以指示该函数经常被使用并且必须对其进行编译。
4)基线编译器通过生成每条指令的优化版本(存根)来进行一些优化。
5) 如果一个函数变得越来越warm,那么它"tagged"就很热:必须进一步优化。
6) 然后监视器决定将此函数发送到编译器优化器,编译器优化器将生成比基线编译器生成的版本更优化的版本。
7)这个编译器对这个函数做了几个假设,例如,变量的类型。知道JavaScript有动态类型,出错的概率不为零。编译器可以去掉它的优化,只引用第4步编译出来的版本:是反优化操作。
8)解释器无需将函数重新翻译成机器语言,而是直接使用其编译版本或优化版本以加快处理速度。
第 7 阶段存在性能问题。事实上,如果编译器花时间优化然后再去优化代码,那么去优化会减慢这个过程。这就是为什么某些 JavaScript 引擎有优化周期限制的原因。
一旦达到此阈值,编译器将停止尝试优化并参考其 "raw" 形式的源代码版本(第 1 步的版本)或第 4 步中生成的存根。
性能水平,为了简单起见,无需深入了解每个 JavaScript 引擎的细节,我们可以看到它的震撼:V8 始终处于领先地位并显示出有趣的性能。
解释还是编译?
既然我们对执行过程有了一个大致的了解,我们可以冒险将JavaScript标记为解释型或编译型
JIT 编译器即时翻译源代码(机器语言),仅用于提高性能,这不是特定于 ECMA TC39 或 JavaScript.
的计划
JavaScript is therefore an interpreted language, which, as the uses and developments progressed, had to face performance challenges and led to a somewhat “hybrid” mode, mixing interpretation and compilation.
最近,Mozilla 提出了使用 Rust 语言对其执行引擎 (HolyJIT) 进行进化,旨在提高编译过程的性能和安全性。
2017年2月底,四大主流浏览器(Chrome、Safari、Edge、Firefox)宣布WebAssembly(WASM)MVP(Mininum Valuable Product)敲定。
它是一个基座,与 JIT 编译器相关联,打开了在浏览器中使用 JavaScript(C ++,Rust)以外的语言的可能性领域。
例如,可以在 JavaScript 应用程序中嵌入和使用使用 C 或 Rust 等语言开发的模块,而不会影响浏览器。
所有这一切都不是微不足道的,需要通过为此目的提供的编译器编译代码,以便作为输出生成 .wasm 文件。
这是一项有趣的技术,因为繁重的处理(通过 CPU 或 GPU 进行的密集计算)可以很好地用适应的语言(C 或 C++)开发,然后开发应用程序的其余部分在 JavaScript.
这里有一些有趣的文章,它们通过关注 V8 更深入地处理了这个主题:
http://www.jayconrod.com/posts/54/a-tour-of-v8-crankshaft-the-optimizing-compiler
https://v8project.blogspot.fr/2016/08/firing-up-ignition-interpreter.html
http://www.jayconrod.com/posts/51/a-tour-of-v8-full-compiler
https://ponyfoo.com/articles/an-introduction-to-speculative-optimization-in-v8
我一直在努力寻找 baseline compiler 和 baseline interpreter 的定义,我很惊讶它没有在任何地方被提及。
如果我没记错的话,基线编译器会将代码编译成字节码而不是依赖于体系结构的机器码,对吗?
在深入研究了很多文章和书籍之后,我能够推断出“基线编译器”的含义。
基本上,基线编译器的工作是尽可能快地生成字节码或机器码。但是,此输出代码(机器代码或中间代码)并未针对处理器进行优化,因此效率非常低且 运行 时间很慢。
另一方面,优化编译器 生成高效的代码,但这样做需要更长的时间。
因此,基线编译器 在您想要尽快加载和 运行 您的应用程序并稍后使用 优化来优化代码时很有用后台编译器。
我在 JavaScript 运行时引擎的上下文中找到了一些关于该主题的信息,专门针对 Web 浏览器:简而言之,基线编译器是运行时引擎执行代码期间的某个阶段。它将非常快速地生成机器代码,但不会对代码实际运行的机器进行优化。所以它实际上是 just-in-time (JIT) compilation 更广泛概念中的一种方法,因此在概念上介于代码解释和代码编译之间。
This article 给出了一些关于 JavaScript JIT 编译的背景:
In summary, after JavaScript code is loaded, the source code is transformed into a tree representation called Abstract Syntax Tree or AST. After, depending on the engine/operational system/platform, either a baseline version of this code is compiled, or a bytecode is created to be interpreted. [...]
When a piece of code is executed multiple times, [...], the interpreter loses his performance since it needs to interpret the same piece of code over and over again, when this happens, the profiler marks this piece of code as warm and baseline compiler comes to action.
When this code section is executed [...], the JIT only needs to take this compiled piece again. When a warm code is called several times in the same manner (like same types), it’s marked as hot. [...]
When a piece of code is marked as hot, the optimizer compiler generates an even faster version of this code.
Here is another source 解释“热”代码的概念和代码执行的不同层次。
This (older) announcement 谈论 Mozilla(当时)的新 JavaScript 引擎以及包含的基线编译器解决的问题。
This other Mozilla blog article 提供了有关代码执行的非常详细的信息,由于新的要求和条件,甚至更多地改变了概念:
However, the modern web has such large codebases that even the relatively fast Baseline JIT Compiler spent a lot of time compiling. To address this, Firefox 70 adds a new tier called the Baseline Interpreter to the pipeline
另一方面,Chromium 似乎有 introduced the concept in 2010 in its V8 engine (calling it a base compiler), and to have dropped it again in 2017。
分享我的发现
关于 Jikes RVM
The goal of the baseline compiler is to efficiently generate code that is ”obviously correct”. It also needs to be easy to port to a new platform and self contained (the entire baseline compiler must be included in all Jikes RVM boot images to support dynamically loading other compilers).
参考:Jikes RVM Chapter 13 Compilers
‘Baseline’ compiler, which exists for debugging and verification purposes; it produces native code that directly implements JVML’s stack model as closely as possible and is in many ways comparable to an interpreter.
参考:Quantifying the Benefits of SSA-Based Mobile Code
关于JavaScript
第一个解释
When the code starts to run, it is processed by the Interpreter. In the background, the Baseline compiler generates code containing profile information. This Baseline code is later invoked. As it executes and popular functions are discovered, they are recompiled by the more advanced DFG compiler. Finally, for the really hot functions, the most advanced compiler (FTL) creates very specialized, high-performance code.
参考:NoMap: Speeding-Up JavaScript Using Hardware Transactional Memory
第二种解释
参考:Server-Side Type Profiling for OptimizingClient-Side JavaScript Engines
要回答您的问题,您必须了解 Javascript 语言的内部工作原理,了解它的历史和最近的发展。
JavaScript is defined as an interpreted language but also as compiled on the fly (JIT-Compiled).
JavaScript 规范本身缺乏信息,进一步加剧了混乱。
执行JavaScript时,浏览器的JavaScript引擎(Chrome上的V8,Firefox上的SpiderMonkey)或服务器(Node.js上的V8)必须将源代码转换成计算机可以理解的格式。
有两种方法可以做到这一点:解释或编译源代码。
Interpretation: The program is translated into machine language during its execution (runtime). Each line is processed on the fly without waiting for a preliminary processing phase.
反之,当一行代码被执行N次时(比如一个循环),解释器必须重做N次机器语言翻译。
Compilation: Requires a preliminary phase of translation into machine language in order to be able to be executed. All the code is compiled and optimized beforehand by the compiler so that the program can be executed. It is a quid pro quo to alleviate the concern related to the interpreters mentioned above.
90年代中期出现,JavaScript很少使用,我们在标签中找到了一些指令和对onclick或alert等函数的调用。
解释要简单得多,并且为当时的用例提供了完全足够的性能。
在 2000 年代,一场关于 Web 浏览器性能的竞赛非常激烈,以至于被称为浏览器 war。这是主要网络播放器(Mozilla,Google)尝试最大限度优化其浏览器的时期。
因此,Firefox 推出了 SpiderMonkey,这是第一个 JIT 编译器,与旧版本的 JavaScript 引擎相比,它的性能提高了大约 20% 到 40%。
在此过程中,Google 提供了 Chrome 浏览器及其 V8 执行引擎,包括编译阶段。后者通常被称为“准时制”或 JIT。
其他浏览器(Edge 等)也通过添加编译阶段更改了它们的 JavaScript 引擎。这一发展将 JavaScript 的速度提高了 10 倍,并成为将其用于以前无法想象的平台(例如面向服务器的编程 (Node.js))的杠杆。
“及时”与编译
A JIT compiler combines the speed of execution of an interpreter with the optimization provided by a compiler.
JavaScript 包含 JIT 的引擎通常由 4 个基本构建块组成:
扮演指挥角色的班长(profiler) 执行源代码(运行时)的解释器 执行一些基本优化的所谓 "basic" 编译器 名为 "optimizer" 的编译器会在必要时负责进一步优化。
(简化)执行过程如下:
1)监视器调用解释器执行代码。它会即时分析所进行的函数调用。
2)如果解释器多次调用同一个函数,监视器将"tag"它作为一个warm函数。
3)一旦一个函数是warm,监视器就会与基线编译器通信,以指示该函数经常被使用并且必须对其进行编译。
4)基线编译器通过生成每条指令的优化版本(存根)来进行一些优化。
5) 如果一个函数变得越来越warm,那么它"tagged"就很热:必须进一步优化。
6) 然后监视器决定将此函数发送到编译器优化器,编译器优化器将生成比基线编译器生成的版本更优化的版本。
7)这个编译器对这个函数做了几个假设,例如,变量的类型。知道JavaScript有动态类型,出错的概率不为零。编译器可以去掉它的优化,只引用第4步编译出来的版本:是反优化操作。
8)解释器无需将函数重新翻译成机器语言,而是直接使用其编译版本或优化版本以加快处理速度。
第 7 阶段存在性能问题。事实上,如果编译器花时间优化然后再去优化代码,那么去优化会减慢这个过程。这就是为什么某些 JavaScript 引擎有优化周期限制的原因。
一旦达到此阈值,编译器将停止尝试优化并参考其 "raw" 形式的源代码版本(第 1 步的版本)或第 4 步中生成的存根。
性能水平,为了简单起见,无需深入了解每个 JavaScript 引擎的细节,我们可以看到它的震撼:V8 始终处于领先地位并显示出有趣的性能。
解释还是编译?
既然我们对执行过程有了一个大致的了解,我们可以冒险将JavaScript标记为解释型或编译型
JIT 编译器即时翻译源代码(机器语言),仅用于提高性能,这不是特定于 ECMA TC39 或 JavaScript.
的计划JavaScript is therefore an interpreted language, which, as the uses and developments progressed, had to face performance challenges and led to a somewhat “hybrid” mode, mixing interpretation and compilation.
最近,Mozilla 提出了使用 Rust 语言对其执行引擎 (HolyJIT) 进行进化,旨在提高编译过程的性能和安全性。
2017年2月底,四大主流浏览器(Chrome、Safari、Edge、Firefox)宣布WebAssembly(WASM)MVP(Mininum Valuable Product)敲定。
它是一个基座,与 JIT 编译器相关联,打开了在浏览器中使用 JavaScript(C ++,Rust)以外的语言的可能性领域。
例如,可以在 JavaScript 应用程序中嵌入和使用使用 C 或 Rust 等语言开发的模块,而不会影响浏览器。
所有这一切都不是微不足道的,需要通过为此目的提供的编译器编译代码,以便作为输出生成 .wasm 文件。
这是一项有趣的技术,因为繁重的处理(通过 CPU 或 GPU 进行的密集计算)可以很好地用适应的语言(C 或 C++)开发,然后开发应用程序的其余部分在 JavaScript.
这里有一些有趣的文章,它们通过关注 V8 更深入地处理了这个主题:
http://www.jayconrod.com/posts/54/a-tour-of-v8-crankshaft-the-optimizing-compiler
https://v8project.blogspot.fr/2016/08/firing-up-ignition-interpreter.html
http://www.jayconrod.com/posts/51/a-tour-of-v8-full-compiler
https://ponyfoo.com/articles/an-introduction-to-speculative-optimization-in-v8