私は、v8コードで直接jsコードのカバレッジを実装するつもりです。 私の最初の目標は、抽象構文ツリーのすべてのステートメントに簡単なプリントを追加することです。 AstVisitor
クラスがあり、ASTをトラバースすることができます。 私の質問は、どのように訪問者が現在訪問しているステートメントの後にASTにステートメントを追加することができますか?V8を操作する
V8を操作する
答えて
私は実験を要約します。まず、Chromiumバージョンr157275で使用されていたように、V8に私が書いたものが適用されるため、それ以上は機能しないかもしれませんが、現在のバージョンの場所にリンクします。
AstVisitor
から継承し、そこからVisitXYZ
メソッドの束を実装する必要があるように、あなた自身のASTビジター、たとえばMyAstVisior
が必要です。実行されたコードを計測/検査するために必要な唯一のものはVisitFunctionLiteral
です。実行されるコードは、関数内でV8がラップして実行されるソース(ファイル)内の関数またはloose文のセットです。
次に、解析されたASTをコードhere(ルーズ文からのコンパイル)とthere(実行時のコンパイル、初めて定義された関数が実行されるとき)の直前に変換すると、訪問者にVisitFunctionLiteral
を呼び出す関数リテラルへの訪問者、:
MyAstVisitor myAV(info);
info->function()->Accept(&myAV);
// next line is the V8 compile call
if (!MakeCode(info)) {
1はASTを変更することを必要とするので、私は、カスタムユーザーへCompilationInfo
ポインタinfo
を可決しました。コンストラクタは次のようになります。
MyAstVisitor(CompilationInfo* compInfo) :
_ci(compInfo), _nf(compInfo->isolate(), compInfo->zone()), _z(compInfo->zone()){};
_ci、_nfと_ZはCompilationInfo
、AstNodeFactory<AstNullVisitor>
とZone
へのポインタです。
VisitFunctionLiteral
には、関数本体を繰り返し処理したり、必要に応じてステートメントを挿入することができます。
void MyAstVisitor::VisitFunctionLiteral(FunctionLiteral* funLit){
// fetch the function body
ZoneList<Statement*>* body = funLit->body();
// create a statement list used to collect the instrumented statements
ZoneList<Statement*>* _stmts = new (_z) ZoneList<Statement*>(body->length(), _z);
// iterate over the function body and rewrite each statement
for (int i = 0; i < body->length(); i++) {
// the rewritten statements are put into the collector
rewriteStatement(body->at(i), _stmts);
}
// replace the original function body with the instrumented one
body->Clear();
body->AddAll(_stmts->ToVector(), _z);
}
rewriteStatement
メソッドでは、このステートメントを検査できます。 _stmts
ポインタは、最後に元の関数本体に置き換わるステートメントのリストを保持します。ですから、最初に元の文を追加して、あなた自身のprint文を追加し、それぞれの文の後にprint文を追加します。
void MyAstVisitor::rewriteStatement(Statement* stmt, ZoneList<Statement*>* collector){
// add original statement
collector->Add(stmt, _z);
// create and add print statement, assuming you define print somewhere in JS:
// 1) create handle (VariableProxy) for print function
Vector<const char> fName("print", 5);
Handle<String> fNameStr = Isolate::Current()->factory()->NewStringFromAscii(fName, TENURED);
fNameStr = Isolate::Current()->factory()->SymbolFromString(fNameStr);
// create the proxy - (it is vital to use _ci->function()->scope(), _ci->scope() crashes)
VariableProxy* _printVP = _ci->function()->scope()->NewUnresolved(&_nf, fNameStr, Interface::NewUnknown(_z), 0);
// 2) create message
Vector<const char> tmp("Hello World!", 12);
Handle<String> v8String = Isolate::Current()->factory()->NewStringFromAscii(tmp, TENURED);
Literal* msg = _nf.NewLiteral(v8String);
// 3) create argument list, call expression, expression statement and add the latter to the collector
ZoneList<Expression*>* args = new (_z) ZoneList<Expression*>(1, _z);
args->Add(msg);
Call* printCall = _nf.NewCall(_printVP, args, 0);
ExpressionStatement* printStmt = _nf.NewExpressionStatement(printCall);
collector->Add(printStmt, _z);
}
NewCall
とNewUnresolved
の最後のパラメータは、スクリプト内の位置を特定する番号です。私はこれがデバッグ/エラーメッセージのどこでエラーが発生したかを示すために使用されると仮定します。私は少なくとも0に設定することで問題に遭遇したことはありません(kNoPositionのどこかに定数もあります)。
最後のいくつかの単語:Blocks
(例:ループ本体)はステートメントのリストを表すステートメントであり、ループは条件式とボディブロックを持つステートメントであるため、実際には各ステートメントの後にprintステートメントを追加しません。したがって、現在どのような文が処理されているのかを調べ、再帰的に調べる必要があります。ブロックの書き換えは、関数本体の書き換えとほぼ同じです。
しかし、ASTには分岐に関する情報も含まれているため、既存のステートメントの置き換えや変更を開始するときに問題が発生します。だから、もしあなたがあなたのコードを壊すいくつかの条件のためのジャンプターゲットを置き換えます。私は、これを置き換えるために新しいものを作成するのではなく、単一の式と文の型にリライト機能を直接追加すると、これをカバーすることができると思います。
これまでのところ、私はそれが役に立ちそうです。
Gad。代わりに、「任意の言語のブランチカバレッジを簡単に作成する」で概説したアプローチを検討してください。http://www.semdesigns.com/Company/Publications/TestCoverage.pdf –
- 1. コードでaccount.moveを作成する - Odoo v8
- 2. C#でデータを操作する操作
- 3. 作成stock.picking OdooのV8
- 4. Bing Maps v8、V8のレストサービスURL
- 5. HBaseでの操作による操作
- 6. データ操作の操作
- 7. 何の操作アトミック操作
- 8. ルックアップファイルからBingマップのv8ポリゴンを作成する
- 9. オブジェクトに複数のシーケンスを作成する - Odoo v8
- 10. 操作行を操作行に制限するAngularJS
- 11. v8(JavaScript)文字列::新規作成
- 12. nsmutabledataを操作する
- 13. エスケープクロージャー値を操作する
- 14. Datetimeindexを操作するパンダ
- 15. キーボードを操作する
- 16. プログラムメモリを操作する。 (メモリハック)
- 17. データフレームを操作する
- 18. オーディオファイルを操作する
- 19. Android、カメラプレビューフレームを操作する
- 20. REST APIを操作する
- 21. チェックボックスリストを操作する
- 22. text-document.writeを操作する
- 23. Jsonオブジェクトリテラルを操作する
- 24. フラグメントクラスを操作する
- 25. Prologコードを操作する
- 26. highcharts barを操作する
- 27. オブジェクトを操作する
- 28. 角を操作する2
- 29. Kinectスケルトンデータを操作する
- 30. BlogPostメタデータを操作する
基本ブロックは、ASTではなく、制御フローグラフの構成要素です。あなたはASTからCFGを作成しようと思いますか? – delnan
私は2つを混合しているかもしれませんが、私はastのノードも基本ブロックだと思いましたか? – user2240085
*どちらのノード?いずれにしても、基本ブロックと一致する共通のASTノードは認識していません(ただし、CFG-ish情報を保持し、それを "AST"と呼ぶデータ構造を持つことは可能です)。たとえば、ループは通常ASTノードですが、多くのループは複数のBBで構成されています。ループノードは、ステートメントノードのリストを含むことができるが、それらのステートメントのいくつかは、BBの* part *(例えば、単純割り当て)に対応し、ステートメントノードのいくつかは*複数の* BB(例えば、インライン条件またはネストループ)おそらく、あなたは "基本ブロック"という用語を誤って使用しているのでしょうか? – delnan