HTML5标准与性能之四:asm.js

Cong Liu (Intel) 于 星期五, 24/05/2013 - 01:13 提交

之前的几篇文章分别介绍了WebWorkersTyped ArrayParallelArray,最后,我们再来介绍一下与性能相关的标准:asm.js。

asm.js

asm.js是由Mozilla提出的一个基于JS的语法标准,主要是为了解决JS引擎的执行效率问题,尤其是使用Emscripten从C/C++语言编译成JS的程序的效率,目前只有Mozilla的Firefox Nightly中支持。

Emscripten

Emscripten是Mozilla的一个实验性项目,目的是把C/C++开发的应用编译成JS或HTML5的应用,编译过程中需要首先把C/C++程序编译成LLVM的中间代码,然后再转换成JS代码,这样做的主要原因是可以很好地复用现有的针对LLVM的优化。

C/C++是一种强类型的语言,这很好地对应了不同字长的CPU指令,每一种数据类型都有固定的上下限,一旦计算超出这个上下限就会产生溢出,比如char类型的取值范围是[-128,127],而(char)(127 + 1)这个计算就会溢出,得到(char)-128

JS语言不仅是弱类型的,而且数值类型只有一种-NumberNumber类型的数据采用双精度64位格式的IEEE 754值表示。如果用JS模拟C/C++类型的数值计算,就要模拟各种类型数据计算时的溢出效果。我们通过下面这个简单的C程序来看看如何用JS来模拟这样的计算。

1 char xInt8 = 127;
2 char yInt8 = xInt8 + 1; // 溢出:yInt8 == (char) -128
3 cahr zInt8 = xInt8 / 2; // 舍入:zInt8 == (char) 63

上面这段代码通过JS模拟后的代码如下:

1 var xInt8 = 127; // (1)
2 var $add = (xInt8 + 1) | 0; // (2)
3 var yInt8 = ($add << 24) >> 24; // (3)
4 var $div = ((yInt8 | 0) / 2) & -1; // (4)
5 var zInt8 = ($div << 24) >> 24; // (5)
  1. 8位整型变量127,相当于char xInt8 = 127;
  2. X|0让计算结果成为32位整数,此时$add == 128
  3. 先左移24位再右移24位,让第8位成为32位整数的符号位,来模拟8位整数计算,此时yInt8 == -128
  4. JS中127/2结果是浮点数63.5,利用X&-1将结果转化成32位整数63(-1的补码表示就是0xFFFFFFFF)
  5. 用上面(3)相同的方法,把结果转换成8位整数

大家看到,利用一些位移和逻辑运算可以模拟C/C++语言中的数据计算,Emscripten就利用这个方法将C代码转换成JS代码。大家可能还记得前篇文章介绍过的Typed Array,对Typed Array元素赋值则会自动进行相应的溢出和舍入处理,因此,利用Typed Array还可以改写成以下的代码:

1 var HEAP8 = new Int8Array(STACK_SIZE); // 构造一个Int8Array数组
2 HEAP8[0] = 127; // char xInt8 = 127
3 HEAP8[1] = HEAP[0] + 1; // char yInt8 = xInt8 + 1,此时yInt8是-128
4 HEAP8[2] = HEAP[1] / 2; // char zInt8 = xInt8 / 2 

在EmScripten中,Typed Array用来模拟C/C++中的堆栈以及指针的访问。

语法

asm.js不是一种新的语言,而是JS语法的一个子集,也就是说所有用asm.js写的程序都是合法的JS程序,asm.js与JS语言的关系有点类似C与C++的关系。因此,不支持asm.js的浏览器或JS引擎也可以无误地执行asm.js的代码。

asm.js顾名思义是作为JS的汇编语言来设计的,它的语法手写起来非常困难,且难以阅读。首先,asm.js的语法利用了一些标注让JS的变量成为强类型的,这些标注与Emscripten生成的代码如出一辙,实际上asm.js的产生就是为了提高Emscripten转换后的代码执行效率的。我们来看一个例子:

1 intValue = f1() | 0; // 利用或运算(|)标记函数f1返回值为int32整数
2 floatValue = +f2(); // 用加号(+)标记函数f2返回值为双精度型浮点 

同时,asm.js还规定了一个特殊的语法格式,下面这段代码是一个最简单的asm.js示例(代码来自:http://asmjs.org/spec/latest/):

1 function MyAsmModule(stdlib, foreign, heap) {
2 "use asm"; // "use asm"来告诉JS引擎这个函数采用asm.js编译器解析执行
3 // module body...
4 return { // 返回向外暴露的函数接口
5  export1: f1,
6  export2: f2,
7  // ... };
8 }
9 var result = MyAsmModule({}, {}, null).export1(); // 调用函数export1

在这个例子中,参数stdlib、foreign、heap由外部传入,表示: 1. stdlib:有限的标准库函数,主要是一些数学函数,对应Math对象上的方法 2. foreign:foreign function interface (FFI)外部JS函数访问接口 3. heap:传入一个ArrayBuffer对象,作为asm.js的堆

编译和运行

由于asm.js相当于支持了强类型,因此可以直接对应编译成机器指令执行。asm.js的代码采用另外一套AOT(Ahead Of Time)编译器,将asm.js代码预先编译成机器指令,在编译过程或运行过程中,一旦发现语法错误或违反类型标记的情况出现,便重新将代码交予JS引 擎解析执行(见下图)。

图片来自:http://asmjs.org/spec/latest/

性能

JS一直以来被人诟病的一个方面就是它的性能,得益于这些年来浏览器之间的竞争,让JS的性能大大提升,Google的V8、Mozilla的 SpiderMonkey以及微软的Chakra在性能方面都已经相当不错,而asm.js进一步提升到相对本地代码2倍慢的性能(如下图)。这些测试用 例使用Emscripten转换而来,Emscripten已经可以直接生成asm.js代码。 数据来自:http://ejohn.org/blog/asmjs-javascript-compile-target/

Demo

参考

  1. asm.js specification: http://asmjs.org/spec/latest/
  2. IEEE 754: https://en.wikipedia.org/wiki/IEEE_floating_point

转:HTML5标准与性能之四:asm.js的更多相关文章

  1. 转:WebGL、Asm.js和WebAssembly概念简介

    WebGL.Asm.js和WebAssembly概念简介 转:http://www.techbrood.com/zh/news/webgl/webgl%E3%80%81asm_js%E5%92%8Cw ...

  2. 让IE8支持HTML5及canvas功能!chart.js图表绘制工具库IE8上兼容方案

    第一步,我们加上对html5的支持. <!--[if IE]> <script src="/public/html5.js" type="text/ja ...

  3. 基于HTML5实现的超酷摄像头(HTML5 webcam)拍照功能 - photobooth.js

    在线演示 WebRTC可能是明年最受关注的HTML5标准了,Mozilla为此开发了一套帮助你控制硬件的API,例如,摄像头,麦克风,或者是加速表.你可以不依赖其它的插件来调用你需要的本机硬件设备. ...

  4. Asm.js: Javascript的编译目标

    正如许多开发者一样,我也为Asm.js的前景而感到兴奋不已.最近的新闻——Asm.js正 在被Firefox支持——引起了我的兴趣.同样感兴趣的还有Mozilla和Epic声明(mirror)他们已经 ...

  5. W3C小组宣布:HTML5标准制定完成

    近日,W3C小组宣布已经完成对HTML5标准以及Canvas 2D性能草案的制定,这就意味着开发人员将会有一个稳定的“计划和实施”目标. Web性能工作组已经推出W3C的两个版本建议草案. Navig ...

  6. 【转】asm.js 和 Emscripten 入门教程

      Web 技术突飞猛进,但是有一个领域一直无法突破 ---- 游戏. 游戏的性能要求非常高,一些大型游戏连 PC 跑起来都很吃力,更不要提在浏览器的沙盒模型里跑了!但是,尽管很困难,许多开发者始终没 ...

  7. 转:asm.js 和 Emscripten 入门教程

    转:http://www.ruanyifeng.com/blog/2017/09/asmjs_emscripten.html asm.js 和 Emscripten 入门教程 作者: 阮一峰 日期:  ...

  8. JavaScript性能优化篇js优化

    JavaScript性能优化篇js优化   随着Ajax越来越普遍,Ajax引用的规模越来越大,Javascript代码的性能越来越显得重要,我想这就是一个很典型的例子,上面那段代码因为会被频繁使用, ...

  9. 2.HTML5 标准改变,准备工作

    1.HTML5 标准改变: Html5 不是SGML,XML语言,没有有效性检查,是规范,有松散的写法 不许写结束标签:area,base,br,col,hr,img,input,link,sourc ...

随机推荐

  1. Linq To Object

    //SelectMany List<List<int>> Numbers = new List<List<int>>() { new List<i ...

  2. php乱码

    1:php 编码是utf-8 但是接口需要是gbk 这么办?? $message = "你的微点管理地址为:".$shortUrl." [请保存信息]"; // ...

  3. C#设计模式(6)——原型模式(Prototype Pattern)

    一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在 ...

  4. Asp.Net Web API 2第十七课——Creating an OData Endpoint in ASP.NET Web API 2(OData终结点)

    前言 很久没更新博客了,加上刚过年,现在准备重新开战,继续自己的学习之路.本文已同步到Web API2系列文章中http://www.cnblogs.com/aehyok/p/3446289.html ...

  5. 配置SharePoint 2013 Search 拓扑结构

    在单台服务器上安装了 SharePoint Server 2013,并且创建了具有默认搜索拓扑的 Search Service 应用程序.在默认搜索拓扑中,所有搜索组件都位于承载管理中心的服务器上.S ...

  6. clearing & settlement

    http://blog.donews.com/tianshun/archive/2013/07/ http://wenku.baidu.com/view/e5a736e3e53a580217fcfe1 ...

  7. 为什么要设置getter和setter?

    面向对象语言中,通常把属性设置为私有,然后添加getter和setter方法来访问.有人说,这本质上和设置属性为公有没有区别,干脆把属性public算了.也有人反驳,这样做破坏了封装.但是,破坏了封装 ...

  8. Lingo 做线性规划 - Game Thoery

    Reference: <An Introduction to Management Science Quantitative Approaches to Decision Making, Rev ...

  9. CSS Sticky Footer: 完美的CSS绝对底部

    CSS的简单在于它易学,CSS的困难在于寻找更好的解决方案.在CSS的世界里,似乎没有完美这种说法.所以,现在介绍的CSS绝对底部,只是目前个人见过的方案中比较完美的吧. 先说我们为什么会使用到这个C ...

  10. SQL中order by;group up;like;关联查询join on的用法

    排序order by的用法: 1.order by 字段名1 asc/desc, 字段名2 asc/desc,... 先按照字段名1的升序/降续给表进行排列 然后 按照字段名2的升序/降续给表进行排列 ...