-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
[Discussion] FFI - require('dlopen') - libuv dynamic library loader binding #1762
Conversation
I don't think what are essentially raw pointers should be exposed to JS like this. Maybe just have some fieldless object only used for its identity that can be mapped back to pointer in C++. For example: Local<FunctionTemplate> t = FunctionTemplate::New(env->isolate());
t->InstanceTemplate()->SetInternalFieldCount(1);
// For '[object Library]' .toString behavior.
t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Library")); Then you can later create objects like: Local<Object> pointer_holder = t->GetFunction()->NewInstance();
pointer_holder->SetAlignedPointerInInternalField(0, ptr); // Or nullptr if you don't have ptr yet You cannot access them in js but you can later get it back in C++: void* ptr = pointer_holder->GetAlignedPointerFromInternalField(0); |
|
||
static void Dlopen(const FunctionCallbackInfo<Value>& args) { | ||
Environment* env = Environment::GetCurrent(args); | ||
HandleScope scope(env->isolate()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HandleScope isn't necessary (here and elsewhere.)
@petkaantonov If you as a user are worried about accessing the contents within the Buffer, then set its size to 0. This is how Essentially, these are just pointers. Though I'm definitely aware of the fact that we're going to need to be very explicit about the unsafe nature of messing with these APIs unless you know what you're doing, once the documentation part comes in. |
@bnoordhuis Nits fixed (hopefully 😄) on this one. |
@petkaantonov I'll add that it's important for users to have access within the contents of the pointer. Consider a C lib that exports an #if defined(WIN32) || defined(_WIN32)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
EXPORT int six = 6; With this new dlopen module, we can open up this lib, get the var lib = dl.dlopen('libfoo.so');
var sixSym = dl.dlsym(lib, 'six');
sixSym.readPointer(0, os.sizeof.int).readInt32LE(0);
// 6 ^ @bnoordhuis This also answers your question in #1750 regarding when you would ever use a value other than |
const binding = process.binding('dlopen'); | ||
|
||
exports.dlopen = function dlopen(name) { | ||
var lib = new Buffer(binding.sizeof_uv_lib_t); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be reconsidered because of the upcoming V8 changes. Here you'd essentially be using a Uint8Array()
. Problem is that with the new implementation we are going to allow V8'd GC to handle this automatically, and there's no way to use conditional logic to make the typed array external and persistent on instantiation. Best you might be able to do is pass the new instance to another function that does this for you.
But for performance an simplifying code complexity I would instead suggest returning a Persistent<External>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'm obviously not getting something here. What exactly is the implied change here from the switch to Uint8Array? As long as the C++ layer can still unwrap to the bare char *
then I think it shouldn't really matter. The GC handled Buffers before as well so I'm not sure what the change here will be.
Also this has basically been the recommended way of allocating memory for structs/etc. in node-ffi for years now, so I would hate for that to be an issue 😀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this has basically been the recommended way of allocating memory for structs/etc. in node-ffi for years now, so I would hate for that to be an issue
This hinges on whether you're alright with V8 cleaning up the pointer, or if you'd like manual control?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling new Buffer()
has always implied V8/node cleaning up the memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember you requested we allow a native module to supply the weak callback. Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry man, still not sure what you're driving at.
Are you worried about automating dlclose()
with when lib
get GC'd? I'm not so worried about that, I consider that the user's responsibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm concerned with making sure the new Buffer implementation meets all your needs. When Buffer moves to Uint8Array it will not have a weak callback available. Anyone who wishes to use one will have to externalize the object and setup the weak callback on their own.
I'm trying to recall a conversation we had 3+ years ago when I was doing my first rewrite of Buffer. I vaguely recall that for certain cases you wanted access to the weak callback because the lifetime of the pointer might have been different than that of the Object.
Do you mean just changing |
Not quite. I meant passing 0 to the "length" parameter on |
Will be used for the "dlopen" module tests.
This one is basically at the point where we need #1750 ( |
Was able to add some initial tests, though they're failing until #1750 is merged. |
@TooTallNate @trevnorris ... any updates on this? |
Closing given the lack of activity or response. This is likely still something that should be looked at more tho. /cc @jbergstroem |
This is a continuation of #1750 and #1759.
This PR adds a new public module:
require('dlopen')
. I'm the owner of the current npm module, and I'm fine with relinquishing control of it in favor of allowing core to use the name (I'm open to alternative names as well).The current impl is very close to a 1-1 mapping of the C uv_dlopen() and friends API, with very minimal JS wrapping to make the API more JS-friendly. We could also/instead do an object-oriented
Library
class API if there is consensus that that would be more node-like.Basic usage looks something like:
Similar to the other PRs, this still needs docs and tests. Mostly just looking for preliminary feedback/comments while I get those in.