V8をビルドするとobj/releaseもしくはobj/debug以下にlibraries.ccとexperimental-libraries.ccと言うソースコードとそのビルド結果となるlibraries.oとexperimenta-libraries.oいう合計4個のファイルが生成される。これは一体どうやって作られて、どんな目的のモノなのであろうか。
まずはビルド時のログ出力をlibrariesをキーに検索すると、以下のような出力がある事が分かる(ちなみに、以下の出力はscons d8 mode=debugでビルドした時のもの。他の場合でも同じだとは思う)。
JS2C(["obj/debug/libraries.cc"], ["src/runtime.js", "src/v8natives.js", "src/array.js", "src/string.js", "src/uri.js", "src/math.js", "src/messages.js", "src/apinatives.js", "src/date.js", "src/regexp.js", "src/json.js", "src/liveedit-debugger.js", "src/mirror-debugger.js", "src/debug-debugger.js", "src/macros.py"])
g++ -o obj/debug/libraries.o -c -fno-rtti -fno-exceptions -fvisibility=hidden -Wall -Werror -W -Wno-unused-parameter -Woverloaded-virtual -Wnon-virtual-dtor -pedantic -m32 -g -O0 -ansi -DV8_TARGET_ARCH_IA32 -DENABLE_DISASSEMBLER -DDEBUG -DENABLE_DEBUGGER_SUPPORT -DV8_ENABLE_CHECKS -DOBJECT_PRINT -Iobj/debug -Isrc -Isrc obj/debug/libraries.cc
JS2C(["obj/debug/experimental-libraries.cc"], ["src/proxy.js", "src/collection.js", "src/macros.py"])
g++ -o obj/debug/experimental-libraries.o -c -fno-rtti -fno-exceptions -fvisibility=hidden -Wall -Werror -W -Wno-unused-parameter -Woverloaded-virtual -Wnon-virtual-dtor -pedantic -m32 -g -O0 -ansi -DV8_TARGET_ARCH_IA32 -DENABLE_DISASSEMBLER -DDEBUG -DENABLE_DEBUGGER_SUPPORT -DV8_ENABLE_CHECKS -DOBJECT_PRINT -Iobj/debug -Isrc -Isrc obj/debug/experimental-libraries.cc
どうもJS2Cでccファイルを生成して、その後にg++でビルドしている様子。JS2Cと言う関数名からするとJavaScriptをCに変換しているのであろう。そのJS2Cはtools/js2c.pyファイルに定義されてて、そのファイルの先頭には以下の様なコメントがある。
# This is a utility for converting JavaScript source code into C-style
# char arrays. It is used for embedded JavaScript code in the V8
# library.
つまり、JavaSciptコードをC形式の文字列配列に変換する、と言う事でJavaScript関数をCの関数に変換している訳ではないようなので、ちょっとがっかり。
とりあえずJS2Cの第二引数に与えられているjsもpyもsrc以下と言う事なのでsrcフォルダを見てみると、jsもpyも全てそこに存在している。とりあえずv8natives.jsの中身を見てみると、どうやらJavaScriptコードの様子。。。なのだが微妙に違う記法が混じっていて、関数名の先頭に%記号が付いている。。。。こんなのありだっけか?と思ったが、恐らくpyの方で何かしらの変換をするのかも知れない。
// Helper function used to install functions on objects.
function InstallFunctions(object, attributes, functions) {
if (functions.length >= 8) {
%OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
}
for (var i = 0; i < functions.length; i += 2) {
var key = functions[i];
var f = functions[i + 1];
%FunctionSetName(f, key);
%FunctionRemovePrototype(f);
%SetProperty(object, key, f, attributes);
%SetNativeFlag(f);
}
%ToFastProperties(object);
}
とりあえずsrcフォルダ以下でOptimizeObjectForAddingMultiplePropertiesを検索キーとしてgrepをかけてみると以下のファイルが見つかった(subversion関連は除外)。
./src/v8natives.js
./src/runtime.cc
./src/runtime.h
./src/math.js
どうもOptimizeObjectForAddingMultiplePropertiesはruntime.ccで定義されているcの関数である事が分かった。と言う事は%が先頭についた関数はcで定義された関数を直接記述する特別な記法なのかも知れない。
次にlibraries.ccの中を見ると以下の通りで、正確にはsources[]の中身を見る必要があるが、やはりスクリプトをC形式の文字列データに置き換えて、V8からアクセス出来る様にしている様子。
// Copyright 2011 Google Inc. All Rights Reserved.
// This file was generated from .js source files by SCons. If you
// want to make changes to this file you should either change the
// javascript source files or the SConstruct script.
#include "v8.h"
#include "natives.h"
#include "utils.h"
namespace v8 {
namespace internal {
static const byte sources[] = { .....(数値の羅列).....};
static const char* raw_sources = reinterpret_cast<const char*>(sources); // const byteをconst charにキャスト
template <>
int NativesCollection<CORE>::GetBuiltinsCount() { // ビルトイン関数の個数
return 14;
}
template <>
int NativesCollection<CORE>::GetDebuggerCount() { // デバッガー関数の個数
return 3;
}
template <>
int NativesCollection<CORE>::GetIndex(const char* name) { // オブジェクト名からインデックスを導出
if (strcmp(name, "liveedit") == 0) return 0;
。。。
if (strcmp(name, "json") == 0) return 13;
return -1;
}
template <>
int NativesCollection<CORE>::GetRawScriptsSize() { // 生スクリプトサイズ
return 238136;
}
template <>
Vector<const char> NativesCollection<CORE>::GetRawScriptSource(int index) { // 生スクリプトソースをインデックスをキーに取得
if (index == 0) return Vector<const char>(raw_sources + 144015, 15179);
。。。
if (index == 13) return Vector<const char>(raw_sources + 138135, 5880);
return Vector<const char>("", 0);
}
template <>
Vector<const char> NativesCollection<CORE>::GetScriptName(int index) { // スクリプト名をインデックスをキーに取得
if (index == 0) return Vector<const char>("native liveedit.js", 18);
。。。
if (index == 13) return Vector<const char>("native json.js", 14);
return Vector<const char>("", 0);
}
template <>
Vector<const byte> NativesCollection<CORE>::GetScriptsSource() { // スクリプトソースを取得
return Vector<const byte>(sources, 238136);
}
template <>
void NativesCollection<CORE>::SetRawScriptsSource(Vector<const char> raw_source) { // 生スクリプトの設定
ASSERT(238136 == raw_source.length());
raw_sources = raw_source.start();
}
} // internal
} // v8
しかし、スクリプトコードをV8から見る事がどんな状況で必要なのだろうか?ここのスクリプトコードをJITコンパイルしてからbuilt-inオブジェクトのメソッドは実行されている?少なくともbuilt-in関数のソースコードはJavaScriptでは見える必要はないので、JITが有力である気がする。となると独自のbuilt-in関数を組み込む場合にはjsファイルを作成して、SConsのスクリプトを書き換えれば、追加が出来る様になるとか?
うーん、もう少し調べたいが、遅いので今日はこれまで。
0 件のコメント:
コメントを投稿