Skip to content

[discussion] integrating nan or similar with io.js #349

Open

Description

@trevnorris

nan has done wonders for the community, but there are still missing bits. If these can be addressed there is a good desire to bring this into io.js itself. This thread should serve as a discussion on what are all the missing bits, what we can do about them and how to eventually get this into io.js.

The most prominent issue is lack of ABI compatibility. Needing to recompile with every new release, especially now with more frequent V8 updates, is difficult. @bnoordhuis mentioned that using templates is not a good form of ABI compatibility because they don't play well with the linker. (Ben, if you have any additional thoughts on this please feel free to include anything I've missed).

Activity

  1. kkoopa commented on May 13, 2015

    @kkoopa
    Collaborator

    I'll start by noting that not using templates leads to very clumsy code, and since V8 makes heavy use of templates, this would require not directly exposing anything from V8. Otherwise the issue of ABI compatibility will reemerge.

  2. rvagg commented on May 14, 2015

    @rvagg
    Member

    Some initial randomish thoughts:

    1. This is a separate effort to NAN and will be until it can completely replace NAN and we can deprecate it - even then we'll probably have overlap while people adjust
    2. Let's start simple and unambitious
    3. We're going to have to accept a world similar to NAN where the API/ABI will have to change over time to adapt to a changing upstream API but the benefit will be that you're dealing with a single API to code against
    4. People are going to want to reach around to V8 regardless of how sophisticated this is, we need to accept that and possibly make allowances for it, the problem with https://github.com/tjfontaine/node-addon-layer as I see it is that it goes too far in one leap and makes no allowances for anything but standard uses (the typical "framework problem"); this and item (2) above are the main reasons I've advocated for the NAN approach over the addon-layer approach in the past
    5. The continued instability from V8 is getting me down, they seem to have an endless appetite to screw with their API and therefore screw users of the C++ API, maybe it's the frustration with having to deal with permanent backward compatibility in JS to ES1 that forces them to take it out on the C++ API. @domenic says he's going to take this up with the V8 team but at this stage I'm much more willing to support efforts to detach Node from V8 as a direct dependency.
    6. Chakra introduces an interesting dynamic here and we may want to engage the Microsoft team on this effort given what they've had to go through to make their shim
  3. trevnorris commented on May 14, 2015

    @trevnorris
    CollaboratorAuthor

    Three things I believe could be done without templates and be ABI compliant:

    1. Local<Value> with a few methods. Such as Is{Undefined,Null,True,etc.}(), BooleanValue(), NumberValue(), etc. The hurdle to overcome would be casting to other types, and supporting all those APIs.
    2. typedef void (*FunctionCallback)(const FunctionCallbackInfo<Value>& info) could be a normal function call. info[i] could be an array of values, and since they're all initially Local<Values> the naive implementation would be supported. The problematic would be all calls that return Local<Object>.
    3. Buffers are pretty straight forward. This should even be possible using our Local<Value> abstraction, and in fact would be most compatible that way because currently it requires a Local<Object> and in the future will require a Local<Uint8Array>. Possibly something like the following (warning, this is very C-ish):
    struct node_buffer_s {
      char* data;
      size_t length;
    };
    typedef void node_buffer_s node_buffer_t;
    void FnCallback(const CallbackInfo* info) {
      node_buffer_t buf;
      Node::Buffer::GetData(info[0], &buf);
    }
  4. kkoopa commented on May 14, 2015

    @kkoopa
    Collaborator

    Would definitely want a code generator to generate the code for all the ensuing virtually identical wrapper functions with different types. It would be nice if one could get at the resulting C++ code after template processing, but before compilation.

    Have a look at how Python 3 is doing it. Python is also dynamically typed, and everything is an object, but I have to say that writing addons for it is rather painful.

    Also, I think the bar for a useful addon API should be set higher than trivial. If you can only do trivial things, you might as well just set up a socket or pipe of sorts and communicate between JavaScript and the real world through that.

  5. trevnorris commented on May 14, 2015

    @trevnorris
    CollaboratorAuthor

    @kkoopa

    Also, I think the bar for a useful addon API should be set higher than trivial.

    I was just echoing @rvagg's sentiment of:

    Let's start simple and unambitious

    So to clarify I was simply saying we start small, experiment and see how well it works. If it works at all.

    One important thing is that if we want to truly achieve ABI compatibility then the exposed API needs to be written in C. There have been more than a few people smarter than myself that have expressed that C++ doesn't do well at maintaining proper memory structures when compiled with different compilers, or even different versions of the same compiler.

  6. kkoopa commented on May 14, 2015

    @kkoopa
    Collaborator

    I agree that we have to start simple, implementation-wise. However, that initial implementation needs to scale up to offering a richer feature set.

    It does not need to be written in C as such, it's just the external functions (and data) that need to be "C" exported. Without C++, how would the the wrappers interact with v8?

  7. trevnorris commented on May 14, 2015

    @trevnorris
    CollaboratorAuthor

    It does not need to be written in C as such, it's just the external functions (and data) that need to be "C" exported.

    Agreed. I should have made my following statement more clear:

    One important thing is that if we want to truly achieve ABI compatibility then the exposed API needs to be written in C.

    So yes. I completely agree. It's just the user facing API that should be C.

  8. kkoopa commented on May 14, 2015

    @kkoopa
    Collaborator

    Something like this should do.
    https://github.com/martine/v8c/blob/v8c/src/v8c.cc

    On May 14, 2015 10:46:57 PM EEST, Trevor Norris notifications@github.com wrote:

    It does not need to be written in C as such, it's just the external
    functions (and data) that need to be "C" exported.

    Agreed. I should have made my following statement more clear:

    One important thing is that if we want to truly achieve ABI
    compatibility then the exposed API needs to be written in C.

    So yes. I completely agree. It's just the user facing API that should
    be C.


    Reply to this email directly or view it on GitHub:
    #349 (comment)

  9. trevnorris commented on May 14, 2015

    @trevnorris
    CollaboratorAuthor

    @kkoopa good stuff. we'd just have to extend it to support current APIs like Buffer.

  10. kkoopa commented on May 14, 2015

    @kkoopa
    Collaborator

    And new V8. Notice that this project has been abandoned for 6 years.

    On May 14, 2015 11:00:11 PM EEST, Trevor Norris notifications@github.com wrote:

    @kkoopa good stuff. we'd just have to extend it to support current APIs
    like Buffer.


    Reply to this email directly or view it on GitHub:
    #349 (comment)

  11. bnoordhuis commented on May 14, 2015

    @bnoordhuis
    Member

    One important thing is that if we want to truly achieve ABI compatibility then the exposed API needs to be written in C. There have been more than a few people smarter than myself that have expressed that C++ doesn't do well at maintaining proper memory structures when compiled with different compilers, or even different versions of the same compiler.

    Structures/classes don't have to be a problem when you don't use features such as virtual methods, multiple inheritance, member function pointers, etc.

    I suppose name mangling could be an issue for people that mix C++11 code with pre-C++11 code. You can work around it by building everything with -fabi-version=6 but that requires that you use a recent compiler.

  12. kkoopa commented on May 14, 2015

    @kkoopa
    Collaborator

    So, what we'd essentially want is to wrap v8's C++ exports in C exports to get a stable ABI and then have a (NAN-derived) header library on top of that which would restore the C++ nature of V8's API by mapping to the C exports.

    Something like this:

    extern "C" {
      V8StringUtf8 v8_string_utf8_new(const char* data, int length);
      V8Number v8_number_int32_new(int32_t val);
      V8Number v8_number_uint32_new(uint32_t val);
    }
    template<v8::String>
    v8::Local<v8::String> NanNew(const char *data, int length = -1) {
      return v8_string_utf8_new(data, length);
    }
    
    template<v8::Int32>
    v8::Local<v8::Int32> NanNew(int32_t val) {
      return v8_number_int32_new(val);
    }
    
    template<v8::UInt32>
    v8::Local<v8::UInt32> NanNew(uint32_t val) {
      return v8_number_uint32_new(val);
    }
  13. kzc commented on May 15, 2015

    @kzc

    Microsoft appears to have created a V8 compatible C++ API facade for Chakra. While it is a nice piece of engineering, it also has the disadvantage of trying to keep up with a constantly changing V8 API that is not managed by the node project.

    I like the javascript engine wrapper C API idea proposed by @trevnorris. Node itself and node native modules could only use this C API. That way the javascript engine (V8, Spidermonkey, Duktape, JavascriptCore or other) could be made to be pluggable at runtime depending on the needs of the user. Native node modules compiled against this hypothetical C API could work against any such runtime-pluggable engine without recompilation due to its more stable ABI.

    However, one downside with such a javascript engine C API would be that it would impose a little bit of overhead on every javascript <=> c++ operation as compared to header-only inline C++ classes or C macros. Even so, I still think it is worth the cost for the maintainability and the flexibility it would offer.

  14. trevnorris commented on May 15, 2015

    @trevnorris
    CollaboratorAuthor

    @kzc After doing testing in this area I'm fairly confident that we'd be able to do this with very little overhead. At least minimal enough where users wouldn't feel it in their JS code.

  15. kkoopa commented on May 15, 2015

    @kkoopa
    Collaborator

    Clearly yes. The overhead of context switching from JavaScript to C++ drowns
    out everything else.

    On Friday 15 May 2015 03:06:11 Trevor Norris wrote:

    @kzc After doing testing in this area I'm fairly confident that we'd be able
    to do this with very little overhead. At least minimal enough where users
    wouldn't feel it in their JS code.


    Reply to this email directly or view it on GitHub:
    #349 (comment)

  16. 71 remaining items

  17. geoffkizer commented on Jun 17, 2015

    @geoffkizer

    @obastemur: how do you get rid of handle<> and local<>?

  18. bmeck commented on Jun 17, 2015

    @bmeck
    Member

    @obastemur

    I would suggest you to check the changes to V8's GC over time. There are no thousands of ways for GC and not a long standing best one. This is a delicate place that may change from one version to another. Even if you have no interest for other JS engines, taking other engines into reference would help the final interface less vulnerable.

    I don't understand the implication here with respect to needing abstract behaviors to be listed for compatibility.

  19. trevnorris commented on Jun 17, 2015

    @trevnorris
    CollaboratorAuthor

    I feel like the proposal is moving from "let's create an abstraction layer from how node currently works" to "let's rethink the fundamental architecture to accommodate all possible variances". I'm skeptical that would fly with the TSC.

    There's functionality that Node needs. Like knowing specific information about the life of an object. I remember a few years ago Ben attempted to implement node on top of SM, but found it wasn't possible to keep feature parity. Node won't sacrifice features to achieve an abstraction. The majority of the community doesn't care about the abstraction. We need to make the case why it's in their best interest to do so. Regardless of preventing V8 breakage, if features are gimped then it won't be welcome.

  20. kzc commented on Jun 17, 2015

    @kzc

    a few years ago Ben attempted to implement node on top of SM, but found it wasn't possible to keep feature parity.

    @trevnorris, what v8 feature(s) specifically? JXCore is a working Node fork on top of an engine abstraction API supporting both SM and V8. So it's clearly possible.

    Are you suggesting that the node foundation would only entertain supporting non-v8 engines only if they were wrapped by a v8-compatible C++ API as Microsoft has done with Chakra? But even so, the v8 API is a moving target - hence this discussion to have an engine agnostic API wrapper.

  21. geoffkizer commented on Jun 17, 2015

    @geoffkizer

    The majority of the community doesn't care about the abstraction. We need to make the case why it's in their best interest to do so.

    I agree.

    Here's the case as I see it for a "simple native binding", based on templates or similar:

    (1) Simplifies your native code. No need to learn a JS engine API, V8 or abstracted or otherwise. Just use the native types supported by the binding layer and everything works. Easy to use, easy to get right.
    (2) Isolates you from V8 API breakage.
    (3) Makes it easier to support other JS engines.

    Most module authors don't care much about (3). They care about (1) and (2). Done properly, I think this could be compelling enough to make them want to use it.

  22. trevnorris commented on Jun 17, 2015

    @trevnorris
    CollaboratorAuthor

    @kzc It was years ago, and most likely that whatever was lacking at the time now exists. And in terms of V8, I'm saying that no existing functionality can can't be sacrificed because some VM doesn't support it. The abstraction needs to allow all public APIs to continue working as they do today.

    @geoffkizer Those are good points, and it sounds like you are more directly addressing native module compatibility. The discussion does seem to have diverged into whether all of core should be abstracted or just the module interface. Which are you looking for?

    EDIT: Fixed typo

  23. obastemur commented on Jun 17, 2015

    @obastemur

    how do you get rid of handle<> and local<>?

    @geoffkizer I've mentioned on my previous comments a bit. JXcore's embedding interface is JS engine independent. API The approach can be improved and used for native add-ons.

    I have no desire for Node to try and satisfy all the implementation differences between engines.
    I don't understand the implication here with respect to needing abstract behaviors to be listed for compatibility.

    @bmeck What I was saying that; we better know the implementation differences among the engines, so we know what is minimalistic and less likely to be broken. I agree with the documentation part.

    I feel like the proposal is moving from "let's create an abstraction layer from how node currently works" to "let's rethink the fundamental architecture to accommodate all possible variances".

    I thought the discussion was a minimalistic API for native addons.

  24. kzc commented on Jun 17, 2015

    @kzc

    The abstraction needs to allow all public APIs to continue working as they do today

    @trevnorris do you consider the (ever changing) v8 API to be part of Node's public API? Where is the line drawn for the public API?

  25. trevnorris commented on Jun 17, 2015

    @trevnorris
    CollaboratorAuthor

    @kzc I'm only considering the APIs we have direct control over. Don't care about the V8 API.

    @obastemur This thread has gotten long, and wires were crossed somewhere. Thought that some of this discussion had shifted to removing V8 from core. Native modules is a much easier target. Thanks for clarifying.

  26. obastemur commented on Jun 17, 2015

    @obastemur

    Agree it's been a long thread. Luckily, many experienced developers participating on this discussion. How about prepare and share a minimalistic API (coverage) that is compatible to the engines discussed here.

    We might have a better picture on the actual facts / problems. Moreover, we may see if it's reasonable or not.

    I can spend some time / or collaborate on the initial list upcoming days.

  27. geoffkizer commented on Jun 18, 2015

    @geoffkizer

    @trevnorris:

    The discussion does seem to have diverged into whether all of core should be abstracted or just the module interface. Which are you looking for?

    I think the pressing need is to abstract the module interface, so that's what I think we should focus on.

    That's what I meant above re "abstracted user facing API"; I should have said "abstracted user facing module API" to be clearer.

  28. trevnorris commented on Jun 18, 2015

    @trevnorris
    CollaboratorAuthor

    For anyone that's participated, I'll be writing up a summary of what these abstractions are attempting to achieve on nodejs/node#1993

    Basically we're just in the process of properly forming a WG to handle these things.

  29. trevnorris commented on Jun 24, 2015

    @trevnorris
    CollaboratorAuthor

    For everyone's information, the API WG repo has been created. I'm still writing the initial README, but feel free to join if you wish to get involved: https://github.com/nodejs/api

    I plan for all communication possible to be async. So submit issues and whatnot and we'll get things going.

  30. trevnorris commented on Jun 30, 2015

    @trevnorris
    CollaboratorAuthor

    Everyone, @obastemur was awesome enough to write up the first PR for the API WG. This has to do w/ the native API, and those that have participated in this thread are more qualified to give feedback from myself: nodejs/api#4

  31. Ben007 commented on Nov 13, 2015

    @Ben007

    A bit outdated but just saw this discussion.I am trying to put up a cross platform native addon. I can't tell how hard it is to catch up with all the changes and differences. Looking forward to see a common API!

    I think the pressing need is to abstract the module interface, so that's what I think we should focus on.

    @geoffkizer exactly.

    @kzc It was years ago, and most likely that whatever was lacking at the time now exists. And in terms of V8, I'm saying that no existing functionality can can't be sacrificed because some VM doesn't support it. The abstraction needs to allow all public APIs to continue working as they do today.

    @trevnorris nothing new with spider monkey. @obastemur implemented the missing features into spider.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions