How to create, handle, and destroy JS::Heap<T> objects in Spidermonkey?

☆樱花仙子☆ 提交于 2019-12-01 21:20:08

问题


Using Spidermonkey 24, 38, 45

Spidermonkey documentation says: "GC thing pointers on the heap must be wrapped in a JS::Heap. The only exception to this is if they are added as roots with the JS_AddRoot() functions or JS::PersistentRooted class, but don't do this unless it's really necessary. JS::Heap pointers must also continue to be traced in the normal way, which is not covered here."

What exactly does tracing mean in this case? Is the following code missing something?

struct Foo
{
   Foo(JS::HandleObject bar) : _bar(bar) {}  // Does that root bar?
   ~Foo() {_bar = nullptr;}                  // Does that release memory?

   JS::Heap<JSObject*>  _bar;
};

Foo *create(JSContext *jscontext, JSObject *parent)
{
   JS::RootedObject bar(jscontext, JS_NewObject(jscontext, &SOME_CLASS, NULL, parent));
   return new Foo(bar);
}

Do I need to add "tracing"? Do I need to root bar object when it is stored inside Foo? Should I rather use JS_AddRoot() functions to root bar instead of using Heap?


回答1:


JS::Heap<T> are used in data structures which reside on the heap. Tracing is indeed a requirement. Without it, the GC may either determine your object is unreachable or relocate it without updating your JS::Heap<T> handle.

Tracing objects in spidermonkey is simple. You need to request an extra GC root tracer using JS_AddExtraGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data). The JSTraceDataOp is a function pointer with the interface void traceOp(JSTracer* trc, void* data). In your function, you must call the various JS_Call<T>Tracer (defined in Tracer.h) methods passing the tracer and your object. Additionally, you should call JS_TraceChildren as necessary.

Using your example, adding a tracer might look something like the following.

Foo* ref = create(cx, nullptr);

void trace_foos(JSTracer* tracer, void* data) {
   JS_CallHeapObjectTracer(tracer, &(ref->_bar), "foo");
}

JS_AddExtraGCRootsTracer(rt, trace_foos, nullptr);

Whenever GC runs, your trace callback will run and you should traverse your object graph and trace GC things as you go.

As for the questions in your comments -

   Foo(JS::HandleObject bar) : _bar(bar) {}  // Does that root bar?

bar is already rooted on the stack by the JS::RootedObject bar in Foo* create. Heap<T> handles are not roots - this is why they must be traced. As soon as create returns, the object is no longer rooted.

  ~Foo() {_bar = nullptr;}                  // Does that release memory?

No. _bar is just an instance of the JS::Heap<T> handle. The thing it points to will be garbage collected on a subsequent cycle.




回答2:


Based on jwilm's answer here is an example of a Foo class implementation.

void trace_obj(JSTracer* tracer, void* data)
{
    JS_CallObjectTracer(tracer, (JS::Heap<JSObject*>*)data, "jsobj");
}

class Foo                                                                                                                                                                             
{                                                                                                                                                                                     
public:                                                                                                                                                                               
   Foo(JSRuntime *rt, JS::HandleObject bar)                                                                                                                                           
     : _rt(rt),                                                                                                                                                                        
     _bar(bar)                                                                                                                                                                      
   {                                                                                                                                                                                  
     if (_bar.get())                                                                                                                                                                  
       JS_AddExtraGCRootsTracer(_rt, trace_obj, &_bar);                                                                                                                               
   }                                                                                                                                                                                  
   Foo(Foo const &f)                                                                                                                                           
     : _rt(f._rt),                                                                                                                                                                        
     _bar(f._bar)                                                                                                                                                                      
   {                                                                                                                                                                                  
     if (_bar.get())                                                                                                                                                                  
       JS_AddExtraGCRootsTracer(_rt, trace_obj, &_bar);                                                                                                                               
   }                                                                                                                                                                                  
   ~Foo()                                                                                                                                                                             
   {                                                                                                                                                                                  
     if (_bar.get())                                                                                                    
       JS_RemoveExtraGCRootsTracer(_rt, trace_obj, &_bar);                                                                                 
   }                                                                                                                                                                                  

private:                                                                                                                
   JSRuntime *_rt;                                                                                                                                                                    
   JS::Heap<JSObject*> _bar;                                                                                                                                                          
};                                                                                                                                                                                    


来源:https://stackoverflow.com/questions/27393732/how-to-create-handle-and-destroy-jsheapt-objects-in-spidermonkey

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!