Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nan context switch issue #549

Open
Enerccio opened this issue Mar 23, 2016 · 13 comments
Open

Nan context switch issue #549

Enerccio opened this issue Mar 23, 2016 · 13 comments

Comments

@Enerccio
Copy link

http://stackoverflow.com/questions/36190856/v8s-persistents-value-changed

Anyone has any idea why does this happen?

@kkoopa
Copy link
Collaborator

kkoopa commented Mar 24, 2016

Nothing concrete comes to mind. Maybe because of using v8::Persistent? Why don't you use Nan::Persistent? Does it work if you only use V8?

@kkoopa
Copy link
Collaborator

kkoopa commented Mar 24, 2016

Actually, since it returns 0, it seems that your v8::Persistent has been reset. This happens when it goes out of scope, since v8::Persistent<T, v8::CopyablePersistentTraits<T> > has the kResetInDestructor flag set to true.

@Enerccio
Copy link
Author

I refactored it using Nan::Persistent only (with default non copyable flags) and instead of assignment, I call .Reset:

ProviderProxy *obj = new ProviderProxy();
obj->Wrap(info.This());
obj->provider.Reset(proxy);

But it still returns 0 if called in different context...

@Enerccio
Copy link
Author

Apparently, it might be other bug or I am doing something wrong, but looks like the instance is garbage collected...

  #include <node.h>
  #include <nan.h>

  #include <set>
  #include <string>
  #include <iostream>

  namespace nodeproxy {

  using namespace std;

  class ProviderProxy : public Nan::ObjectWrap {
  public:
    static NAN_MODULE_INIT(Init) {
        v8::Local<v8::FunctionTemplate> fnc = Nan::New<v8::FunctionTemplate>(MakeProxy);
        Nan::Set(target, Nan::New("makeProxy").ToLocalChecked(),
                  Nan::GetFunction(fnc).ToLocalChecked());
    }

   static NAN_METHOD(MakeProxy) {
     v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
     tpl->SetClassName(Nan::New("ProviderProxy").ToLocalChecked());
     tpl->InstanceTemplate()->SetInternalFieldCount(1);
     Nan::SetPrototypeMethod(tpl, "_get", Get);
     info.GetReturnValue().Set(Nan::GetFunction(tpl).ToLocalChecked());
   }

   ProviderProxy();
   ~ProviderProxy();

   static NAN_METHOD(CallProxified);
   static NAN_METHOD(Get);

   static NAN_METHOD(New) {
      if (info.IsConstructCall()) {
        v8::Local<v8::Object> proxy = v8::Local<v8::Object>::Cast(info[0]);
        ProviderProxy* obj = new ProviderProxy();
        obj->Wrap(info.This());
        obj->provider.Reset(proxy);
        info.GetReturnValue().Set(info.This());

        Nan::Set(info.This(), Nan::New("isProxied").ToLocalChecked(), Nan::New("yes").ToLocalChecked());

        v8::Local<v8::Function> proxify = v8::Local<v8::Function>::Cast(info[2]);
        obj->proxify.Reset(proxify);

        v8::Local<v8::Object> definedProviders = v8::Local<v8::Object>::Cast(info[1]);
        set<string> functions;

        Nan::MaybeLocal<v8::Value> providerList = Nan::Get(proxy,
            Nan::New("__providers").ToLocalChecked());
        if (providerList.IsEmpty()) {
          Nan::ThrowTypeError("Proxied object does not have any interface!");
          return;
        }

        Nan::MaybeLocal<v8::Object> ppsTested = Nan::To<v8::Object>(providerList.ToLocalChecked());
        if (ppsTested.IsEmpty()) {

          v8::String::Utf8Value str(providerList.ToLocalChecked()->ToString());
          string strstr = string(*str);

          v8::String::Utf8Value str2(Nan::New(obj->provider)->ToString());
          string strstr2 = string(*str2);

          v8::String::Utf8Value str3(info.Holder()->ToString());
          string strstr3 = string(*str3);

          Nan::ThrowTypeError(("ptr <" + to_string((uint64_t)(void*)obj) + ">" +
            strstr3+string(": ")+strstr2+string("'s __providers is NOT an array but ") + strstr).c_str());
          return;
        }
        v8::Local<v8::Object> pps = ppsTested.ToLocalChecked();
        uint32_t len = Nan::To<uint32_t>(Nan::Get(pps, Nan::New("length").ToLocalChecked()).ToLocalChecked())
                            .FromJust();
        for (uint32_t i=0; i<len; i++) {
          Nan::MaybeLocal<v8::String> testString = Nan::To<v8::String>(Nan::Get(pps, Nan::New(i)).ToLocalChecked());
          if (testString.IsEmpty()) {
            continue; // skip garbage
          }

          Nan::MaybeLocal<v8::Value> interface = Nan::Get(definedProviders, testString.ToLocalChecked());
          if (interface.IsEmpty()) {
            Nan::ThrowTypeError("There is no such interface defined!");
          }

          v8::Local<v8::Object> fncArray = Nan::To<v8::Object>(interface.ToLocalChecked()).ToLocalChecked();
          uint32_t flen = Nan::To<uint32_t>(Nan::Get(fncArray, Nan::New("length").ToLocalChecked()).ToLocalChecked())
                         .FromJust();
          for (uint32_t fi=0; fi<flen; fi++) {
            v8::Local<v8::String> function = Nan::To<v8::String>(Nan::Get(fncArray, Nan::New(fi))
              .ToLocalChecked()).ToLocalChecked();

             v8::String::Utf8Value fncName(function->ToString());
             std::string func = std::string(*fncName);
             functions.insert(func);
          }

          for (set<string>::iterator it=functions.begin(); it!=functions.end(); ++it) {
            string fnc = *it;
            Nan::SetMethod(info.This(), fnc.c_str(), CallProxified);
          }
        }
      }
    }

      Nan::Persistent<v8::Object> provider;
      Nan::Persistent<v8::Function> proxify;
  };

  ProviderProxy::ProviderProxy() {

  }

  ProviderProxy::~ProviderProxy() {
    cout << "destructor called" << endl;
    this->provider.Reset();
    this->proxify.Reset();
    volatile int *p = reinterpret_cast<volatile int*>(0);
    *p = 0x1337D00D;
  }

  NAN_METHOD(ProviderProxy::Get) {
    ProviderProxy* proxy = Nan::ObjectWrap::Unwrap<ProviderProxy>(info.Holder());
    info.GetReturnValue().Set(Nan::New(proxy->provider));
  }

  NAN_METHOD(ProviderProxy::CallProxified) {
    ProviderProxy* proxy = Nan::ObjectWrap::Unwrap<ProviderProxy>(info.Holder());
    v8::Local<v8::Object> provider = Nan::New(proxy->provider);

    v8::Local<v8::String> name = Nan::To<v8::String>(info.Callee()->GetName()).ToLocalChecked();
    Nan::MaybeLocal<v8::Value> fncV = Nan::Get(provider, name);

    if (fncV.IsEmpty()) {
      Nan::ThrowTypeError("Original object has lost method proxified");
      return;
    }

    v8::Local<v8::Value> fncLv = fncV.ToLocalChecked();

    if (!fncLv->IsFunction()) {
      Nan::ThrowTypeError("Original object changed the property into non-function");
      return;
    }

    v8::Local<v8::Function> fnc = v8::Local<v8::Function>::Cast(fncLv);

    int argc = info.Length();
    v8::Local<v8::Value> argv[argc];
    v8::Local<v8::Value> cargs[1];
    v8::Local<v8::Function> proxyCall = Nan::New(proxy->proxify);

    cargs[0] = proxyCall;
    for (int i=0; i<argc; i++) {
      cargs[0] = info[i];
      argv[i] = Nan::Call(proxyCall, Nan::New<v8::Object>(), 1, cargs).ToLocalChecked();
    }

    Nan::MaybeLocal<v8::Value> ret = Nan::Call(fnc, provider, argc, argv);
    v8::Local<v8::Value> retVal = (ret.IsEmpty() ? (v8::Local<v8::Value>)(Nan::Undefined()) : ret.ToLocalChecked());

    cargs[0] = retVal;
    Nan::MaybeLocal<v8::Value> vr = Nan::Call(proxyCall, Nan::New<v8::Object>(), 1, cargs);
    info.GetReturnValue().Set(vr.IsEmpty() ? (v8::Local<v8::Value>)(Nan::Undefined()) : vr.ToLocalChecked());
  }

  NODE_MODULE(nproxy, ProviderProxy::Init)

  };

#1 0x00007ffff1832641 in nodeproxy::ProviderProxy::~ProviderProxy() ()
from /tmp/nproxy/build/Release/nproxy.node
#2 0x00000000007e64de in v8::internal::GlobalHandles::PendingPhantomCallback::Invoke(v8::internal::Isolate_) ()
#3 0x00000000007e66e6 in v8::internal::GlobalHandles::DispatchPendingPhantomCallbacks(bool) ()
#4 0x00000000007e686a in v8::internal::GlobalHandles::PostGarbageCollectionProcessing(v8::internal::GarbageCollector, v8::GCCallbackFlags) ()
#5 0x000000000081802c in v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags)
()
#6 0x000000000081868d in v8::internal::Heap::CollectGarbage(v8::internal::GarbageCollector, char const_, char const_, v8::GCCallbackFlags) ()
#7 0x00000000007cb8d9 in v8::internal::Factory::NewRawOneByteString(int, v8::internal::PretenureFlag) ()
#8 0x00000000007cbd71 in v8::internal::Factory::NewStringFromOneByte(v8::internal::Vector, v8::internal::PretenureFlag) ()
#9 0x00000000007cc013 in v8::internal::Factory::NewStringFromUtf8(v8::internal::Vector, v8::internal::PretenureFlag) ()
#10 0x000000000066106d in v8::String::NewFromUtf8(v8::Isolate_, char const_, v8::String::NewStringType, int) ()
#11 0x0000000000b2f25e in ?? ()
#12 0x000000000067e0ea in v8::internal::FunctionCallbackArguments::Call(void (_)(v8::FunctionCallbackInfov8::Value const&))
()
#13 0x00000000006a4fb7 in ?? ()

@Enerccio
Copy link
Author

Okay, apparently I fixed it by calling obj->Ref(); (though that could mean that it will never be garbage collected now?).

@kkoopa
Copy link
Collaborator

kkoopa commented Mar 27, 2016

It ought to mean that, yes. What you would need to do instead is keep a reference alive on tge javascript side until it is no longer needed, then set it to null or delete it or something, and it will be subsequently garbage collected.

On March 27, 2016 4:57:33 PM GMT+03:00, Enerccio notifications@github.com wrote:

Okay, apparently I fixed it by calling 'obj->Ref();` (though that could
mean that it will never be garbage collected now?).


You are receiving this because you commented.
Reply to this email directly or view it on GitHub:
#549 (comment)

@Enerccio
Copy link
Author

I thought that it is done automatically with regards it being objectwrap, no? Ie when the object to which this was wrapped has been collected, so should the c++ instance, no? Because the javascript object is definitely NOT being garabage collected.

@kkoopa
Copy link
Collaborator

kkoopa commented Mar 27, 2016

The objectwrapped object will not be collected until its js correspondent has been collected.

On March 27, 2016 5:43:59 PM GMT+03:00, Enerccio notifications@github.com wrote:

I thought that it is done automatically with regards it being
objectwrap, no? Ie when the object to which this was wrapped has been
collected, so should the c++ instance, no? Because the javascript
object is definitely NOT being garabage collected.


You are receiving this because you commented.
Reply to this email directly or view it on GitHub:
#549 (comment)

@Enerccio
Copy link
Author

But it is, which is why I get all these problems. The underline objectwrapped object is collected, while js correspondent is kept alive and next time it is used, I get segfault or persistents are cleared.

@Enerccio
Copy link
Author

This makes no sense, how can I get my object garbage collected yet later use it to access my c++ instance?

#0  0x00007ffff1832099 in nodeproxy::ProviderProxy::~ProviderProxy() ()
   from /tmp/nproxy/build/Release/nproxy.node
#1  0x00007ffff1832121 in nodeproxy::ProviderProxy::~ProviderProxy() ()
   from /tmp/nproxy/build/Release/nproxy.node
#2  0x00000000007e64de in v8::internal::GlobalHandles::PendingPhantomCallback::Invoke(v8::internal::Isolate*) ()
#3  0x00000000007e66e6 in v8::internal::GlobalHandles::DispatchPendingPhantomCallbacks(bool) ()
#4  0x00000000007e686a in v8::internal::GlobalHandles::PostGarbageCollectionProcessing(v8::internal::GarbageCollector, v8::GCCallbackFlags) ()
#5  0x000000000081802c in v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags)
    ()
#6  0x000000000081868d in v8::internal::Heap::CollectGarbage(v8::internal::GarbageCollector, char const*, char const*, v8::GCCallbackFlags) ()
#7  0x00000000007cb8d9 in v8::internal::Factory::NewRawOneByteString(int, v8::internal::PretenureFlag) ()
#8  0x0000000000920694 in v8::internal::String::SlowFlatten(v8::internal::Handle<v8::internal::ConsString>, v8::internal::PretenureFlag) ()
#9  0x000000000096b309 in v8::internal::Parser::ParseProgram(v8::internal::Isolate*, v8::internal::ParseInfo*) ()
#10 0x000000000096b81a in v8::internal::Parser::Parse(v8::internal::ParseInfo*) ()
#11 0x000000000096b8ee in v8::internal::Parser::ParseStatic(v8::internal::ParseInfo*) ()
#12 0x00000000007785e3 in ?? ()
#13 0x000000000077a2bd in v8::internal::Compiler::CompileScript(v8::internal::Handle<v8::internal::String>, v8::internal::Handle<v8::internal::Object>, int, int, v8::ScriptOriginOptions, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Context>, v8::Extension*, v8::internal::ScriptData**, v8::ScriptCompiler::CompileOptions, v8::internal::NativesFlag, bool) ()
#14 0x0000000000676545 in v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate*, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, bool) ()
#15 0x00000000006766fb in v8::ScriptCompiler::CompileUnbound(v8::Isolate*, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions) ()
#16 0x0000000000b22c16 in node::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&) ()
#17 0x000000000067e0ea in v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&))
    ()
#18 0x00000000006a4acf in ?? ()

@kkoopa
Copy link
Collaborator

kkoopa commented Mar 27, 2016

That would seem appropriate, given that it creates a new, separate context. However, there ought to be some way of creating a reference between contexts, but I'm not familiar with how.

On March 27, 2016 10:07:13 PM GMT+03:00, Enerccio notifications@github.com wrote:

Looks like I lose the reference during contextifying environment? The
stacktrace suggests that...

#0  0x00007ffff1832099 in nodeproxy::ProviderProxy::~ProviderProxy() ()
  from /tmp/nproxy/build/Release/nproxy.node
#1  0x00007ffff1832121 in nodeproxy::ProviderProxy::~ProviderProxy() ()
  from /tmp/nproxy/build/Release/nproxy.node
#2  0x00000000007e64de in
v8::internal::GlobalHandles::PendingPhantomCallback::Invoke(v8::internal::Isolate*)
()
#3  0x00000000007e66e6 in
v8::internal::GlobalHandles::DispatchPendingPhantomCallbacks(bool) ()
#4  0x00000000007e686a in
v8::internal::GlobalHandles::PostGarbageCollectionProcessing(v8::internal::GarbageCollector,
v8::GCCallbackFlags) ()
#5  0x000000000081802c in
v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector,
v8::GCCallbackFlags)
   ()
#6  0x000000000081868d in
v8::internal::Heap::CollectGarbage(v8::internal::GarbageCollector, char
const*, char const*, v8::GCCallbackFlags) ()
#7  0x00000000007cb8d9 in
v8::internal::Factory::NewRawOneByteString(int,
v8::internal::PretenureFlag) ()
#8  0x0000000000920694 in
v8::internal::String::SlowFlatten(v8::internal::Handle<v8::internal::ConsString>,
v8::internal::PretenureFlag) ()
#9  0x000000000096b309 in
v8::internal::Parser::ParseProgram(v8::internal::Isolate*,
v8::internal::ParseInfo*) ()
#10 0x000000000096b81a in
v8::internal::Parser::Parse(v8::internal::ParseInfo*) ()
#11 0x000000000096b8ee in
v8::internal::Parser::ParseStatic(v8::internal::ParseInfo*) ()
#12 0x00000000007785e3 in ?? ()
#13 0x000000000077a2bd in
v8::internal::Compiler::CompileScript(v8::internal::Handle<v8::internal::String>,
v8::internal::Handle<v8::internal::Object>, int, int,
v8::ScriptOriginOptions, v8::internal::Handle<v8::internal::Object>,
v8::internal::Handle<v8::internal::Context>, v8::Extension*,
v8::internal::ScriptData**, v8::ScriptCompiler::CompileOptions,
v8::internal::NativesFlag, bool) ()
#14 0x0000000000676545 in
v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate*,
v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, bool)
()
#15 0x00000000006766fb in
v8::ScriptCompiler::CompileUnbound(v8::Isolate*,
v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions) ()
#16 0x0000000000b22c16 in
node::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&)
()
#17 0x000000000067e0ea in
v8::internal::FunctionCallbackArguments::Call(void
(*)(v8::FunctionCallbackInfo<v8::Value> const&))
   ()
#18 0x00000000006a4acf in ?? ()

You are receiving this because you commented.
Reply to this email directly or view it on GitHub:
#549 (comment)

@Enerccio
Copy link
Author

Actually I tested it with separate code using same c++ code:

#include <node.h>
#include <nan.h>

#include <set>
#include <string>
#include <iostream>

static const char* type = "ProviderProxyType";

namespace nodeproxy {

using namespace std;

class ProviderProxy : public Nan::ObjectWrap {
public:
  static NAN_MODULE_INIT(Init) {
      v8::Local<v8::FunctionTemplate> fnc = Nan::New<v8::FunctionTemplate>(MakeProxy);
      v8::Local<v8::FunctionTemplate> fnc2 = Nan::New<v8::FunctionTemplate>(Deproxify);
      Nan::Set(target, Nan::New("makeProxy").ToLocalChecked(),
                Nan::GetFunction(fnc).ToLocalChecked());
      Nan::Set(target, Nan::New("deproxify").ToLocalChecked(),
                Nan::GetFunction(fnc2).ToLocalChecked());
  }

 static NAN_METHOD(MakeProxy) {
   v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
   tpl->SetClassName(Nan::New("ProviderProxy").ToLocalChecked());
   tpl->InstanceTemplate()->SetInternalFieldCount(2);
   info.GetReturnValue().Set(Nan::GetFunction(tpl).ToLocalChecked());
 }

 static NAN_METHOD(Deproxify) {
   v8::Local<v8::Object> proxy = v8::Local<v8::Object>::Cast(info[0]);
   if (proxy->InternalFieldCount() != 2) {
     Nan::ThrowTypeError("Object is not a proxy!");
     return;
   }
   if (proxy->GetAlignedPointerFromInternalField(1) != (void*)type) {
     Nan::ThrowTypeError("Object is not a proxy!");
     return;
   }
   ProviderProxy* pproxy = Nan::ObjectWrap::Unwrap<ProviderProxy>(proxy);
   info.GetReturnValue().Set(Nan::New(pproxy->provider));
 }

 ProviderProxy();
 ~ProviderProxy();

 static NAN_METHOD(CallProxified);
 static NAN_METHOD(Get);

 static NAN_METHOD(New) {
    if (info.IsConstructCall()) {
      v8::Local<v8::Object> proxy = v8::Local<v8::Object>::Cast(info[0]);
      ProviderProxy* obj = new ProviderProxy();
      obj->Wrap(info.This());
      info.This()->SetAlignedPointerInInternalField(1, (void*) type);
      obj->provider.Reset(proxy);

      Nan::Set(info.This(), Nan::New("isProxied").ToLocalChecked(), Nan::New("yes").ToLocalChecked());

      v8::Local<v8::Function> proxify = v8::Local<v8::Function>::Cast(info[2]);
      obj->proxify.Reset(proxify);

      v8::Local<v8::Object> definedProviders = v8::Local<v8::Object>::Cast(info[1]);
      set<string> functions;

      Nan::MaybeLocal<v8::Value> providerList = Nan::Get(proxy,
          Nan::New("__providers").ToLocalChecked());
      if (providerList.IsEmpty()) {
        Nan::ThrowTypeError("Proxied object does not have any interface!");
        return;
      }

      Nan::MaybeLocal<v8::Object> ppsTested = Nan::To<v8::Object>(providerList.ToLocalChecked());
      if (ppsTested.IsEmpty()) {

        v8::String::Utf8Value str(providerList.ToLocalChecked()->ToString());
        string strstr = string(*str);

        v8::String::Utf8Value str2(Nan::New(obj->provider)->ToString());
        string strstr2 = string(*str2);

        v8::String::Utf8Value str3(info.Holder()->ToString());
        string strstr3 = string(*str3);

        Nan::ThrowTypeError(("ptr <" + to_string((uint64_t)(void*)obj) + ">" +
          strstr3+string(": ")+strstr2+string("'s __providers is NOT an array but ") + strstr).c_str());
        return;
      }
      v8::Local<v8::Object> pps = ppsTested.ToLocalChecked();
      uint32_t len = Nan::To<uint32_t>(Nan::Get(pps, Nan::New("length").ToLocalChecked()).ToLocalChecked())
                          .FromJust();
      for (uint32_t i=0; i<len; i++) {
        Nan::MaybeLocal<v8::String> testString = Nan::To<v8::String>(Nan::Get(pps, Nan::New(i)).ToLocalChecked());
        if (testString.IsEmpty()) {
          continue; // skip garbage
        }

        Nan::MaybeLocal<v8::Value> interface = Nan::Get(definedProviders, testString.ToLocalChecked());
        if (interface.IsEmpty()) {
          Nan::ThrowTypeError("There is no such interface defined!");
        }

        v8::Local<v8::Object> fncArray = Nan::To<v8::Object>(interface.ToLocalChecked()).ToLocalChecked();
        uint32_t flen = Nan::To<uint32_t>(Nan::Get(fncArray, Nan::New("length").ToLocalChecked()).ToLocalChecked())
                       .FromJust();
        for (uint32_t fi=0; fi<flen; fi++) {
          v8::Local<v8::String> function = Nan::To<v8::String>(Nan::Get(fncArray, Nan::New(fi))
            .ToLocalChecked()).ToLocalChecked();

           v8::String::Utf8Value fncName(function->ToString());
           std::string func = std::string(*fncName);
           functions.insert(func);
        }

        for (set<string>::iterator it=functions.begin(); it!=functions.end(); ++it) {
          string fnc = *it;
          Nan::SetMethod(info.This(), fnc.c_str(), CallProxified);
        }
      }

      info.GetReturnValue().Set(info.This());
    }
  }

    Nan::Persistent<v8::Object> provider;
    Nan::Persistent<v8::Function> proxify;
};

ProviderProxy::ProviderProxy() {

}

ProviderProxy::~ProviderProxy() {
  this->provider.Reset();
  this->proxify.Reset();
  int* x = (int*)(void*)0x1234;
  *x = 50000;
}

NAN_METHOD(ProviderProxy::CallProxified) {
  ProviderProxy* proxy = Nan::ObjectWrap::Unwrap<ProviderProxy>(info.Holder());
  v8::Local<v8::Object> provider = Nan::New(proxy->provider);

  v8::Local<v8::String> name = Nan::To<v8::String>(info.Callee()->GetName()).ToLocalChecked();
  Nan::MaybeLocal<v8::Value> fncV = Nan::Get(provider, name);

  if (fncV.IsEmpty()) {
    Nan::ThrowTypeError("Original object has lost method proxified");
    return;
  }

  v8::Local<v8::Value> fncLv = fncV.ToLocalChecked();

  if (!fncLv->IsFunction()) {
    Nan::ThrowTypeError("Original object changed the property into non-function");
    return;
  }

  v8::Local<v8::Function> fnc = v8::Local<v8::Function>::Cast(fncLv);

  int argc = info.Length();
  v8::Local<v8::Value> argv[argc];
  v8::Local<v8::Value> cargs[1];
  v8::Local<v8::Function> proxyCall = Nan::New(proxy->proxify);

  cargs[0] = proxyCall;
  for (int i=0; i<argc; i++) {
    cargs[0] = info[i];
    argv[i] = Nan::Call(proxyCall, Nan::New<v8::Object>(), 1, cargs).ToLocalChecked();
  }

  Nan::MaybeLocal<v8::Value> ret = Nan::Call(fnc, provider, argc, argv);
  v8::Local<v8::Value> retVal = (ret.IsEmpty() ? (v8::Local<v8::Value>)(Nan::Undefined()) : ret.ToLocalChecked());

  cargs[0] = retVal;
  Nan::MaybeLocal<v8::Value> vr = Nan::Call(proxyCall, Nan::New<v8::Object>(), 1, cargs);
  info.GetReturnValue().Set(vr.IsEmpty() ? (v8::Local<v8::Value>)(Nan::Undefined()) : vr.ToLocalChecked());
}

NODE_MODULE(test, ProviderProxy::Init)

};
var _ = require('util');
var vm = require('vm');
var x = require('./build/Release/ttest.node');

var y = {data:'bar', __providers:["test"], foo:function() {
  return 1;
}};

var Test = x.makeProxy();
var test = new Test(y, {test:["foo"]}, function(id) { return id; });

var sandbox = {
  p: test
};

Test = null;
test = null;
y = null;
var context = vm.createContext(sandbox);
sandbox = null;

global.gc();

var script = new vm.Script('"use strict";\np.foo();');
console.log(script.runInContext(context));

Which works fine (invoked with --expose-gc). Now, that works just fine, but if I use in much larger complex code, I get my instance deallocated prematurely by gc. Any idea what can cause that?

@kkoopa
Copy link
Collaborator

kkoopa commented Mar 27, 2016

There have been a number of issues with the vm module (contextify) which have been subsequently fixed. For example, this. Try running node master and see if the problem still is there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants