Hatena::Groupsubtech

ういはるかぜの化学

Friday, December 16, 2011

[]JavaScript エンジン Chakra を無理矢理使う。 15:01 JavaScript エンジン Chakra を無理矢理使う。 - ういはるかぜの化学 を含むブックマーク はてなブックマーク - JavaScript エンジン Chakra を無理矢理使う。 - ういはるかぜの化学

こんにちは。JavaScript Advent Calendar 2011 オレ標準コース16日目です。

Internet Explorer 9で新たに導入されたJavaScript エンジン、Chakraを非公開な方法で使うという誰得な話です。

はじめに

WindowsにはJavaScriptMicrosoft実装であるJScriptVBScriptなどスクリプト言語(サードパーティー製でPerlとかRubyとかもある)をいい感じにあつかうActiveScriptという枠組みがあり、それを使ってスクリプトを実行するWSH(Windows Scripting Host)というのがあります。

Cscript.exeとかWscript.exeといったものがそれです。Windowsでなんとか.jsという名前で保存してダブルクリックすると起動するのはWscript.exeです。ActiveScriptはスクリプトエンジン、WSHはそれをホストして機能を提供するものと覚えておけばよいでしょう。

JScriptのバージョン

そんなJScriptにはバージョンがあります。大体IEとセットでバージョンアップしていくのでIE7で5.7、IE8で5.8となっています。詳しくはJScript のバージョン情報に書いてあります。

7(.NET 1.x)と8(.NET 2.0)と10(.NET 4)は.NETJScriptで、IE9Chakraは位置づけ的にはJScriptエンジンではなくJavaScriptエンジンとしてるようですが 9となっています。たぶんIE10は10でかぶりそうですが.NET版は忘れましょう。

WSHChakra

IE9の話に戻りますがChakraIE9をインストールすると勝手に入ります。それならばと思ってWSHJavaScriptを実行すると残念なことにJScript 5.8で動作します。

試しにIE9の入っている環境で以下のプログラムを実行してみます。

WScript.Echo(ScriptEngine() + '/' + [ScriptEngineMajorVersion(), ScriptEngineMinorVersion(), ScriptEngineBuildVersion()].join('.'));

するとJScript 5.8 (つまりIE8JavaScriptエンジンと同等)として動作します。

C:\Users\Tomoyo\Desktop>cscript //NoLogo test.js
JScript/5.8.16982

なぜ5.8で動作しているのかというとChakraは今までのエンジンの実体が別になったためです。今まではJScript.dllというライブラリでしたがChakraは別にJScript9.dllという別なライブラリに分かれています。

じゃあJScript9.dllの方を呼び出せれば解決しそうです。JScript9.dllもActiveScriptエンジンとして登録されているのでWSHにそれを使うように指示すればよさそうです。

幸いWSHの実行ファイルWScript.exe/CScript.exeにはスクリプトエンジンを指定するコマンドラインオプション(//E)があるのでそれが使えます。例えば//E:JScriptとか//E:VBScriptとかという感じです。

JScript9のような名前は登録されていないのですが、若干裏技で呼び出せます。というわけで呼び出してみます。

C:\Users\Tomoyo\Desktop>cscript //NoLogo //E:{16d51579-a30b-4c8b-a276-0ff4dc41e755} test.js
JScript/9.0.16440

なかなかクールな名前ですね。それは置いておいてスクリプトエンジンのバージョンが9になりました。つまりChakraです。

しかしChakraが本当に使われているかわかりませんね。というわけで以下のようななんとなく時間のかかりそうな処理スクリプト( JavaScript でフィボナッチ数列を高速に求める - IT戦記からコピペしました)を実行してみます。

WScript.Echo(ScriptEngine() + '/' + [ScriptEngineMajorVersion(), ScriptEngineMinorVersion(), ScriptEngineBuildVersion()].join('.'));
function fib(i) {
  if(i == 0 || i == 1) return i;
  return fib(i-1) + fib(i-2);
}
var startAt = new Date();
fib(30);
WScript.Echo(new Date() - startAt + "ms");
C:\Users\Tomoyo\Desktop>cscript //NoLogo //E:JScript test.js
JScript/5.8.16982
3531ms

C:\Users\Tomoyo\Desktop>cscript //NoLogo //E:{16d51579-a30b-4c8b-a276-0ff4dc41e755} test.js
JScript/9.0.16440
1114ms

ちゃんと実行速度がはやくなりました。よかったよかった。

と思いきや一つ残念なお知らせがあります。5.8の時と同様にegtraさんが書いているように5.7互換モードで動作しています。

Chakraで動いても5.7互換モードなのでJSONやES5の素敵機能を使えません。単にWSHを高速に実行できるだけで、互換モードから5.8以降に変えることはできません。激しく残念。

Chakraをホストする

WSHではどうやっても5.7互換でしか動きませんでした。これはChakraに限らず5.8の時でも同様です。その部分はegtraさんが書かれていますが、自分でエンジンをホストする場合にはオプションを指定すれば5.8モードに変更できます。

とするともしかしてChakraもモードを指定すれば変わるのでは?と思いますよね。指定できるモードの説明IActiveScriptProperty::SetProperty | Microsoft Docs を読むと2 (SCRIPTLANGUAGEVERSION_5_8)とか書いてあるのでもしかして3かも?と思って3を指定したら見事に動作しました。

// WSHの時と同様にChakraエンジンを呼び出す
_engine = Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("16D51579-A30B-4C8B-A276-0FF4DC41E755"))) as IActiveScript;

var prop = _engine as IActiveScriptProperty;
Object invokeVer;
invokeVer = 3; // JScript9
hr = prop.SetProperty(/*SCRIPTPROP_INVOKEVERSIONING*/0x00004000, IntPtr.Zero, ref invokeVer);

JScript 9モードで動作するとJSONECMAScript 5thっぽい機能が使えるようになるのでホストする場合には幸せになれそうですね。

おまけ: Classic ASPChakra

ところでWindows ServerにはASPというActiveScriptを使ったサーバーサイドのWeb技術があります。

先ほどのChakraというかJScript9.dllのGUIDにちゃんと名前をつけてあげるとClassic ASPのlanguageで指定できるようになってASPで動くようになります。

無駄に高速なClassic ASPになりますがなぜか一度しかリクエストを処理できないので何の役に立ちません。

おしまい

明日は@polygon_planetさんです。