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

Is this still being actively maintained? #38

Closed
trevorlinton opened this issue Jul 17, 2014 · 13 comments
Closed

Is this still being actively maintained? #38

trevorlinton opened this issue Jul 17, 2014 · 13 comments

Comments

@trevorlinton
Copy link
Collaborator

Hi,

I've been working heavily in nodobjc for quite a few months and have fixed a vast amount of bugs i've found, including:

  1. Support for node-ffi/ffi 1.0
  2. Structure returned for id/super message sending
  3. Better support for automatic garbage collection of delegates
  4. Less memory overhead using libxmljs to read in frameworks
  5. Integration of node's CF loop without needing uvcf (uvcf is great, but it pushes the clock timer to 0.01 MS and cpu use to 100% after NSApplication run. It also does not adhere to Apple's energy/performance guidelines) and requires a C++ compiled in solution.
  6. Fixed some odds and ends here and there to make code more clear (there was a reference in there where you were writing/reading a variable and in the comments didn't know why but it seg faulted without it, turns out it was a mem alignment issue where the ref wasn't written to the pointer unless it was read first).

I'd like to push these up but the API has changed (very slightly), the dependencies have changed, and I need it (quickly) for a project i'm doing.

I'm considering creating a derived project from nodobjc for the changes i've made so I can get into NPM in the next two-three weeks but I wanted to first check here to see if this is being actively maintained, if so i'll push the changes up here. However if you think this is something you'll not be maintianing actively going forward my company can commit to maintaining its feature set.

I guess i'm asking for your recommendation on what we should do concerning nodobjc. (BTW, any new project we'd be happy to add a disclaimer that its derived work from nodobjc and give you credit, and if the changes are integrated into nodobjc we'd redirect back, or, if you can add us as a contributor/collaborator we can continue to maintain nodobjc through your repo).

Thanks!
Trevor

@TooTallNate
Copy link
Owner

So yes, I'm still maintaining the project, and will happily review any pull requests.

I'm really glad that you have been working on getting some of these issues fixed, as they've all been on my radar for a long time now, it's just been hard to find the time. Let's get some of these patches landed!

@trevorlinton
Copy link
Collaborator Author

Great! We'll clean it up and get it over to you.

@trevorlinton
Copy link
Collaborator Author

Hi Nate,

I've finished my own unit tests and have fixed the items below. Can you open a new branch 0.1.0 that I can push up to? There's some issues below that we'd need to address before any sort of merge into a main/master.

Here's the branch: https://github.com/trevorlinton/NodObjC/tree/0.1.0

Changes:

  1. Decoupled many of the various prototypical inheritances between class/id/etc, the issue was a combination of both garbage collection not properly cleaning up extended classes and there were odd namespacing issues (discussed below) causing corner cases (such as created classes loosing their proto for the class when unwrapping).
  2. Put all the modules into a tighter closure (except for exception, i can update that though)
  3. Fixed some garbage collection issues when new function/selector were created, the pointer for the function/selector wasn't held onto, and if the user didn't hold it (but held its container) the GC would gobble it and an Unwrap error occurred.
  4. Imports now have an optional "recurse" level as a second param to $.Import, cycling recursively through all the imports dependencies can cause a simple nodobjc script to take sometimes 200~300MB. You can now specify a recursion level (0 for just that framework) as a second arg, if none is specified it will default to recursively including all dependences (as before).
  5. There were circular dependencies that have been fixed (i'm still trying to decouple a handful), these no longer cause GC issues but it may as code increases. Many of the SEL/imp/etc modules were merged together as they took up less memory (~1.2MB) by sitting in core rather than separate modules. The issue was core -> sel -> core -> imp -> core and multiple copies of core and several other modules were being made. Class/ID were converted to using a harder class/prototype schema and seems to have reduced the memory use as well.
  6. Running a dependency graph there was a lot of proxy/alias function and dead functions in the code (not used by unit tests or examples or I could find in the docs). These were removed, some were commented out and placed at the bottom of the .js files for review. Less code surface, less bugs :)
  7. The unit tests are not passing, i'm still trying to see what the intent of some of these were as i'm unsure what exactly was trying to be expressed, for example one unit tests creates and instance of a class then does a strict comparison of that class to the instance, failing if they are not equal. Is this supposed to be the case? An instances class definition should be equal to the original class, perhaps an "id instanceof Class" should be, but should a strict equality between instances and classes be true? I'm hoping maybe you can guide me through the failing unit tests and help see what can be done to correct them.
  8. I added uv.js as a test to see about integrating the CFEventLoop, I have a obj-c .mm file that links with node.js and successfully integrates the app loop with node but the uv.js version (which is pretty damn close) fails.
  9. I'm also currently working on yanking out libxmljs, the original bridgesupport leaked memory through libxmljs' node object, this has been fixed and drastically reduced memory footprint. There are some quick parsing "hacks" that can be done for parsing xml without having to use libxml. These hacks are fairly fool proof so long as the schema is straight forward, i'm hoping a 0.1.0 version can remove the libxmljs version and hopefully fix up the uv.js CFEventLoop issues.
  10. Added support for obj-c messages returning structures (specifically struts size >= 16 bytes). This required adding support for objcSendMsgStret (and its super equiv.).
  11. Changed import/loading system so that it uses the object returned by require for nodobjc to place definitions "onto" rather than using global's. This I thought would be just good practice :/ let me know if it may have screwed something up I didn't realize.
  12. I don't believe I've integrated the regex types support in index.js. This should also be finished soon.
  13. Fixed code to support node-ffi 1.2.x
  14. ref-struct vs. struct and types vs. types collisions, there were instances where Struct was actually ref-struct and not struct.js, i've resolved these as well. I'm unsure if the collisions were causing bugs as most of it was in dead code that was removed.

@TooTallNate
Copy link
Owner

Hey @trevorlinton Nice looking branch, and list! So I've added you as a committer to this main repo. You can push to a new branch if you want and we can take a closer look and get things merged to the master branch asap.

I really appreciate you diving in and doing what's been on my TODO list for quite a while! Cheers!

@trevorlinton
Copy link
Collaborator Author

@TooTallNate Hi Nate, after talking with some Apple engineers the general consensus was that ID's are a nomenclature and that Class and ID effectively mean the same thing since Classes are just Objects in obj-c (but only have significant differences in compiler validations and when integrating with C/C++ bridges). This may actually be good news but brings up a design ramification I wanted to clear through you before I do anything.

Should the ID and Class be merged together? If so, should the following assertions be true:

var someInstance = $.NSString('alloc');
assert(someInstance !== $.NSString);
assert(someInstance instanceof $.NSString);
assert(someInstance instanceof $.NSObject); // maintain heirarchy in obj-c
assert(someInstance.class() === $.NSString);
assert(someInstance.class().super() === $.NSObject);

assert(someInstance.super() == someInstance); // ???????  
// what happens here? and instance has a super of what? The NSObject "instance" i suppose?

someInstance.toString(); // Format: '[ '+ClassName+' '+pointerAddress+' ]'  [NSString 0x00000003 *]
// note that the * just tries to differentiate between a instance (id) and a class.
someInstance.class().toString(); // [NSString 0x00000001]
someInstance.class().super().toString(); // [NSObject 0x00000000]
someInstance.super().toString(); // [NSObject 0x00000000 *] ????
// what happens here? once again do we infer an "instance" of NSObject as the super? or?

assert(someInstance.isInstance() == true)
assert(someInstance.isClass() == false)
assert($.NSObject.isClass() == true)
assert($.NSObject.class() === Object.prototype) // ???

In addition static or '+' methods are only accessible by Class "definitions" and '-' or instance methods are only available by ID "definitions" (if you will, I say definitions as both Class/ID would come out of the same object in node).

Finally, extending a class simply extends its '+' methods and applies a new inheritance chain? In addition should extending a class into a new one immediately register it within the NodObjc main object for consistency?

@TooTallNate
Copy link
Owner

after talking with some Apple engineers the general consensus was that ID's are a nomenclature and that Class and ID effectively mean the same thing since Classes are just Objects in obj-c.

I mean I wouldn't call them the same thing... Class instances are a type of Object, but vice-versa isn't true. Just look at the Obj-C runtime reference. You can see that there's functions (prefixed class_) that only work on Class objects, and not instances (which the objc_ prefix is used for). That said... it does still make sense to me to keep them separate. Your ??? assertions below support this (more on that in a sec).

but only have significant differences in compiler validations and when integrating with C/C++ bridges

Well NodObjC is a bridge right? 😉

assertions...

So... all of those assertions seem fine to me in theory, however I'm not sure if we'll be able to get instanceof working reliably. Setting up an full JS prototype chain of Class objects seems costly to me when all you're really interested in is the base NSString.

assert(someInstance.super() == someInstance); // ???????  
assert(someInstance.super().toString(); // [NSObject 0x00000000 *] ????
// what happens here? once again do we infer an "instance" of NSObject as the super? or?

Both of those bases seem kind of weird to me. A super() function should probably only be available on Class objects, not instances.

assert($.NSObject.class() === Object.prototype) // ???

I would think null actually. Trying to merge over to the JS world once we reach the top of the Obj-C inheritance chain seems unnecessary to me.

extending a class simply extends its '+' methods and applies a new inheritance chain?

Well if we could get instanceof working like that, then ya, possibly. But we'd still need to do the objc_allocateClassPair() and friends dance as well, so that the Obj-C runtime registers the subclass as well (what the Class#extend() function does right now).

In addition should extending a class into a new one immediately register it within the NodObjc main object for consistency?

It already does that in the Class#register() function. Do you want it to be bound earlier? It's not quite usable/fully subclassed until the register() function is called (objc_registerClassPair() C function).

Let me know if that helps!

@trevorlinton
Copy link
Collaborator Author

@TooTallNate All of your points were fairly spot on. I tried to do some more refactoring but realized I was walking down a rabbit hole and have since stopped.

I have found one issue which is perplexing, using core.objc_getAssociatedObject and core.objc_setAssociatedObject to hold onto a pointer within ID.wrap seems to sometimes cause assertion violations (as the incoming/return pointers are not equal), I believe this is due to the objects original memory pointer being recycled by obj-c's runtime. In addition, it seems it prevents v8 from gobbling up anything passed through ID.wrap, which is obviously an issue. I was wondering if this was done for speed or if it served another purpose? I've also added a test-case memtest.js that tries to cause memory leaks. So far (there's still a ways to go) but it seems most of the memory issues are resolved.

You can see the updates here: trevorlinton@0184e91

Thoughts?

@TooTallNate
Copy link
Owner

IIRC, the core.objc_getAssociatedObject() and core.objc_setAssociatedObject() dance was required in order to ensure that a JavaScript wrapper would be the same wrapper instance throughout the Objective-C object's lifetime. See this test case for an example:

assert.ok(nsarray === $.NSArray, 'fails strict equality test')

As for your patch, I'll try reviewing that a bit later today. Cheers!

@trevorlinton
Copy link
Collaborator Author

@TooTallNate Ahh, that makes more sense, I was shoring up the code to pass all the unit tests and the array-references was one of the outliers I was struggling with. That helps, thanks. I'll soon have a finished patch with all the unit tests passing.

And the latest mem-tests i've ran allocate 2GB of structs, to delegates and function pointers without a single bit of memory leaks! (well, atleast on the javascript/v8 side of things).

@trevorlinton
Copy link
Collaborator Author

@TooTallNate All unit tests are passing, memory references seem clear and i've successfully decoupled Class from ID. Note there were minor changes to some unit tests, most were simply changing the "require" file/module; all of the code of the unit tests were kept.

@trevorlinton
Copy link
Collaborator Author

@TooTallNate I pushed up branch 0.1.0, docs need to be revised, maybe some more testing and your thumbs up and we can set it in motion!

@TooTallNate
Copy link
Owner

@trevorlinton Hey Trev, so I'm checking out your branch now. First issue is that the dependencies in the package.json aren't quite right/complete. node-ffi package has been renamed to ffi package (c0aaa30), and there's some additional missing deps.

@TooTallNate
Copy link
Owner

Let's continue this in #39.

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