Weak callback for function callback data never getting called

119 views
Skip to first unread message

tbl...@icloud.com

unread,
Oct 2, 2016, 5:02:37 PM10/2/16
to v8-users
I'm using FunctionTemplate to create a function that has callback data, and I want to get a callback when the function is no longer reachable from Javascript so I can do some cleanup associated with the callback data. I'm trying to do this with a weak reference callback, but I'm having some trouble getting the weak callback to actually get called.

MVCE:

#include <stdlib.h>
#include <stdio.h>
#include <v8.h>
#include <libplatform/libplatform.h>

using namespace v8;

class MallocAllocator : public ArrayBuffer::Allocator {
   
public:
   
virtual void *Allocate(size_t size) {
       
void *data = AllocateUninitialized(size);
       
if (data != NULL)
            memset
(data, 0, size);
       
return data;
   
}
   
virtual void *AllocateUninitialized(size_t size) {
       
return malloc(size);
   
}
   
virtual void Free(void *data, size_t size) {
        free
(data);
   
}
};

void func_callback(const FunctionCallbackInfo<Value> &info) {}

void weak_callback(const WeakCallbackInfo<Persistent<String>> &info) {
   
Persistent<String> *handle = info.GetParameter();
    printf
("weak callback called with %p\n", handle);
   
delete handle;
}

int main() {
    V8
::InitializeICU();
   
Platform *current_platform = platform::CreateDefaultPlatform();
    V8
::InitializePlatform(current_platform);
    V8
::Initialize();
    V8
::SetFlagsFromString("--expose_gc", strlen("--expose_gc"));
   
Isolate::CreateParams params;
   
params.array_buffer_allocator = new MallocAllocator();
   
Isolate *isolate = Isolate::New(params);
   
HandleScope hs(isolate);

   
Local<Context> context = Context::New(isolate);
   
Local<String> key = String::NewFromUtf8(isolate, "test", NewStringType::kNormal).ToLocalChecked();

   
Persistent<String> *weak_str = new Persistent<String>();
   
{
       
HandleScope hs(isolate);
       
Local<String> str = String::NewFromUtf8(isolate, "hi there", NewStringType::kNormal).ToLocalChecked();

       
Local<FunctionTemplate> templ = FunctionTemplate::New(isolate, func_callback, str);

        weak_str
->Reset(isolate, str);
        weak_str
->SetWeak(weak_str, weak_callback, WeakCallbackType::kParameter);
        context
->Global()->Set(context,
                key
, templ->GetFunction(context).ToLocalChecked())
           
.FromJust();
   
}

    context
->Global()->Delete(context, key).FromJust();

    isolate
->RequestGarbageCollectionForTesting(Isolate::GarbageCollectionType::kFullGarbageCollection);
   
return 0;
}

In this program, weak_callback never gets called. Anyone know why?

Thanks,
~Theodore

Zac Hansen

unread,
Oct 3, 2016, 12:55:41 AM10/3/16
to v8-users

Specifically: 

NOTE: There is no guarantee as to when or even if the callback is invoked. The invocation is performed solely on a best effort basis. As always, GC-based finalization should not be relied upon for any critical form of resource management!

That said, if you play around with sending some bogus numbers to  

int64_t v8::Isolate::AdjustAmountOfExternalAllocatedMemory(int64_t change_in_bytes)




you can convince the garbage collector to run pretty quickly.   On allocation of an object, tell it that it cost a megabyte and in your weak cleanup, tell it -1megabyte and make objects in a tight loop and you'll see GC soon enough.

Pavel Medvedev

unread,
Oct 3, 2016, 6:27:42 AM10/3/16
to v8-users
Hi  Theodore,

In this program, weak_callback never gets called. Anyone know why?


There is no isolate->Enter() after Isolate::New(params), and no context->Enter() after Context::New(isolate). May it be a reason?
 

Jochen Eisinger

unread,
Oct 4, 2016, 4:17:44 AM10/4/16
to v8-users
v8 has an per-isolate cache of function templates. As the string is referenced by the function template, it will never go out of scope.

I'd recommend to create a weak handle to the function you create via GetFunction() instead

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to the Google Groups "v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Theodore Dubois

unread,
Oct 4, 2016, 5:19:56 PM10/4/16
to v8-u...@googlegroups.com
Interesting. So when a function template is created, its callback data will never be freed?

~Theodore

You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.

Zac Hansen

unread,
Oct 4, 2016, 6:46:09 PM10/4/16
to v8-u...@googlegroups.com
The way I read it is that because the function template remains until the end of the program, its data cannot be cleaned up.  And since it has to keep str around until the function template goes away, str won't be cleaned up either because there's still a reference to it. 

On Tue, Oct 4, 2016 at 2:19 PM, Theodore Dubois <tbl...@icloud.com> wrote:
Interesting. So when a function template is created, its callback data will never be freed?

~Theodore
On Oct 4, 2016, at 1:17 AM, Jochen Eisinger <joc...@chromium.org> wrote:

v8 has an per-isolate cache of function templates. As the string is referenced by the function template, it will never go out of scope.

I'd recommend to create a weak handle to the function you create via GetFunction() instead

On Mon, Oct 3, 2016 at 12:27 PM Pavel Medvedev <pmed...@gmail.com> wrote:
Hi  Theodore,

In this program, weak_callback never gets called. Anyone know why?


There is no isolate->Enter() after Isolate::New(params), and no context->Enter() after Context::New(isolate). May it be a reason?
 

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to the Google Groups "v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+unsubscribe@googlegroups.com.

Theodore Dubois

unread,
Oct 4, 2016, 6:48:25 PM10/4/16
to v8-u...@googlegroups.com
I created the FunctionTemplate inside its own HandleScope which gets destroyed before the program finishes, so it should get garbage collected before the end of the program. Is that right?

~Theodore


To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.

Zac Hansen

unread,
Oct 4, 2016, 6:56:21 PM10/4/16
to v8-u...@googlegroups.com

isolate->AdjustAmountOfExternalAllocatedMemory(1000000)

in there too and see what happens.  


To unsubscribe from this group and all its topics, send an email to v8-users+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Jochen Eisinger

unread,
Oct 5, 2016, 1:04:41 AM10/5/16
to v8-u...@googlegroups.com
the function template won't ever get gc'd after you've instantiated it once.

To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
You received this message because you are subscribed to the Google Groups "v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+u...@googlegroups.com.

tbl...@icloud.com

unread,
Oct 5, 2016, 7:25:49 PM10/5/16
to v8-users
Thanks for all your feedback. I tried attaching the weak callback to the function instead of the callback data, and I tried a tight loop with AdjustAmountOfExternalAllocatedMemory. But the weak callback still isn't getting called. Here's the updated main function:

int main() {
    V8::InitializeICU();
    Platform *current_platform = platform::CreateDefaultPlatform();
    V8::InitializePlatform(current_platform);
    V8::Initialize();
    V8::SetFlagsFromString("--expose_gc", strlen("--expose_gc"));
    Isolate::CreateParams params;
    params.array_buffer_allocator = new MallocAllocator();
    Isolate *isolate = Isolate::New(params);
    Isolate::Scope is(isolate);
    HandleScope hs(isolate);

    Local<Context> context = Context::New(isolate);
    Context::Scope cs(context);
    Local<String> key = String::NewFromUtf8(isolate, "test", NewStringType::kNormal).ToLocalChecked();

    for (int i = 0; ; i++) {
        Persistent<Function> *weak_func = new Persistent<Function>();

        Local<FunctionTemplate> templ = FunctionTemplate::New(isolate, func_callback);
        Local<Function> func = templ->GetFunction(context).ToLocalChecked();

        weak_func->Reset(isolate, func);
        weak_func->MarkIndependent();
        weak_func->SetWeak(weak_func, weak_callback, WeakCallbackType::kParameter);
        isolate->AdjustAmountOfExternalAllocatedMemory(100000000);
        printf("%d\r", i);
        /* context->Global()->Set(context, key, func).FromJust(); */
        /* context->Global()->Delete(context, key).FromJust(); */
    }

    isolate->RequestGarbageCollectionForTesting(Isolate::GarbageCollectionType::kFullGarbageCollection);
    return 0;
}

Uncommenting the two commented lines doesn't make any difference. What am I doing wrong now?

Zac Hansen

unread,
Oct 5, 2016, 8:54:26 PM10/5/16
to v8-u...@googlegroups.com
The loop is inside the handle scope if I'm reading to correctly so the handle scope keeps a reference to everything meaning it can't be gc
--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+unsubscribe@googlegroups.com.

Zac Hansen

unread,
Oct 5, 2016, 8:57:46 PM10/5/16
to v8-u...@googlegroups.com
Put a(mother) handle scope inside the for loop


On Wednesday, October 5, 2016, <tbl...@icloud.com> wrote:
--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+unsubscribe@googlegroups.com.

tbl...@icloud.com

unread,
Oct 5, 2016, 10:03:41 PM10/5/16
to v8-users
Why didn't I think of that?


Put a(mother) handle scope inside the for loop

Also, autocorrect failure ^^^^^ 

Zac Hansen

unread,
Oct 5, 2016, 10:07:35 PM10/5/16
to v8-u...@googlegroups.com
It's in the v8::mother experimental namespace :-)


On Wednesday, October 5, 2016, <tbl...@icloud.com> wrote:
--

tbl...@icloud.com

unread,
Oct 5, 2016, 10:56:40 PM10/5/16
to v8-users
Actually, that didn't work. Any other ideas? Any techniques for debugging GC (like getting information on where an object is referenced?)

Zac Hansen

unread,
Oct 5, 2016, 11:36:03 PM10/5/16
to v8-u...@googlegroups.com

Good news is, this program calls the callback.  Bad news it crashes, but I think it demonstrates the general idea.

I believe the problem with your program is that your global with the weak callback goes away too early.  In my program below you can see I'm allocating the global on the heap (and leaking the crap out of it - but you can clean it up in the callback) and that makes the callback get called because the global is still around.


caveat emptor 


P.S. Posting a compilable program next time makes it easier for me to help you


#include <v8.h>

#include <v8-platform.h>

#include <libplatform/libplatform.h>

#include <stdio.h>


using namespace v8;


void func_callback(const FunctionCallbackInfo<v8::Value> &data) {

  fprintf(stderr, "Here\n");

}


void weak_callback(const WeakCallbackInfo<int> &data) {

  fprintf(stderr, "weak callback\n");

}



class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {

public:

  inline virtual void* Allocate(size_t length) override {

    void* data = AllocateUninitialized(length);

    return data == NULL ? data : memset(data, 0, length);

  }

  inline virtual void* AllocateUninitialized(size_t length) override { return malloc(length); }

  inline virtual void Free(void* data, size_t) override { free(data); }

};



int main() {

  V8::InitializeICU();

  Platform *current_platform = v8::platform::CreateDefaultPlatform();

  V8::InitializePlatform(current_platform);

  V8::Initialize();

  V8::SetFlagsFromString("--expose_gc", strlen("--expose_gc"));

  Isolate::CreateParams params;

  params.array_buffer_allocator = new ArrayBufferAllocator();

  Isolate *isolate = Isolate::New(params);

  HandleScope hs(isolate);


  Local<Context> context = Context::New(isolate);



  int iii; // bogus int                                                                                                                                

  Local<ObjectTemplate> ot = ObjectTemplate::New(isolate);

  ot->SetInternalFieldCount(1);


  for (int i = 0; ; i++) {

    HandleScope hs2(isolate);

    Local<Object> obj = ot->NewInstance(context).ToLocalChecked();

    Global<Object> * gobject = new Global<Object>(isolate, obj);

    gobject->SetWeak<int>(&iii, weak_callback, WeakCallbackType::kParameter);

    isolate->AdjustAmountOfExternalAllocatedMemory(100000000);


    if (i%1000==0)printf("%d\r", i);

    /* context->Global()->Set(context, key, func).FromJust(); */

    /* context->Global()->Delete(context, key).FromJust(); */

  }



  return 0;


On Wed, Oct 5, 2016 at 7:56 PM, <tbl...@icloud.com> wrote:
Actually, that didn't work. Any other ideas? Any techniques for debugging GC (like getting information on where an object is referenced?)

--

Zac Hansen

unread,
Oct 5, 2016, 11:41:28 PM10/5/16
to v8-u...@googlegroups.com
Also, here's the somewhat generalized code I use for doing this in my integration library:

Theodore Dubois

unread,
Oct 6, 2016, 12:48:36 PM10/6/16
to v8-u...@googlegroups.com
I don’t think the problem is allocating the handle on the heap, I’m doing that in my code too. The significant difference between your code and my code is that I’m using a FunctionTemplate and trying to get a weak callback on the Functions it creates, and you’re using an ObjectTemplate. When I changed Function to Object in my code and fixed a few compiler errors, it worked.

It seems like it’s pretty easy to get this to work with objects, but much harder with functions. Does anyone know how to make this work?

Thanks,
~Theodore
> To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>
>
>
> --
> --
> v8-users mailing list
> v8-u...@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.

Zac Hansen

unread,
Oct 6, 2016, 5:50:41 PM10/6/16
to v8-u...@googlegroups.com
A guess would be that it only works on types with internal fields, which are only objecttemplate-sourced objects.   That's the only thing that would need any type of user-specified code to run on GC.  But that's just a guess.   A quick glance at the source doesn't back it up.

> To unsubscribe from this group and all its topics, send an email to v8-users+unsubscribe@googlegroups.com.

> For more options, visit https://groups.google.com/d/optout.
>
>
>
> --
> --
> v8-users mailing list
> v8-u...@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to v8-users+unsubscribe@googlegroups.com.

> For more options, visit https://groups.google.com/d/optout.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+unsubscribe@googlegroups.com.

Theodore Dubois

unread,
Oct 6, 2016, 5:52:02 PM10/6/16
to v8-u...@googlegroups.com
Interestingly, the %s/Function/Object/g version worked without adding a call to SetInternalFieldCount.

~Theodore
> > To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
> >
> >
> >
> > --
> > --
> > v8-users mailing list
> > v8-u...@googlegroups.com
> > http://groups.google.com/group/v8-users
> > ---
> > You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
> > To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
> > To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
>
> --
> --
> v8-users mailing list
> v8-u...@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> --
> v8-users mailing list
> v8-u...@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/Rshbi2HKYCM/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages