IT戦記

プログラミング、起業などについて書いているプログラマーのブログです😚

ブラウザで X86 のマシン語を動かす! Google 謹製 Native Client をさっそく試してみる

はじめに

Google から、非常に面白そうなソフトウェアがリリースされました!
その名も Native Client なんとブラウザ上で X86 のバイナリを動かしてしまうそうです。

これはすごい!
さっそく試してみたいと思います。その過程を逐次更新していきます。

自分が試したときの環境

自分が試す環境は、以下の通りです。

準備

では、さっそく準備をしましょう。
http://nativeclient.googlecode.com/svn/trunk/nacl/googleclient/native_client/documentation/getting_started.html を参考にやってみます。

環境一式をダウンロード

まずは、以下から nacl_mac_0.1_9308700.tgz をダウンロードしてくきます。
http://code.google.com/p/nativeclient/downloads/list

$ wget http://nativeclient.googlecode.com/files/nacl_mac_0.1_9308700.tgz
--2008-12-09 15:10:07--  http://nativeclient.googlecode.com/files/nacl_mac_0.1_9308700.tgz
nativeclient.googlecode.com をDNSに問いあわせています... 74.125.47.82
nativeclient.googlecode.com|74.125.47.82|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 83237741 (79M) [application/x-gzip]
`nacl_mac_0.1_9308700.tgz' に保存中

100%[==================================================================================================================>] 83,237,741  2.61M/s 時間 36s     

2008-12-09 15:10:44 (2.21 MB/s) - `nacl_mac_0.1_9308700.tgz' へ保存完了 [83237741/83237741]
解凍

tgz だったので、 tar で解凍します。

$ tar xvfz nacl_mac_0.1_9308700.tgz 
中を見てみる

tar すると nacl というディレクトリにいろいろと解凍されました。
解凍されたディレクトリを tree してみました。

ng$ cd ..
$ tree -dL 3 nacl
nacl
`-- googleclient
    |-- native_client
    |   |-- common
    |   |-- documentation
    |   |-- gtest
    |   |-- include
    |   |-- intermodule_comm
    |   |-- ncv
    |   |-- nonnacl_util
    |   |-- npapi_plugin
    |   |-- scons-out
    |   |-- service_runtime
    |   |-- site_scons
    |   |-- site_scons_general
    |   |-- tests
    |   |-- third_party
    |   |-- tools
    |   `-- tools_bin
    `-- third_party
        |-- binutils
        |-- gcc
        |-- gnu_binutils
        |-- gtest
        |-- libxt
        |-- newlib
        |-- npapi
        |-- scons
        `-- sdl

28 directories

third_party/sdl というディレクトリがありますね!ワクワクします。

サンプルを実行してみる

サンプルは、 nacl/googleclient/native_client/tests/ の中に入っているみたいです。

tree -dL 1 nacl/googleclient/native_client/tests/
nacl/googleclient/native_client/tests/
|-- Frameworks
|-- app_lib
|-- cloudfs
|-- createthreads
|-- earth
|-- eviltests
|-- fib
|-- file
|-- hello_world
|-- imc_shm_mmap
|-- life
|-- mandel
|-- mandel_nav
|-- mm_init
|-- mmap
|-- noop
|-- npapi_bridge
|-- npapi_hw
|-- npapi_pi
|-- nrd_xfer
|-- null
|-- plug_univ
|-- quake
|-- srpc
|-- srpc_hw
|-- syscalls
|-- tone
|-- voronoi
`-- xaos

29 directories

なんか、いろいろあります。
では、 life というサンプルを実行してみましょう!

$ cd nacl/googleclient/native_client/tests/
$ python run.py


おおお。なんか、ライフゲームが立ち上がりました!
ディレクトリの中身を見てみましょう。

$ ls -la
total 64
drwxr-xr-x   2 amachang  staff   272 12  8 12:45 .
drwxr-xr-x  31 amachang  staff  1054 12  8 12:45 ..
-r--r--r--   1 amachang  staff  1882 12  8 12:45 Makefile
-r--r--r--   1 amachang  staff   166 12  8 12:45 README.txt
-r--r--r--   1 amachang  staff  1874 12  8 12:45 SConscript.nacl
-r-xr-xr-x   1 amachang  staff  9795 12  8 12:45 life.cc
-r--r--r--   2 amachang  staff  1134 12  8 12:45 life.html
-r-xr-xr-x   1 amachang  staff  1786 12  8 12:45 run.py

ビルド用の Makefile と SConscript と、ソースコード life.cc と、 html に貼付けるための life.html、単品実行用の run.py って感じですね。

ちょっと脱線:ソースコードを覗き見してみる

ソースコードをちらっと見てみましょう。
include を見ると、以下のように nacl/nacl_* というファイルを include しています。
standalone で実行する時は、違うヘッダを読み込むようですね。

#if !defined(STANDALONE)
#include <nacl/nacl_av.h>
#include <nacl/nacl_srpc.h>
#else
#include "native_client/common/standalone.h"
#endif

描画は、以下のように nacl_video_update に uint32_t のバッファを渡してやるようです。

struct Surface {
  int width, height, pitch;
  uint32_t *pixels;
  Surface(int w, int h) { width = w; height = h; pitch = w;
                          pixels = new uint32_t[width * height]; }
  ~Surface() { delete[] pixels; }
};
:
:

// Copies sw rendered life image to screen
void Life::Draw() {
  int r;
  r = nacl_video_update(surf_->pixels);
  if (-1 == r) {
    printf("nacl_video_update() returned %d\n", errno);
  }
}

詳しいことはこの時点ではよく分かりません。
でも、このアプリケーションは 341 行という短いコードで動いているようです。

ちょっと脱線: run.py は何をやっているの?

追いかけてみたら、 run.py は以下のコマンドを実行しているみたいです。

$ nacl/googleclient/native_client/scons-out/dbg-mac/staging/sel_ldr -d -f nacl/googleclient/native_client/scons-out/nacl/staging/life.nexe

sel_ldr というプログラムは、スタンドアローン版の flash player のようなもので nexe というが swf のようなものなのでしょう。

  • -f オプションはファイル指定
  • -d オプションはデバッグ

という意味だそうです。

life.nexe というのはどういうファイルなのか?

ちょっと気になるので、 file してみました

$ file scons-out/nacl/staging/life.nexe 
scons-out/nacl/staging/life.nexe: ELF 32-bit LSB executable, Intel 80386, version 1, statically linked, not stripped

どうやら、 *.nexe は ELF 32-bit LSB バイナリ(リナックスの実行ファイルの形式)だということが分かりました。

プラグインをビルドする

SCons でビルド出来るようです。

$ cd googleclient/native_client
$ scons --help
scons: Reading SConscript files ...
EnvironmentError: No module named component_setup:
  File "/Users/amachang/nc/nacl/googleclient/native_client/SConstruct", line 52:
    COMPONENT_LIBRARY_PUBLISH = True,
  File "/opt/local/lib/scons-0.98.4/SCons/Environment.py", line 933:
    apply_tools(self, tools, toolpath)
  File "/opt/local/lib/scons-0.98.4/SCons/Environment.py", line 106:
    env.Tool(tool)
  File "/opt/local/lib/scons-0.98.4/SCons/Environment.py", line 1582:
    tool = apply(SCons.Tool.Tool, (tool, toolpath), kw)
  File "/opt/local/lib/scons-0.98.4/SCons/Tool/__init__.py", line 89:
    module = self._tool_module()
  File "/opt/local/lib/scons-0.98.4/SCons/Tool/__init__.py", line 140:
    raise SCons.Errors.EnvironmentError, e

怒られてしまいました><
どうやら、 Native Client が用意した scons を使えということらしいですね。

$ ./scons --help
scons: Reading SConscript files ...
======================================================================
Building nexe binaries using sdk at [/Users/amachang/nc/nacl/googleclient/native_client/tools_bin/mac/sdk/nacl-sdk]
======================================================================
======================================================================
SDL build enabled, this is somewhat experimental
Using version in /Users/amachang/nc/nacl/googleclient/native_client/../third_party/sdl/osx/v1_2_13
======================================================================
*** Solution file generation skipped (not supported on this platform).
scons: done reading SConscript files.

Additional options for SCons:

  --mode=MODE                 Specify build mode (see below).
  --host-platform=PLATFORM    Force SCons to use PLATFORM as the host platform,
                              instead of the actual platform on which SCons is
                              run.  Useful for examining the dependency tree
                              which would be created, but not useful for
                              actually running the build because it'll attempt
                              to use the wrong tools for your actual platform.
  --site-path=DIRLIST         Comma-separated list of additional site
                              directory paths; each is processed as if passed
                              to --site-dir.
  --verbose                   Print verbose output while building, including
                              the full command lines for all commands.
  --brief                     Print brief output while building (the default).
                              This and --verbose are opposites.  Use --silent
                              to turn off all output.
  --retest                    Rerun specified tests, ignoring cached results.
======================================================================
Help for NaCl
======================================================================

Common tasks:
-------------

* cleaning:        scons -c
* build mandel:    scons MODE=all mandel.nexe
* some unittests:  scons run_unit_tests
* a smoke test:    scons -k pp=1 smoke_test
* 2nd smoke test:  scons -k pp=1 MODE=nacl smoke_test
* documentation:   scons MODE=doc
* firefox plugin:  scons MODE=opt-linux npGoogleNaClPlugin
* sel_ldr:         scons MODE=opt-linux sel_ldr
* firefox install: scons firefox_install

Options:
--------
pp=1              use command line pretty printing (more concise output)
sdl=<mode>        where <mode>:
                  'none': don't use SDL (default)
                  'local': use locally installed SDL
                  'hermetic': use the hermetic SDL copy
naclsdk_mode=<mode>   where <mode>:
                      'local': use locally installed sdk kit
                      'download': use the download copy (default)
                      'custom:<path>': use kit at <path>

Automagically generated help:
-----------------------------

Use --mode=type to specify the type of build to perform.  The following types
may be specified:
    dbg-mac          MacOS debug build
    opt-mac          MacOS optimized build
    nacl             NaCl module build
    doc              Documentation build

The following build groups may also be specified via --mode.  Build groups
build one or more of the other build types.  The available build groups are:
    all              dbg-mac,opt-mac,nacl,doc
    default          dbg-mac

Multiple modes may be specified, separated by commas: --mode=mode1,mode2.  If
no mode is specified, the default group will be built.  This is equivalent to
specifying --mode=default.
  
The following libraries can be built:
  gio                    naclthread             nonnacl_util_c         
  google_nacl_imc        ncvalidate             nrd_xfer               
  google_nacl_imc_c      ncvtest                sel                    
  google_nacl_npruntime  nonnacl_srpc           
  gtest                  nonnacl_util           
  all_libraries (do all of the above)

The following large tests can be run:
  run_service_runtime_tests  simple_tests               
  run_large_tests (do all of the above)

The following tests can be run:
  run_service_runtime_tests  simple_tests               
  run_all_tests (do all of the above)

The following bundles can be built:
  /Users/amachang/nc/nacl/googleclient/native_client/scons-out/dbg-mac/staging/npGoogleNaClPlugin.bundle  
  all_bundles (do all of the above)

The following programs can be built:
  client                 ncval                  sel_universal          
  nacl_cpuid             npGoogleNaClPlugin     server                 
  nacl_ldt_unittest      npapi_test             service_runtime_tests  
  ncdecode_table         nrd_xfer_test          
  ncdis                  sel_ldr                
  all_programs (do all of the above)

Use scons -H for help about command-line options.

おおお。このツールでなんでも作れるみたいですね。
さっそく Firefox のプラグインをインストールします。

$ ./scons --prebuilt firefox_install
scons: Reading SConscript files ...
======================================================================
Building nexe binaries using sdk at [/Users/amachang/nc/nacl/googleclient/native_client/tools_bin/mac/sdk/nacl-sdk]
======================================================================
*** Solution file generation skipped (not supported on this platform).
scons: done reading SConscript files.
scons: Building targets ...
/System/Library/Frameworks/Python.framework/Versions/2.5/Resources/Python.app/Contents/MacOS/Python ./tools/firefoxinstall.py MODE=0 PLATFORM_BASE="/Users/amachang/nc/nacl/googleclient/native_client/scons-out/"
MODE=0
PLATFORM_BASE=/Users/amachang/nc/nacl/googleclient/native_client/scons-out/
This script will install:
   /Users/amachang/nc/nacl/googleclient/native_client/scons-out/opt-mac/staging/npGoogleNaClPlugin.bundle in /Users/amachang/Library/Internet Plug-Ins/npGoogleNaClPlugin.bundle
   /Users/amachang/nc/nacl/googleclient/native_client/scons-out/opt-mac/staging/sel_ldr in /Users/amachang/Library/Internet Plug-Ins/npGoogleNaClPlugin.bundle/Contents/Resources
and
/Users/amachang/nc/nacl/googleclient/native_client/scons-out/opt-mac/Frameworks/SDL.framework in /Users/amachang/Library/Frameworks/SDL.framework
Okey to continue? [y/n]

sel_ldr や SDL.framework や npGoogleNaClPlugin.bundle がインストールされる見たいですね。
良ければ、 y と答えます。

Okey to continue? [y/n] y
Okay, you asked for it.
copying directory /Users/amachang/nc/nacl/googleclient/native_client/scons-out/opt-mac/staging/npGoogleNaClPlugin.bundle to /Users/amachang/Library/Internet Plug-Ins/npGoogleNaClPlugin.bundle ...
copying directory /Users/amachang/nc/nacl/googleclient/native_client/scons-out/opt-mac/Frameworks/SDL.framework to /Users/amachang/Library/Frameworks/SDL.framework ...
copying /Users/amachang/nc/nacl/googleclient/native_client/scons-out/opt-mac/staging/sel_ldr to /Users/amachang/Library/Internet Plug-Ins/npGoogleNaClPlugin.bundle/Contents/Resources ...
*********************************************************************
* You have successfully installed the NaCl Firefox plugin.
* As a self-test, please confirm you can run
*     /Users/amachang/Library/Internet Plug-Ins/npGoogleNaClPlugin.bundle/Contents/Resources/sel_ldr
* from a shell/command prompt. With no args you should see
*     No nacl file specified
* on Linux or Mac and no output on Windows.
*********************************************************************
* To test this installation also try the test links on the page
*     scons-out/nacl/staging/index.html
*********************************************************************
scons: done building targets.

おおお。成功したみたいです。

ブラウザでサンプルを見てみる。

さっそく、 Firefox を起動して、 scons-out/nacl/staging/earth.html を見てみましょう。

おおおおおお。めっちゃ軽いです!

自分で動くものを作ってみる

では、さっそく何か作ってみましょう。

足し算するだけの nexe を作ってみる

まずは、以下のような add.c というファイルを作ります。

#include <nacl/nacl_srpc.h>

int Add(NaClAppArg **in_args, NaClAppArg **out_args) {
    out_args[0]->u.ival = in_args[0]->u.ival + in_args[1]->u.ival;
    return RPC_OK;
}

NACL_SRPC_METHOD("add:ii:i", Add);

次に、以下のような add.html を作ります。

<!DOCTYPE html>
<html>
    <head>
        <title>test</title>
  </head>
  <body>
      <embed id="nacl" type="application/x-nacl-srpc" width="0" height="0" src="add.nexe" />
      <a href="javascript:void(0);" onclick="alert(document.getElementById('nacl').add(1, 2))">1 + 2 = ?</a>
  </body>
</html>

で、以下のようにコンパイルします。
長い人は PATH を通してしまいましょう。

$ nacl/googleclient/native_client/tools_bin/mac/sdk/nacl-sdk/bin/nacl-gcc -lsrpc -lgoogle_nacl_imc -lpthread -static add.c -o add.nexe

完成しました。
さっそくブラウザで見てみましょう。

おおお。足し算が出来ました!

文字列の diff を取る nexe を作ってみる

http://labs.unoh.net/2008/11/diff_with_c.html で紹介されている Google Code Archive - Long-term storage for Google Code Project Hosting. という diff ライブラリを使います。
まず、このライブラリの dtl.hpp を同じディレクトリに置きます。
次に、以下のような C++ のコードを書き diff.cpp とします。

#include "dtl.hpp"
#include <iostream>
#include <vector>
#include <sstream>
#include <nacl/nacl_srpc.h>

std::string diff(std::string as, std::string bs) {
    using namespace std;
    using namespace dtl;

    // 文字列を行にバラす
    istringstream ais(as);
    istringstream bis(bs);
    string buf;
    vector<string> av, bv;
    while(getline(ais, buf)) av.push_back(buf);
    while(getline(bis, buf)) bv.push_back(buf);

    // Diff を取る
    Diff<string, vector<string> > d(av, bv);
    d.compose();
    Ses<string> ses = d.getSes();    
    vector< pair<string, elemInfo> > v = ses.getSequence();

    // 結果を ostringstream に HTML 形式で出力する
    ostringstream os;
    vector< pair<string, elemInfo> >::iterator it;
    for (it = v.begin(); it != v.end(); ++it) {
        switch (it->second.type) {
            case SES_ADD :
                os << "<li class=\"add\">" << it->first << "</li>\n";
                break;
            case SES_DELETE :
                os << "<li class=\"delete\">" << it->first << "</li>\n";
                break;
            case SES_COMMON :
                os << "<li class=\"common\">" << it->first << "</li>\n";
                break;
            default :
                break;
        }
    }

    return os.str();
}

// SRPC で呼び出される関数
int Diff(NaClAppArg **in_args, NaClAppArg **out_args) {
    // diff 関数を呼び出す
    out_args[0]->u.sval = strdup(diff(in_args[0]->u.sval, in_args[1]->u.sval).c_str());
    return RPC_OK;
}

// diff:ss:s は、文字列を2つ受け取って文字列を返すという意味
NACL_SRPC_METHOD("diff:ss:s", Diff);

そして、さきほどと同じようにコンパイルします。

$ nacl/googleclient/native_client/tools_bin/mac/sdk/nacl-sdk/bin/nacl-g++  -lsrpc -lgoogle_nacl_imc -lpthread -static diff.cpp -o diff.nexe

今回は C++ なので nacl-g++ を使っているところに注意してください。
diff.nexe が出来たので、以下のような diff.html を作ります。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Diff Sample</title>
        <style type="text/css">
            html { width: 100%; margin: 0; padding 0; }
            body { width: 96%; margin: 2%; padding 0; }
            body > div { float: left; width: 50%; }
            body > div > textarea { width: 90%; height: 10em; }
            ul { list-style-type: none; margin: 0; padding: 0 }
            li { white-space: pre }
            li.add { color: #080; background: #8f8; }
            li.delete { color: #800; background: #f88; }
        </style>
        <script type="text/javascript">
            var result, nacl, text1, text2;
            window.onload = function() {
                result = document.getElementById('result');
                nacl   = document.getElementById('nacl');
                text1  = document.getElementById('text1');
                text2  = document.getElementById('text2');
            };
        </script>
    </head>
    <body>
        <h1>Diff Sample</h1>
        <div>
            <h2>Text 1</h2>
<textarea id="text1">
function fib(n){
    if(n == 1 || n == 2){
        return 1;
    }else{
        return fib(n - 1) + fib(n - 2);
    }
}
</textarea>
        </div>
        <div>
            <h2>Text 2</h2>
<textarea id="text2">
function fibonatti(n){
    if(n == 1 || n == 2){
        return 1;
    }else{
        return fibonatti(n - 1) + fibonatti(n - 2);
    }
}
</textarea>
        </div>
        <p> <a href="javascript:void(0);" onclick="result.innerHTML = nacl.diff(text1.value, text2.value);">diff!</a> </p>
        <ul id="result"></ul>
        <embed id="nacl" type="application/x-nacl-srpc" width="0" height="0" src="diff.nexe" />
    </body>
</html>

そして、ブラウザで読み込むと、、、

おおおおおお。 diff が取れました!

自分で Native Client の実行環境をビルドしてみる

いったん clean して

$ ./scons --mode=dbg-mac,nacl - c

デバッグビルドします。

$ ./scons --mode=dbg-mac,nacl

普通に成功しました。
で、 firefox にデバッグ版をインストールします。

$ ./scons firefox_install DBG=1

でも、どうやったらデバッグできるんだろう orz
ドキュメントには、以下のようにインクルードして、普通のローカルアプリケーションとしてビルドすれば、 gdb でも kdbg でもなんでも出来るよね!というようなことが書いてありました。

#if !defined(STANDALONE)
#include <nacl/nacl_srpc.h>
#else
#include "native_client/common/standalone.h"
#endif

どうやって nexe は実行されるか

ちょっと調べてみます。

sel_ldr が別プロセスとして立ち上がってる
$ ps auwx | grep sel_ldr
amachang 17617   0.0  0.3  1139488   6256   ??  S     8:50PM   0:00.12 /Users/amachang/Library/Internet Plug-Ins/npGoogleNaClPlugin.bundle/Contents/Resources/sel_ldr -f /Users/amachang/nc/sample/diff/diff.nexe -i 5:42 -P 5 -X 5

ページをロードするごとに、一つ sel_ldr プロセスが立ち上がるみたいです。
これと Firefox がどうにか通信しているんですね。

どうやって、 nexe にジャンプするか

service_runtime/nacl_switch.S というアセンブラがあって、以下のようにジャンプしています。

    .text
    .globl  IDENTIFIER(NaClSwitch)
IDENTIFIER(NaClSwitch):
    popl    %eax  /* throw away the return addr */

    /* do not leak info to app */
    xorl    %ecx, %ecx
    /* xorl will leave eflags in a known state, so no info leaks */
    popl    %edx  /* new eip */
    popl    %ebp
    popl    %edi
    popl    %esi
    popl    %ebx

    popl    %gs 
    popl    %fs 
    popl    %es 

    ljmp    *(%esp)
飛んだ先はどうなっているか

diff.cpp には main がありませんでした。どこに飛ぶのでしょうか。
libsrpc.a に main が weak シンボルで定義されていました。

int __attribute__ ((weak)) main(int argc, char* argv[]) {
  /*  
   * Print the methods that are available.
   __NaClPrintRpcMethods();
   */

  srpc_init();
  /*  
   * Message processing loop goes here.  For now, just do a sel_universal.
   */
  __CommandLoop();

  return 0;
}

では __CommandLoop では何をやっているのでしょうか。

__CommandLoop では何をやっているのか

__CommandLoop は以下のようになっていました。

NaClSrpcError __CommandLoop() {
:
:
  socket_desc = __srpc_get_fd();
  if (socket_desc == -1) {
    /*  
     * No socket connection, use stdin/stdout.
     */
    rpc_desc = __BuildInterfaceDescription(&num_rpc);
    // process commands from stdin and dispatch
    for (;;) {
:
:
    } 
  } else {
    NaClSrpcChannel channel;
:
:
    for (;;) {
:
:
    }
:
:
  }
  return RPC_OK;
}

コメントを見る限りは、ソケット通信しているかどうかでループを分けています。

SRPC メッセージのフォーマットは?

tools/libsrpc/rpc_serialize.c のコメントのところに書いてあります。

SRPC の解析処理 → 関数実行の流れ

Firefox からデータが送られてくると tools/libsrpc/rpc_serialize.c の以下の箇所で rpc_number が抽出され

:
  retval = ImcRead(&client_protocol, sizeof(client_protocol), 1, channel);
:
  retval = ImcRead(&rpc_number, sizeof(rpc_number), 1, channel);
:

以下の箇所で、実際にアプリケーションに書いたあれらの関数(さっきの例の Add や Diff)が呼び出されます。

 app_error = (channel->rpc_descr[rpc_number].handler)(args, rets);

また、ページ遷移すると Firefox から NACL_SRPC_SHUTDOWN_METHOD というメッセージが送られてきて
以下の SRPC のメソッドが呼ばれ、 nexe は終了します。

static int srpc_shutdown_request(NaClAppArg **in_args, NaClAppArg **out_arg) {
  if (srpc_privileged) {
    _exit(0);
  }
  return RPC_OK;
}

NACL_SRPC_METHOD("shutdown::", srpc_shutdown_request);

このメッセージ(NACL_SRPC_SHUTDOWN_METHOD)は、 JavaScript からも element.shutdown() というように呼び出すことで送出することが出来ます。

まとめ

そろそろまとめますよっと。とりあえず試してみた Native Client ですが、ちょっと難しかったです><
でも、ネイティブのコードが動くというのはやっぱり凄いですね。
Alchemy のようなアプローチでは(C → LLVM → AS → ABC という感じ)、やはり速度には限界がありますし。
ただ、セキュリティをどうやって確保しているのかが気になりますね。もちろん、ウェブページに埋め込むようなものなのできちんとしたサンドボックスが必要ですよね。時間があるときに、そこら辺も調べてみたいですね。
もし、セキュリティ上問題がないのなら、これ以上最強なものはないのではないでしょうか。

追記:id:moira さんがそこら辺のことに言及されています

http://blog.deadbeaf.org/2008/12/09/google-native-client/
さすがです><