TryCatch のスコープではまること

V8 における文字列の評価処理は、だいたい次のような流れをとります。

  const char* lpszScript = ...;
  
  HandleScope handle_scope;
  TryCatch try_catch;
  Local<Script> script = Script::Compile(String::New(lpszScript));
  if (script.IsEmpty()) {
    ReportException(try_catch.Exception());
  } else {
    Local<Value> result = script->Run();
    if (result.IsEmpty()) {
      ReportException(try_catch.Exception());
    } else {
      Print(result);
    }
  }

コマンド入力だったらこんなのでよいかもしれませんが、スクリプトをファイルから読み込ませるような関数を書いている場合、その場で ReportException を呼ぶより、外に例外を投げる方が設計上好ましいように思われます。とにかくそこからは例外で脱出して、インタプリタのトップレベルによって一度だけ例外を報告させることができるからです。
V8 でコールバックが例外を投げる場合は、ThrowException() という関数を使ってそのまま return するように求められていますが、上のコードをそのまま流用したりして、直感的にはだいたいこんな感じで書いてしまいがちです。

  HandleScope handle_scope;
  TryCatch try_catch;
  Local<Script> script = Script::Compile(String::New(lpszScript));
  if (script.IsEmpty()) {
    return ThrowException(try_catch.Exception());
  }
  Local<Value> result = script->Run();
  if (result.IsEmpty()) {
    return ThrowException(try_catch.Exception());
  }

実はこれは正しく動きません。

続きを読む

Weak handle にも Dispose の愛の手を

http://groups.google.com/group/v8-users/browse_thread/thread/d0c8bd822ce21f9e
http://d.hatena.ne.jp/tossy-2/20090123/1232653840


最近の v8-users のログを見たらちょうど話題にあがっていたので、ちょっとエントリ修正。
上記エントリでデストラクタの呼び出しを GC 任せにする手法が導入されていますが、weak handle にするために作った Persistent のハンドルが Dispose されていませんでした。
たしかに、ヒープ内のハンドルをおっかけていると、参照のない weak handle は GC サイクルで NEAR_DEATH (=WeakReferenceCallback が呼ばれた)状態になりますが、DESTROYED (=ハンドルが解放され、フリーになった)状態にはなりません。
よく考えれば、ハンドル自体への参照がある「かもしれない」状態で、勝手に自分を delete したりするのは危険ですから(dangling pointer になってしまうので)、ハンドル側ではそこらへんのケアをしないのはまったく当然です。


ということで、正しくはコールバックを次のように書く必要があるそうです。

static void hoge_Destructor(v8::Persistent<v8::Value> handle, void* parameter)
{
  delete static_cast<hoge*>(parameter); // ...など

  handle.Dispose(); // ここでハンドルを解放する
}

V8 のバージョンがあがったようです

昨日コミットされた r1243 で、バージョン文字列が 1.0.0 になったようです。
ライブラリをビルドしなおして、テスト用のアプリのほうも…とおもったら winmm.lib (timeGetTime() のため)が追加ライブラリに入ってなくてこけたり。前はなんでリンク通ってたんだろう?


http://code.google.com/p/v8/source/detail?r=1243

V8 のヒープの中身を覗き見る

参照がなくなったはずのオブジェクトがなかなか回収されないのでどうしたもんかと思い、昨日今日ととりあえずヒープの中に分け入っています。
GC 管理下のヒープの中身を覗くとか正直あまりやりたくはないのですが、表向きには参照がなくなっているはずなのでだれの責任かつきとめないとなんとなく気持ちが悪いわけでして…。(実装間違っているのかなあ、と不安。)

続きを読む

V8 向け ActiveXObject、なんとか動いた

というわけで、先日からごそごそとやっている V8 用 COM/OLE 対応コードですが、なんか別の URL を使ってみたら動きました。悲しすぎる。
要するにどういうものかというと、OLE オートメーションに対応しているオブジェクトを Javascript コードからオブジェクトとして触ることができます。逆に、Javascript オブジェクト(と関数)を dispatch interface として COM 側からアクセスすることができるようになります。
まだ JS オブジェクトの export の動作検証や ITypeInfo 関係のコードなどは書いていないのですが、相手が動的言語のオブジェクトなのである程度手抜きしてもいい…のかなあ。

続きを読む

ActiveXObject with V8 (続き)

Locale の問題とかいろいろ修正していたら、なんとなく動くようになった気がしますが、よくわからないエラーが出ているのでまだまだのようです。。。

> var o = new ActiveXObject('Msxml2.XMLHTTP')
> o
[ActiveXObject@021D3A68]
> o.open
function open() { [native code] }
> o.open('GET', 'http://www.google.com/', false)
> o.readyState
1
> o.send()
Error: アクセスが拒否されました。

> o.readyState
4
> o.status
0
> o.statusText
Unknown

コールバックもできるよ!

> o.abort()
> o.readyState
0
> o.onreadystatechange = function() { print('readyState = ' + o.readyState) }
function () { print('readyState = ' + o.readyState) }
> o.open('GET', 'http://www.google.com/', false)
[readyState = 1]
> o.send()
[readyState = 1]
[readyState = 4]
Error: アクセスが拒否されました。


非同期モードはまだ動かないようです。