3

C++アプリケーションにSpidermonkeyを埋め込んでいます。jsvalを渡すネイティブC++でいくつかのカスタムJavascript関数を実装する必要があります。偶発的なガベージコレクションからjsvalを保護する必要があります。私がこれを行うのは適切ですか?

(1)initルーチンの場合:

static jsval vp; // a STATIC variable, value unknown
JSBool init((JSContext *cx, uintN argc, jsval *vp) {
   JS_AddValueRoot(cx,  &vp);
}

(2)Javascript関数setter()を実装する1つのc ++関数で:

JSBool setter(JSContext *cx, uintN argc, jsval *vp) {
   ...
  vp=...;// set to some JSObject and hopefully makes any previous JSObject available for gc

}

(3)Javascript関数getter()を実装する同じコンパイルユニット内の2番目のC++関数呼び出しで:

JSBool getter(JSContext *cx, uintN argc, jsval *vp) {
  jsval somethingelse = vp; //directly retrieve the static value stored by setter()
  ....
}

私のJavascriptスクリプトは、次のような関数呼び出しを使用します。

init();
setter(...);
some_other_function_call_that_causes_gc();
getter();
setter(...);
some_other_function_call_that_causes_gc();
getter();
....
some_other_function_call_that_causes_gc();
setter(...);
some_other_function_call_that_causes_gc();
getter();

静的jsvalvpは、2つの関数呼び出しの間に渡されるjsvalの永続的なストレージであるため、JS_RemoveRoot()を呼び出さないことに注意してください。そして、jsvalに格納されている以前のJSObjectがガベージコレクションに使用できると仮定して、setter()のgcルート静的変数vpに新しい値を設定し続けます。

関数呼び出しを介して渡すことができるgcルートの一時変数を作成するこれらの適切な方法はありますか?特に、setter()が以前のJSObjectを置き換える方法は、既存のJSObjectをgcで使用できるようにする(つまり、メモリリーク/クラッシュが発生しない)ための適切な方法です。

編集:ガベージコレクションが問題であると私が信じる理由は次のとおりです:

https://developer.mozilla.org/En/SpiderMonkey/JSAPI_User_Guide

セクションJSAPIの概念、Javascriptの値:

jsval自体は、ガベージコレクタからその指示対象を保護しません

https://developer.mozilla.org/en/SpiderMonkey_Garbage_Collection_Tips

例3は、「ルートを進むにつれて」と言い、jsvalをルートに割り当てる方法を示しています。

4

2 に答える 2

0

SpiderMonkey 17 以降について

jsvalまたは、GC の使用中に GC をトリガーする可能性がある場合は、他の GCを保護する必要があります。jsvalこれは、すでに保護されているストレージを参照する場合でも必要です。SpiderMonkey の GC は移動 GCです。

スタック ベースおよびヒープ ベースのRootedValue保護に使用します (は と同じです)。関数の引数にはandを使用します。jsvalHeap<JS::Value>jsval
jsvalJS::ValueHandle<JS::Value>MutableHandle<JS::Value>

以下は、RootingAPI コメントからの抜粋です。

 * A moving GC may change the physical location of GC allocated things, even
 * when they are rooted, updating all pointers to the thing to refer to its new
 * location. The GC must therefore know about all live pointers to a thing,
 * not just one of them, in order to behave correctly.
 *
 * For a code fragment such as:
 *
 * JSObject *obj = NewObject(cx);
 * DoSomething(cx);
 * ... = obj->lastProperty();
 *
 * If |DoSomething()| can trigger a GC, the stack location of |obj| must be
 * rooted to ensure that the GC does not move the JSObject referred to by
 * |obj| without updating |obj|'s location itself. This rooting must happen
 * regardless of whether there are other roots which ensure that the object
 * itself will not be collected.
 *
 * If |DoSomething()| cannot trigger a GC, and the same holds for all other
 * calls made between |obj|'s definitions and its last uses, then no rooting
 * is required.
 *
 * SpiderMonkey can trigger a GC at almost any time and in ways that are not
 * always clear. For example, the following innocuous-looking actions can
 * cause a GC: allocation of any new GC thing; JSObject::hasProperty;
 * JS_ReportError and friends; and ToNumber, among many others. The following
 * dangerous-looking actions cannot trigger a GC: js_malloc, cx->malloc_,
 * rt->malloc_, and friends and JS_ReportOutOfMemory.
于 2014-03-03T02:07:10.267 に答える