在编译之前重用javascript的优化代码外文翻译资料

 2022-12-18 04:12

Reusing the Optimized Code for JavaScript Ahead-of-Time Compilation

HYUKWOO PARK, SUNGKOOK KIM, JUNG-GEUN PARK, and SOO-MOOK MOON,

Seoul National University

As web pages and web apps increasingly include heavy JavaScript code, JavaScript performance has been a critical issue. Modern JavaScript engines achieve a remarkable performance by employing tiered-execution architecture based on interpreter, baseline just-in-time compiler (JITC), and optimizing JITC. Unfortunately, they suffer from a substantial compilation overhead, which can take more than 50% of the whole running time. A simple idea to reduce the compilation overhead is ahead-of-time compilation (AOTC), which reuses the code generated in the previous run. In fact, existing studies that reuse the bytecode generated by the interpreter or the machine code generated by the baseline JITC have shown tangible performance benefits [12, 31, 41]. However, there has been no study to reuse the machine code generated by the optimizing JITC, which heavily uses profile-based optimizations, thus not easily reusable. We propose a novel AOTC that can reuse the optimized machine code for high-performance JavaScript engines. Unlike previous AOTCs, we need to resolve a few challenging issues related to reusing profile-based optimized code and relocating dynamic addresses. Our AOTC improves the performance of a commercial JavaScript engine by 6.36 times (max) and 1.99 times (average) for Octane benchmarks, by reducing the compilation overhead and by running the optimized code from the first invocation of functions. It also improves the loading time of six web apps by 1.28 times, on average.

CCS Concepts: bull; Software and its engineering Compilers; Scripting languages;

Additional Key Words and Phrases: JavaScript, ahead-of-time compilation, optimizing just-in-time compila- tion, web app, JavaScriptCore engine

ACM Reference format:

Hyukwoo Park, Sungkook Kim, Jung-Geun Park, and Soo-Mook Moon. 2018. Reusing the Optimized Code for JavaScript Ahead-of-Time Compilation. ACM Trans. Archit. Code Optim. 15, 4, Article 54 (December 2018), 20 pages.

https://doi.org/10.1145/3291056

This work was supported by Basic Science Research Program through the National Research Foundation (NRF) of Korea funded by the Ministry of Science, ICT amp; Future Planning (NRF-2017R1A2B2005562).

The preliminary idea of this article was proposed as a two-paged work-in-progress paper [32], but most parts of this article are new and original.

Authorsrsquo; addresses: H. Park, S. Kim, J.-G. Park, and S.-M. Moon. Department of Electrical and Computer Engineering. Seoul National University, Seoul, Korea; emails: {clover2123, skkeem, erebus, smoon}@altair.snu.ac.kr.

54

Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. Copyrights for components of this work owned by others than the author(s) must be honored. Abstracting with credit is permitted. To copy otherwise, or republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. Request permissions from permissions@acm.org.

copy; 2018 Copyright held by the owner/author(s). Publication rights licensed to ACM. 1544-3566/2018/12-ART54

https://doi.org/10.1145/3291056

INTRODUCTION

JavaScript is a standard web programming language, along with HTML and CSS. Traditionally, JavaScript has been used as lightweight scripting for web pages, especially for interacting with the user inputs and modifying the web pages at the client side. However, as the web has evolved with new standards and libraries, such as HTML5 [16], WebGL [24], ECMAScript6 [7], JavaScript is increasingly undertaking complex computations, and even running in the server environment [28]. So, JavaScript performance has been a real issue, and the just-in-time compiler (JITC) that translates JavaScript code to machine code at run time has been popularly used [8].

Modern JavaScript engines used in WebKit [2], Chrome [9], and Firefox [25] browsers ex- tend JITC by employing a tiered execution architecture based on adaptive compilation, which re- compiles JavaScript code differently based on the “hotness” of a function. That is, when a JavaScript function is first called, it is parsed to an intermediate code, e.g., bytecode, which is then executed by the interpreter. When the function is found to be warm, the baseline JITC compiles the bytecode into basic machine code for better performance. If the function is executed more frequently, thus being hot, the optimizing JITC re-compiles it into highly-optimized code. In this way, JavaScript engines can trade-off the startup delay and the steady-state performance.

Although JavaScript performance has soared using tiered compilation, we found that the com- pilation overhead is extremely high. Figure 1 shows the overhead for each compilation tier of the WebKit JavaScriptCore (JSC) engine, measured for Octane benchmarks [11]. The total compila- tion overhead accounts for 52% of the whole JavaScript execution time, most of which is due to parsing a

剩余内容已隐藏,支付完成后下载完整资料


在编译之前重用javascript的优化代码

HYUKWOO PARK, SUNGKOOK KIM, JUNG-GEUN PARK, and SOO-MOOK MOON,首尔国立大学

随着网页和web应用程序越来越包含大量的javascript代码,javascript性能一直是一个关键问题。现代的JavaScript引擎通过使用基于解释器的分层执行体系结构、基线实时编译器(JITC)和优化JITC来实现卓越的性能。不幸的是,它们会遭受大量的编译开销,这可能会占用整个运行时间的50%以上。减少编译开销的一个简单方法是提前编译(AOTC),它重用在前一次运行中生成的代码。事实上,现有的研究表明,重用解释器生成的字节码或基线jitc生成的机器代码有明显的性能优势[12,31,41]。然而,目前还没有研究如何重用优化jitc生成的机器代码,它大量使用基于概要文件的优化,因此不容易重用。我们提出了一种新的AOTC,可以将优化后的机器代码重用到高性能的javascript引擎中。与以前的AOTC不同,我们需要解决一些与重用基于概要文件的优化代码和重新定位动态地址相关的挑战性问题。我们的AOTC通过减少编译开销和从第一次调用函数开始运行优化的代码,将商业JavaScript引擎的性能提高了6.36倍(最大值)和1.99倍(平均值)。它还将六个Web应用程序的加载时间平均提高了1.28倍。

ccs概念:bull;软件及其工程编译器;脚本语言;

其他关键词和短语:javascript、提前编译、优化实时编译、Web应用、JavaScript引擎

介绍

JavaScript是一种标准的Web编程语言,与HTML和CSS一起使用。传统上,JavaScript被用作网页的轻量级脚本,特别是用于与用户输入交互和修改客户端的网页。然而,随着Web随着新的标准和库(如HTML5[16]、WebGL[24]、ECMAScript6[7])的发展,JavaScript越来越需要进行复杂的计算,甚至在服务器环境中运行[28]。因此,javascript性能一直是一个真正的问题,而在运行时将javascript代码转换为机器代码的实时编译器(jitc)被广泛使用[8]。

webkit[2]、chrome[9]和firefox[25]浏览器中使用的现代javascript引擎通过采用基于自适应编译的分层执行体系结构来增强JITC,该体系结构根据函数的“热度”重新编译不同的javascript代码。也就是说,当第一次调用Ajavascript函数时,它被解析为中间代码,例如字节码,然后由解释器执行。当发现函数是暖函数时,基线JITC将字节码编译为基本机器代码,以获得更好的性能。如果函数执行的频率更高,因此很热,优化jitc会将其重新编译为高度优化的代码。这样,javascript引擎可以权衡启动延迟和稳态性能。

虽然使用分层编译的JavaScript性能已经大幅提高,但我们发现编译开销非常高。图1显示了webkit javascriptcore(JSC)引擎的每个编译层的开销,根据辛烷值基准测量[11]。编译总开销占整个JavaScript执行时间的52%,其中大部分是由于分析和优化JITC。也就是说,解析通过词法和句法分析将每个调用的javascript函数转换为字节码,而优化jitc执行许多优化,尤其是配置文件优化。另一方面,baselinejitc只需简单地将每个字节码映射到相应的机器代码,而很少进行优化,因此开销相对较低。对于Web应用程序,我们可以观察到在应用程序加载期间编译开销较低但仍相当可观(20%),尽管可以启用优化JITC的热函数要少得多(当我们在应用程序加载后以事件驱动的方式运行应用程序时,如果相同的事件处理程序和函数是重复执行)。

为了减少优化jitc开销,我们提出了并发编译[4,13,23],其中优化jitc在单独的线程上工作,并与主线程一起隐藏编译开销。然而,并发编译需要多核CPU,因此通常不适用,即使使用多核CPU,也无法隐藏解释开销。此外,由于内部的值表示,一些浏览器(例如WebKit)仅对64位操作系统(OS)启用并发编译。

减少编译开销的一种更简单的方法是提前编译(AOTC),它可以保存在上一次运行中生成的编译代码,并在当前运行中重用它,而不进行编译。实际上,AOTC已经成功地用于Java,例如重用完全优化的JITC代码(19, 20, 39)或使用从BytECODE到C(21, 29)获得的高性能代码。AOTC-FavaJava相对简单,因为它的语言特征是静态的,允许简单的翻译和重用(甚至允许基于硬件的分析和TRAN)。Java的SLIP)[33, 34, 35 ]。然而,JavaScript的AOTC比Java复杂得多,因为它的动态动态特性,如动态类型、闭包或运行时添加/删除对象属性,需要比Java更复杂的基于轮廓的优化;这样的优化代码很难生成和重用,这将很快解释。实际上,以前的aotcs for javascript只重用解释器生成的字节码或基线jitc生成的机器代码[12,31,41]。

本文提出了一种新的AOTC方法,用于将优化JITC生成的机器代码重用到最先进的JavaScript引擎中。它可以避免所有编译分析、基线JITC和优化JITC的开销。此外,即使从第一次调用开始,尽早重用优化的代码也会带来额外的性能优势。虽然这个想法很简单,但是对于重用优化的代码来说,有一些挑战性的问题。例如,我们需要重新定位优化代码中的许多动态地址,例如隐藏类地址,这不像在基线代码中重新定位静态地址那样简单。我们还需要验证上一次运行中基于概要文件的优化过程中使用的推测,以确认我们可以在当前运行中重用代码。一个问题是,有时不可能重用代码,因为在当前运行中无法识别在检查代码中为推测指定的对象(可能在我们即将执行代码时还没有创建该对象)。最后,优化的JITC可以在执行过程中多次重新编译一个函数,因此为AOTC保存和重用哪个版本也是一个问题。我们解决了这些问题,并在WebKit JSC引擎上实现了所提议的AOTC。我们的AOTC显示出比原始JSC更高的性能。据我们所知,我们的工作是第一个AOTC,它重用由现代JavaScript引擎的激进优化JITC生成的基于概要的优化代码。

本文的其余部分组织如下。第2节包含有关现代JavaScript引擎和优化JITC的背景信息。在第3节中,我们描述了我们的AOTC方法,并展示了它的设计和实现。在第4节中,我们介绍了实验结果,在第5节中,我们回顾了相关的工作。我们将在第6节中结束。

背景

    1. JavaScript引擎体系结构

现代的JavaScript引擎通常采用多层架构,由多个执行层(包括解释器和JITC)组成。这些层以功能为基础进行操作。图2代表了现代JavaScript引擎的典型执行过程,例如WebKit的JSC[3]、Chrome的V8[10]和Firefox的Spidermonkey[26]。因为javascript是作为源代码格式分发的,所以在执行之前,应该首先翻译javascript源代码。在第一层中,解析器将被调用的javascript函数的源代码转换为字节码。然后,解释器首先执行字节码,以确保快速启动JavaScript执行。当函数被反复调用并认为是暖的(在JSC中是10次)时,会触发基线jitc,用最小的优化(第二层)将字节码编译成简单的机器代码。基线jitc还插入检测代码来收集一些配置文件信息。如果执行的基线代码足以收集稳定的配置文件(66次 jsc),函数被认为是热的,启动第三层。现在,优化jitc使用许多优化来重新编译字节码,其中最强大的是基于概要的优化,它会生成推测代码。但是,如果一些猜测失败,就会发生去优化,返回到基线代码。第三层将在第2.2节中解释。在第三层之后可以添加更多的优化层,以优化更热的javascript函数(例如,ftl injsc)。

    1. 基于配置文件的优化

执行各种优化,例如常用的子表达式消除、循环不变的代码移动、内嵌函数等,这些通常在静态编译器中使用。需要注意的一点是,优化JITC还积极地执行基于概要文件的优化。

JavaScript是一种动态类型的面向对象语言。变量的类型在执行期间可更改。对象的属性(字段)也可以动态插入或删除。基线代码收集的配置文件信息主要与动态行为有关,例如变量类型或执行期间对象的形状。然后,优化jitc生成专门用于这些概要文件的代码,推测相同的行为将在将来重复。

图3显示了一个示例JavaScript源代码以及基线代码和优化代码。源代码显示全局变量glob首先初始化为整数1。然后,函数foo()经常在一个循环中调用,从而最终通过优化jitc进行优化。使用参数对象重复调用foo(),该参数对象的xproperty初始化为整数2(即foo((x^:2))。foo()所做的是添加两个操作数,参数对象的xproperty和glob。foo()的基线代码为每个操作数类型生成每种情况的加法代码,以处理动态类型,如图3所示。

从基线代码执行期间收集的配置文件信息中,优化JITC可以识别以下内容。首先,全局初始化一次并保持不变。其次,传递给foo()的参数对象始终具有相同的形状,其中唯一的属性x位于第一个位置(偏移量0)。最后,加法运算的两个操作数glob和x属性是整数值。

根据这些信息,函数foo()优化如下。首先,对加法运算的每个操作数的加载进行了优化。对于参数的x属性,我们需要生成加载属性x值的代码。通常,JavaScript引擎使用隐藏类、属性列表及其在对象中的偏移量来表示对象的形状。所以,每个对象都有一个指向其隐藏类的指针,为了访问一个属性,我们应该首先从隐藏类中找到属性的位置。但是,我们观察到foo()总是用相同形状的对象调用,因此参数对象总是有一种隐藏类。因此,优化jitc生成直接在固定位置加载属性x的代码。

图3 带有baselinecode和函数的优化代码的javascript源代码示例英尺()。

(缓存的偏移量0)在对象中,而不查找隐藏类,预期参数将来将是相同形状的对象。这种对属性访问的优化被称为内联缓存[18]。当然,这种推测在将来可能是无效的,例如,函数foo()可以用另一个形状的对象调用。为了验证每个推测,优化jitc还插入了保护代码。在这种情况下,将缓存观察到的隐藏类的地址,并将其与当前参数对象的隐藏类的地址进行比较。如果两个地址不同,则表示另一个形状的对象在图的源代码中作为参数(例如,由foo(y:1,x:2)传递。3)。它触发一个称为去优化的恢复机制,该机制停止优化代码中该保护点的执行,并在基线代码中的等效点恢复执行,无需猜测,从而继续执行。这实际上是由图3中调用的去优化处理程序处理的,它通过恢复基线代码堆栈将执行切换到基线代码。需要注意的一点是,函数的优化代码不会立即丢弃,因为下次调用foo()时推测可能有效。当由于保护代码的失败而进行了许多去优化时,最终会丢弃优化的代码,然后使用基线代码代替。但是,如果基线代码再次频繁执行,那么函数将通过优化jitc重新编译,现在在基线代码执行期间会添加额外的配置文件。

对于另一个操作数glob,optimizingjitc推测glob是一个常量,因为glob被初始化一次且不变。因此,glob(integer 1)的值直接用于add操作,而不是生成从全局堆栈访问和加载值的代码。为了保护对glob常量值的推测,javascript引擎为glob设置了一个观察点,它排除了保护代码;当变量有更新时,javascript引擎会立即检测到它,并根据对常量值的推测丢弃任何优化的代码。在图3中,监视点监视全局变量的变化,并有一个时间

使用监控值优化功能。如果修改了glob(如图3中源代码的最后一行),则会触发观察点。然后,放弃列表中每个函数的优化代码,改用基线代码,因为优化代码不再有效。无效后,在基线代码中执行函数foo()的每次调用;即使重新编译foo(),也不会再次使用观察点,因为它是无效的。监视点只分配给那些可以全局访问的值,例如全局变量或原型,因为监视每个值的效率很低。

最后,对于加法操作,优化jitc根据配置文件信息生成专门用于整数加法的代码。在添加代码之前,有一个保护代码检查属性x的类型,如果它不是整数,则跳转到反优化处理程序。不需要对glob进行类型检查,因为glob已经被推测为1并由监视点监视。

Aotc用于重用优化代码

在前一节中,我们展示了优化的JITC执行许多基于概要文件的规范。在本节中,我们描述了提议的AOTC,它重用推测的代码。对于本文的其余部分,前一次运行意味着我们在其中保存AOTC代码的运行,而当前运行意味着我们在其中重用保存的代码的运行。

    1. Aotc框架

我们提出的AOTC框架的工作原理如下,适用于上一次运行中的每一个函数的使用:

(1)对于优化jitc编译的函数,我们将其优化后的代码保存在AOTC文件中,以便在以后的运行中重用。我们希望重用优化的代码可以通过两种方式提供更高的性能优势:

bull;我们可以跳过整个编译过程,从而完全消除编译开销。

bull;我们可以从函数的第一次调用开始执行优化的代码,而不是遍历所有编译层(参见图4和比较)。

(2)对于由baseline jitc编译的函数,由于三个原因,我们不将baseline代码保存在AOTC文件中。首先,如图1所示,基线JITC的编译开销很小,因此跳过它几乎没有影响。第二,执行基线代码而不是解释字节码的性能影响可以忽略不计,因为基线代码根本没有优化,而解释只在函数执行的前10次进行,因此用基线代码执行替换解释会有一些不同。最后,基线代码比优化后

剩余内容已隐藏,支付完成后下载完整资料


资料编号:[20038],资料为PDF文档或Word文档,PDF文档可免费转换为Word

您需要先支付 30元 才能查看全部内容!立即支付

课题毕业论文、文献综述、任务书、外文翻译、程序设计、图纸设计等资料可联系客服协助查找。