OS X Mountain Lion 10.8.5 上でウェブブラウザ Google Chrome に使われている JavaScript engine V8 を試す。

enchantMOON ; The Hypertext Authoring Tablet
http://enchantmoon.com/

賛否両論がある enchantMOON を 2013/07/13(Sat) にアスキーストアで予約しました。随分待たされましたが、2013/09/21(Sat) に到着しました。URL を入力して Web を開くシールを作ってみました。次回にでも公開したいと思います。

enchantMOON が到着するまでに時間があったので、以前から興味があった enchantMOON の JavaScript Based Virtual Machine (EAGLEVM) に利用されている V8 を試してみました。

Chrome V8 — Google Developers
https://developers.google.com/v8/

V8 は、ウェブブラウザ Google Chrome に使われている JavaScript engine です。プログラミング言語 C++ で書かれています。私の C++ の知識は、

C++ Primer(5th Edition)

C++ Primer (5th Edition)

C++ Primer (5th Edition)

を読んだ程度です。ほとんど C++ でプログラミングをしたことがない初心者です。

ソースのダウンロードは

How to Download and Build V8 - Chrome V8 — Google Developers
https://developers.google.com/v8/build
Source - v8 - How to get the V8 source code - V8 JavaScript Engine - Google Project Hosting
http://code.google.com/p/v8/wiki/Source

Git を使わず Subversion を利用しました。

ターミナル上で

~ $ svn checkout http://v8.googlecode.com/svn/trunk/ v8

上記コマンド svn を用いてソースコードを入手しました。

BuildingWithGYP - v8 - Instructions to build V8 using GYP - V8 JavaScript Engine - Google Project Hosting
http://code.google.com/p/v8/wiki/BuildingWithGYP

OS X Mountain Lion 上では GYP が正しく動作しないようなので、上記ページと v8/build/ReadMe.txt を参考に

~ $ cd v8
~/v8 $ make dependencies
~/v8 $ make x64.release
~/v8 $ make x64.release.check

上記コマンドを実行しました。

Getting Started - Chrome V8 — Google Developers
https://developers.google.com/v8/get_started
Getting Started
Audience
Hello World
Run the Hello World example

上記ページ、最初に紹介されている Hello World のソースは handle、scope、context が追加されていないので、ビルドできません。その下の Hello World サンプルソースを hello_world.cc として保存し、v8 フォルダにコピーします。ターミナル上で次のコマンド

~/v8 $ g++ -Iinclude hello_world.cc -o hello_world out/x64.release/libv8_base.x64.a out/x64.release/libv8_snapshot.a out/x64.release/libicu{data,i18n,uc}.a -lpthread

を実行するとビルドできました。実際に hello_world を実行すると次のように

~/v8 $ ./hello_world
Hello, World!
~/v8 $ 

表示されます。

ディレクトリ v8/out/x64.release には

~/v8 $ cd out/x64.release/
~/v8/out/x64.release $ ls
cctest			libv8_nosnapshot.x64.a	obj.target
d8			libv8_snapshot.a	preparser
libicudata.a		lineprocessor		process
libicui18n.a		mksnapshot.x64		shell
libicuuc.a		obj
libv8_base.x64.a	obj.host
~/v8/out/x64.release $ 

hello_world.cc のビルドに必要なライブラリ

libv8_base.x64.a
ibv8_snapshot.a
libicudata.a
libicui18n.a
libicuuc.a

と v8/samples のサンプルをビルドした実行ファイル

shell
process
lineprocessor

Javascript インタプリタ d8 が含まれています。以下が d8 の実行例です。

~ $ cd v8/out/x64.release/
~/v8/out/x64.release $ ./d8
V8 version 3.22.1 [console: dumb]
d8> var x=Math.sqrt(2);
undefined
d8> x
1.4142135623730951
d8> var r = function(x,y,x1,y1) { return Math.sqrt((x1-x)*(x1-x)+(y1-y)*(y1-y)); };
undefined
d8> r(0,0,1,1);
1.4142135623730951
d8> r(0,0,1,Math.sqrt(3));
1.9999999999999998
d8> quit()
~/v8/out/x64.release $ 

v8/samples ディレクトリのサンプルソースを理解するには、

~ $ cd v8/samples
~/v8/samples $ ls
count-hosts.js		process.cc		shell.cc
lineprocessor.cc	samples.gyp
~/v8/samples $ 
Getting Started - Chrome V8 — Google Developers
https://developers.google.com/v8/get_started
Getting Started
Embedder's Guide - Chrome V8 — Google Developers
https://developers.google.com/v8/embed
▼ Documentation
Embedder's Guide

上記ページが参考になります。サンプル Hello World や Contexts、自作の関数を定義するのに利用する Templates など、基本的な仕組みを理解するのに便利です。

v8: v8::String Class Reference
http://izs.me/v8-docs/classv8_1_1String.html

また、上記ページで各クラスの説明を見ることができます。ディレクトリ v8/src、v8/include には、ソースやヘッダがあるので勉強になると思います。

私自身、初歩的なことがわかっていなかったので、

// hello_world.cc
Handle<String> source = String::New("'Hello' + ', World!'");

の String::New() は Local 返すのに Handle に代入していたので、疑問に思っていたのですが、Local は Handle を継承しているのですね!

また、process.cc 351行目

string ObjectToString(Local<Value> value) {
String::Utf8Value utf8_value(value);
return string(*utf8_value);
}

の *utf8_value が理解できなかったのですが、

~ $ cd v8/include
~/v8/include $ grep -e "class V8_EXPORT Utf8Value" *.h
v8.h:  class V8_EXPORT Utf8Value {
~/v8/include $ 
// ~/v8/include/v8.h 1838 行目
class V8_EXPORT Utf8Value {
public:
explicit Utf8Value(Handle<v8::Value> obj);
~Utf8Value();
char* operator*() { return str_; }
const char* operator*() const { return str_; }
int length() const { return length_; }

String::Utf8Value には、上の char* operator*() { return str_; } ように * 演算子が定義されているのですね!

Sample Code - Chrome V8 — Google Developers
https://developers.google.com/v8/samples
▼ Documentation
Sample Code

上記ページでサンプルコード、process.cc、shell.cc の簡単な説明があります。

~/v8/samples $ ls
count-hosts.js		process.cc		shell.cc
lineprocessor.cc	samples.gyp
~/v8/samples $ 

上記 v8/samples ディレクトリあるサンプルコード shell.cc、process.cc、lineprocessor.cc を説明したいと思います。

説明をしやすいように、下記のようにディレクトリ v8/samples 内のすべてのファイルをディレクトリ v8/out/x64.release/ に cp コマンドを使ってコピーしました。

~ $ cd v8/samples/
~/v8/samples $ cp *.* ../out/x64.release/
~/v8/samples $ 

■サンプルコード shell.cc

shell.cc は、コマンドライン引数として –help、–shell、ファイル名を指定できます。

~ $ cd v8/out/x64.release/
~/v8/out/x64.release $ ./shell
V8 version 3.22.1 [sample shell]
> 1+1
2
> var x=1;
> print(x);
1
> var text = read("shell.cc");
> print(text);
....
> load("count-hosts.js");
> version();
3.22.1
> quit();
~/v8/out/x64.release $ 

shell.cc
99行目より、自作関数として print()、read()、load()、quit()、version() が使えます。

print(x)		: 引数を表示する。
read(filename)	: 引数のファイルを読み込む
load(filename)	: 引数のファイルを読み込み、コンパイルして実行する。
quit()			: プログラム終了
version() 		: バージョン表示

shell のコマンドライン引数に javascript ファイルを指定すると javascript ファイルを実行します。

~/v8/out/x64.release $ ./shell count-hosts.js
~/v8/out/x64.release $ 

実行した後、shell モードに入りたい場合は、コマンドライン引数に –shell を指定します。

~/v8/out/x64.release $ ./shell count-hosts.js --shell
V8 version 3.22.1 [sample shell]
> Initialize();
> var request = {host:"localhost", path:"/", referrer:"apple.com", userAgent:"Safari"};
> var options = {verbose:0};
> var output = {};
> Process(request);
> print(output);
[object Object]
> print(request.host);
localhost
> print(output["localhost"]);
1
> quit();
~/v8/out/x64.release $ 

■サンプルコード process.cc

process.cc は v8/samples ディレクトリある Javascript ファイル count-hosts.js を利用します。

プログラム process.cc 内で log 関数、変数 options.verbose、output を作り、process.cc 599行目

const int kSampleSize = 6;
StringHttpRequest kSampleRequests[kSampleSize] = {
StringHttpRequest("/process.cc", "localhost", "google.com", "firefox"),
StringHttpRequest("/", "localhost", "google.net", "firefox"),
StringHttpRequest("/", "localhost", "google.org", "safari"),
StringHttpRequest("/", "localhost", "yahoo.com", "ie"),
StringHttpRequest("/", "localhost", "yahoo.com", "safari"),
StringHttpRequest("/", "localhost", "yahoo.com", "firefox")
};
StringHttpRequest("/process.cc", "localhost", "google.com", "firefox"),
を例にとると
var request = {path:"/proces.cc", host:"localhost",  referrer:"google.com", userAgent:"firefox"};
になります。

で宣言されているそれぞれの request を Javascript ファイル count-hosts.js 内の Process 関数で呼び出します。結果が、変数 output に格納されます。output の内容は、process,cc 652行目

PrintMap(&output);

で表示します。実行結果は

~/v8/out/x64.release $ ./process count-hosts.js
google.com: 1
google.net: 1
google.org: 1
yahoo.com: 3
~/v8/out/x64.release $ 

になります。 ./process のコマンドライン引数として verbose=true を宣言すると log 関数が呼び出されます。

~/v8/out/x64.release $  ./process count-hosts.js verbose=true
Logged: Processing google.com/process.cc from localhost@firefox
Logged: Processing google.net/ from localhost@firefox
Logged: Processing google.org/ from localhost@safari
Logged: Processing yahoo.com/ from localhost@ie
Logged: Processing yahoo.com/ from localhost@safari
Logged: Processing yahoo.com/ from localhost@firefox
google.com: 1
google.net: 1
google.org: 1
yahoo.com: 3
~/v8/out/x64.release $ 

■サンプルコード lineprocessor.cc

lineprocessor は、コマンドライン引数として –main-cycle-in-cpp、–main-cycle-in-js のどちらかを指定することで違った動作をします。ループ処理を C++側か、Javascript 側で行うかの違いがあります。

サンプルコード lineprocessor.cc の 56 行目にある

function ProcessLine(input_line) {
return ">>>" + input_line + "<<<";
}

の部分を main-cycle-in-cpp.js という名前で保存します。

コマンドライン引数を main-cycle-in-cpp.js、–main-cycle-in-cpp とし、実行すると

~/v8/out/x64.release $ ./lineprocessor main-cycle-in-cpp.js --main-cycle-in-cpp
hello
>>>hello<<<
bye
>>>bye<<<
^C
~/v8/out/x64.release $ 

lineprocessor.cc 内で入力処理を行い、Javascript ファイルの関数 ProcessLine(input_line) を呼び出します。関数 ProcessLine(input_line) の返り値を下記 RunCppCycle 関数内の

    printf("%s\n", cstr);

で表示します。

272行目

bool RunCppCycle(v8::Handle<v8::Script> script,
v8::Local<v8::Context> context,
bool report_exceptions) {

lineprocessor.cc 側の上記 RunCppCycle 関数内でループ処理を行います。

サンプルコード lineprocessor.cc の 66 行目にある

while (true) {
var line = read_line();
if (!line) {
break;
}
var res = line + " | " + line;
print(res);
}

の部分を main-cycle-in-js.js という名前で保存します。

コマンドライン引数を main-cycle-in-js.js 、–main-cycle-in-js としてし、実行すると

~/v8/out/x64.release $ ./lineprocessor main-cycle-in-js.js --main-cycle-in-js
hello
hello | hello
bye
bye | bye
^C
~/v8/out/x64.release $ 

lineprocessor.cc 内で read_line() を定義し、Javascript 側でループ処理をおこないます。

lineprocessor.cc の肝は、デバッガに対応していることです。

Google Chrome Developer Tools for Java

V8 でデバッガを利用するには、Google Chrome Developer Tools for JavaEclipse が必要です。

chromedevtools - Google Chrome Developer Tools for Java - Google Project Hosting
http://code.google.com/p/chromedevtools/

が、参考になります。

2013/09/29(Sun) 現在、OS X Mountain Lion バージョン 10.8.5 上では、

~ $ java -version
java version "1.6.0_51"
Java(TM) SE Runtime Environment (build 1.6.0_51-b11-457-11M4509)
Java HotSpot(TM) 64-Bit Server VM (build 20.51-b01-457, mixed mode)
~ $ 

Java のバージョンは、1.6.0_51で問題ありません。

Eclipse は、余計なものがインストールされないように

Eclipse Downloads
http://www.eclipse.org/downloads/
Eclipse Standard 4.3.1, 196 MB
Downloaded 381 Times  Other Downloads
Mac OS X 64 Bit

から、一番上の Eclipse Standard 4.3.1, 196 MB Mac OS X 64 Bit をダウンロードしました。ダウンロードした eclipse-standard-kepler-SR1-macosx-cocoa-x86_64.tar.gz ファイルを Finder 上でダブルクリックして展開し、作成された eclipse フォルダを /アプリケーション フォルダに移動します。

eclipse を再インストールルする時は、/アプリケーション フォルダ内の eclipse フォルダ と ~/書類/workspace フォルダを削除してください。workspace フォルダには、不可視ファイルが含まれているので必ず削除してください。

DebuggerTutorial - chromedevtools - First steps of using Debugger. - Google Chrome Developer Tools for Java - Google Project Hosting
http://code.google.com/p/chromedevtools/wiki/DebuggerTutorial

上記 URL を参考に、SDK をインストールする必要があります。

/アプリケーション/eclipse フォルダ 内の Eclipse を Finder 上でダブルクリックして起動します。

メニュー Help/Install New Software…. を選びます。

図 1

図 1の一番上のテキストフィールド Wok with: に

http://chromedevtools.googlecode.com/svn/update/dev/

を入力します。Add ボタンをクリックします。

図 2

図 2 のダイアログが開くので、Name: に

Google Chrome Developer Tools

と入力して OK ボタンをクリックします。

図 3

図 3 の中央に表示される大きなエリアの Google Chrome Developer Tools 横にある ▼ をクリックして開きます。

Chromium JavaScript Remote Debugger” にチェックを入れます。

後は Next > ボタンを 2 回クリックし、ライセンス同意ボタンを選択して終了します。途中、セキュリティ警告が表示されますが、OK ボタンをクリックしてください。

■サンプルコード lineprocessor.cc をデバッガで試す

AddDebuggerSupport - v8 - Adding debugger support to application HOW-TO. - V8 JavaScript Engine - Google Project Hosting
http://code.google.com/p/v8/wiki/AddDebuggerSupport

上記 URL が参考になります。

まず、最初にターミナルで、コマンドライン引数 -p 9222、–callback を追加して lineprocessor 実行します。

~/v8/out/x64.release $ ./lineprocessor -p 9222 main-cycle-in-cpp.js --main-cycle-in-cpp --callback

それから、

図 4

図 4のように Eclipse を起動、メニュー Run/Debug Configurations… を選択します。

図 5

図 5 のように、左エリア内の Standalone V8 VM を選択して、上部ノートに + が付いたアイコンをクリックします。図 6のように設定が新規に作成されます。

図 6

図 6 のように remote タブの Host: localhost、Port: 9222、show debugger network cominucation console にチェックを入れます。 Apply ボタンをクリックしてから Debug ボタンをクリックします。

図 7

上図のように表示されます。左上の一番上のアイコンをクリックすると下図のように表示されます。

図 8

Project Explorer の New_configuration の▼を開き、main-cycle-in-cpp.js をダブルクリックして開きます。
ソース main-cycle-in-cpp.js のブレークポイントを仕掛けたい行をクリックすると、図 9 のように青色反転させます。

図 9

図 10

図 10 のメニュー ‘Run’/’Add V8/Chrome Javascript Exception Breakpoint’/’Togle Line Breakpoint’ を選択して、ブレークポイントを仕掛けます。

図 11

ターミナル側で

./lineprocessor capitalizer.js -p 9222 --main-cycle-in-cpp --callback
hello

hello と文字を入力して Return キーを押します。

するとブレークポイントで実行が止まり、デバッガーを表示していいか尋ねてくるので、Yes ボタンをクリックします。

Variables タブで、変数 input_line に “Hello” という文字列が渡されているのが確認できると思います。

メニュー Window/Show Toolbar を選び、ツールバーを表示します。ツールバーの赤色正方形の横にステップイン、ステップオーバーなどのボタンがあります。

図 12

Resume ボタン(緑色の再生ボタン) 押すとターミナル側で

~ $ cd v8/out/x64.release/
~/v8/out/x64.release $ ./lineprocessor -p 9222 main-cycle-in-cpp.js --main-cycle-in-cpp --callback
hello
>>>hello<<<

図 13

>>>hello<<< という文字が表示されます。ターミナルで CTRL + C を押せば終了させることができます。

また、main-cycle-in-js.js、–main-cycle-in-js のコマンドライン引数を lineprocessor に渡しても、同じようにデバッガを使うことができます。

~/v8/out/x64.release $  ./lineprocessor main-cycle-in-js.js --main-cycle-in-js  -p 9222 --callback
hello

変数 line の内容を表示するには、ソースの line という文字にカーソルを合わせます。 図 14 のように “hello”というポップアップが現れます。

while (true) {
var line = read_line();
if (!line) {
break;
}
var res = line + " | " + line;
print(res);
}

図 14

Myst、Bento、VMware Fusion、Windows 7 RC、Ubuntu 9.04 日本語版、Android 1.5 SDK、YouTube キャプチャー動画公開

iTunesApp Store で公開されるアプリは iPhone OS 3.0 上で動作することが必須になったので、遅ればせながら iPhone SDK 3.0 beta 5 をインストールしました。問題なく動作しています。

iTunes 上のApp Store で、次の2つの iPhoneiPod touch 用アプリケーションを購入してみました。

Myst
カテゴリ/ゲーム
\700
http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=311941991&mt=8
Bento
カテゴリ/仕事効率化
\600
http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=314638461&mt=8

ずいぶん昔になりますが、Mystセガサターン(コンシューマ用ビデオゲーム機)で遊んだ記憶があります。エンディングを見たかは覚えていませんが、攻略本は確か購入したはずです。現在はなくしてしまいましたが!iPhoneiPod touch 版の Myst は 727 MB もあります。私の iPod touch は 32GB 版なので、容量的には問題はありません。日本語にはローカライズされていませんが、懐かしかったので購入してしまいました。本当によくできています。

私は試していませんが

How To Beat Myst on the iPhone in 5 Minutes | Mac|Life
http://www.maclife.com/article/howtos/how_beat_myst_5_minutes

で 5分でエンディングが見れるようです。

Bento はあまり使用していないので、判断しにくいですね。 Cover Flow のインターフェイスは面白いのですが、私が使った限り機能的には実用性に乏しいと思いました。

また Windows 7 RC 版が公開されました。

Windows 7 にようこそ
http://www.microsoft.com/japan/windows/windows-7/default.aspx

当たり前かもしれませんが、Mac OS X 上の Safari から Windows 7 RC版をダウンロードを試みましたが無理でした。VMware Fusion 上の Windows XP Professional から IE を使ってダウンロードしました。(Windows Live ID が必要でしたので MSN Hotmail アカウントを新規登録せず Gmail のメールアドレスを使って作成しました。)

VMware Fusion を使って Windows 7 RC 版 ‘仮想マシン‘ を作成するために

VMware: Team Fusion: Windows 7 on Mac with VMware Fusion: A Practical Guide Revisited
http://blogs.vmware.com/teamfusion/2009/05/windows-7-on-mac-with-vmware-fusion-a-practical-guide-revisited.html

上記ページを参考にしました。別に難しいところはありません。気をつけるところは

オペレーティング システム: Microsoft Windows
バージョン: Windows Vista (64版のときは Windows Vista x64 Edition)

と設定するぐらいです。何の問題もなくインストールできました。正常に動作しています。

VMware: Team Fusion: Windows 7 on Mac with VMware Fusion: A Practical Guide Revisited
http://blogs.vmware.com/teamfusion/2009/05/windows-7-on-mac-with-vmware-fusion-a-practical-guide-revisited.html
Stop Windows 7 From Suspending Itself Every 30 Minutes

は設定しておくべきです。実行画面を添付しておきます。

話は変わって

Ubuntu Desktop 日本語 Remix CDのダウンロード | Ubuntu Japanese Team
http://www.ubuntulinux.jp/products/JA-Localized/download

Ubuntu 9.04 日本語版が公開されたので ‘BitTorrent プロトコル対応のファイル共有ソフト’ Transmission を使ってダウンロードしました。また Android 1.5 SDK, Release 1も発表されていたので

Android 1.5 SDK, Release 1 | Android Developers
http://developer.android.com/sdk/1.5_r1/index.html

Ubuntu 9.04 日本語版に

Installing the Android SDK | Android Developers
http://developer.android.com/sdk/1.5_r1/installing.html

Android 1.5 SDK, Release 1 をインストールしてみました。AVD について詳しく述べられていないので

Developing In Eclipse, with ADT | Android Developers
http://developer.android.com/guide/developing/eclipse-adt.html
Running Your Application
Android Virtual Devices | Android Developers
http://developer.android.com/guide/developing/tools/avd.html

を参考に作成しました。

簡単に言えば、アプリケーション ‘端末’ 上で

android create avd -n my_android1.5 -t 2
android create avd -n my_android1.1 -t 1

を実行しただけです。

また、Hello, Android: Introducing Google‘s Mobile Development Platform

のサンプルをビルドする方法を記載しておきます。Hello, Android 本は

日本語訳も発売されているようです。

Upgrading the SDK | Android Developers
http://developer.android.com/sdk/1.5_r1/upgrading.html#UpdateYourProjects
Update Your Projects

上記資料が参考になります。

まず最初に、Eclipse のメニュー ‘File/Import…’ を選び

‘General’ タブの ‘Existing Projects into Workspace’ を選択し、Next ボタンを押します。

ウインドウが開いたら ‘Select root directory’ の ‘Browse…’ ボタンを押し、読み込みたいプロジェクトのフォルダを指定します。(ここではサンプル OpenGL で説明します。)

‘Copy projects into workspace’ にチェックを入れ、’Finish’ ボタンを押します。これでプロジェクトが読み込まれます。このままではエラーが出て Run できません。そこで次の設定を行ってください。

エラー:
Android requires .class compatibilitiy set to 5.0. Please fix project properties.

というエラーが出るので、プロジェクト名 OpenGL を右クリック、メニュー ‘Properties/Java Compiler’ を選び、

‘Enable project specific settings’ にチェックを入れます。(これで正しいのか自信はありません) ‘Apply’ ボタンを押し適用した後、

エラー:
Project has no target set. Edit the project properties to set one.

のエラーを取り除くため、’Android‘ を選択し (プロジェクト名 OpenGL を右クリック、メニュー ‘Properties/Android‘)、’Project Build target’ の ‘Target Name’ を選択します。通常 ‘Android 1.5′ にチェックを入れます。’Apply’ ボタンを押して適用し、OK ボタンを押します。

エラー:
The type R is already defined             R.java

上のエラーは ファイル R.java が重複して存在するためです。Project Explorer 上の OpenGL で ファイル ‘gen/org.example.opengl/R.java‘ を確認した後、ファイル src/org.example.opengl/R.java を右クリックして Delete を選び、削除してください。

警告:
WARNING: Application does not specify an API level requirement !

と警告が出るので ‘AndroidManifest.xml‘ に設定を追加する必要があります。

Android 1.5 Version Notes | Android Developers
http://developer.android.com/sdk/android-1.5.html

を参考に Project Exploer 上で ファイル ‘AndroidManifest.xml‘ をダブルクリックし、表示されたソースの右下部分 ‘AndroidManifest.xml‘ タブをマウスで選択し ‘Sdk version’ を次のように指定します。


...

...

Eclipse のメニュー ‘File/Save’ を選択し、ファイル ‘AndroidManifest.xml‘ を保存してください。後は、プロジェクト名 OpenGL を右クリック、メニュー ‘Run As/Android Application’ を選択すれば動作を確認できます。

Linux デスクトップ上の操作を録画できる動画キャプチャーソフト ‘XVidCap Screen Capture’ 、Mac の動画変換ソフト ‘携帯動画変換ちゃん’、’iMovie‘ を使ってデスクトップを録画、編集し、YouTube に投稿してみました。添付しておきます。