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

People/sam/cocoascript boxing cleanup #40

Open
wants to merge 100 commits into
base: master
Choose a base branch
from

Conversation

samdeane
Copy link
Contributor

@samdeane samdeane commented Jan 19, 2016

I'm not sure if you'll want to take everything here, as there might be some Sketch specific things (I'm not certain of that, but I'm aware that I haven't had a chance to factor out all the changes nicely). There are certainly some project changes caused by upgrading to XC7/8, for example, and some other older debugging changes.

However, you might want to take an attempt I made to clean up the boxing, and a possible fix for the Mocha crash.

We had been operating with the "fix" that just called JSValueProtect on every object, and thus leaked all the JS objects.

I had yet another think about what the problem might be (assuming that it's not a bug in JSCore), and the theory I came up with was that either:

  • there might be situations where the JS object gets garbage collected whilst we have a reference to it stored somewhere other than our box (the prime candidate being ffi invocations)
  • or that there might be some short-circuiting going on where JSCore doesn't call finalize because it knows that we've made an object which nothing ever references

I suspect that the second situation might be happening with MOStruct. We seem to make JS objects here, and thus cause them to be boxed, but we don't actually hold on to the JS refs anywhere that I can see, other than the boxes themselves. The objects seem to be made in passing, as a way of extracting structures out of ffi return values.

My speculation is that in this situation JSCore might be "smart" enough not to bother actually initialising/finalising the object at all (or it might be a bug that it doesn't get finalised).

My fix for these two possible scenarios is to call JSValueProtect:

  • on every argument before a function/method invocation
  • on every JS object who's corresponding Obj-C object is stored in an MOStruct

I can then balance these with calls to JSValueUnprotect:

  • after the function invocation returns
  • when an MOStruct is destroyed

I'm not certain that this is a valid fix, but it seems to work in one of the cases that was crashing for me here.

It's a slightly better fix than just calling JSValueProtect everywhere, as it does allow some objects to be freed up.

I've also improved the cleanup that COScript/MochaRuntime does when shutting down. In particular, they clear out the box table, and the script removes its reference to the runtime, thus breaking a retain cycle that was happening for us (because, I think, the runtime contained a JS variable that had a reference to the script).


Note: This is a revision of #39, which was a revision of #34. I'm doing my best to confuse everyone...

samdeane and others added 30 commits April 30, 2014 11:41
Unfortunately there's no other way to suppress them optionally that I can find, and they were the only warnings in our build.
Import paths can be in the format:

    relative/to/script.js
    /absolute/path/to/script.js
    ~/relative/to/home/script.js
BohemianCoding/Sketch#3319 Script import: Add support for absolute and ~ paths
Also guards against multiple imports of the same URL, and therefore circular imports

Ref BohemianCoding/Sketch#3319
BohemianCoding/Sketch#3319 Add support for nested @import statements
Fix a bug which ignored first line of @import-ed scripts
@ccgus
Copy link
Owner

ccgus commented Feb 4, 2016

Finally getting around to this.
Why main thread for MOBoxManager initWithContext? Just to make things simpler?

@samdeane
Copy link
Contributor Author

samdeane commented Feb 5, 2016

Actually, I don't think the thread matters per-se, I was just trying to check that the box manager wasn't being hit from multiple threads. Probably it should record the thread that it was initialised on, and just assert that it's only used from that thread. Could also make it thread-safe of course, but I was wondering if it was some sort of race condition causing the crash, so the checks were just a little bit of investigation.

…cle which would otherwise occur if the runtime contains a global object that owns a reference to the COScript object (which happens in Sketch).
…ocoascript-boxing-cleanup

# Conflicts:
#	Cocoa Script.xcodeproj/project.pbxproj
#	src/framework/COScript.m
… the boxed object, so that we can annotate it with extra debug if necessary.
We were sometimes missing out some boxes when performing cleanup, because the keys returned to us by (for NSValue* key in _index) were failing to return a value when [_index objectForKey:key] was called!
I presume that this is because the key lookup was using isEqual: and somehow was failing to match somehow.
To avoid this we turn on NSMapTableObjectPointerPersonality for the keys.
For extra paranoia, we iterate the collection's objects, rather than its keys, so that we can be certain we're getting them all.
@samdeane
Copy link
Contributor Author

samdeane commented Jul 8, 2016

I've been looking at this yet again, in relation to another problem we had.

Our crude workaround for the crash (not this branch, but in the branch that Sketch is currently using) was just to leak all the JS objects until we cleaned up the context after the script executed.

However at some point we created a retain cycle so we weren't actually cleaning up the context ever - not good. In fixing that I uncovered another problem with cleanup, so I thought I'd give this branch another try whilst debugging it.

The cleanup problem still happened on this branch, and I tracked it down to an issue with the lookup table that keeps the boxed objects, which was failing to look up the box sometimes because it wasn't using pointer identity for the keys.

@samdeane
Copy link
Contributor Author

samdeane commented Jul 8, 2016

That pointer identity fix was something that Logan has actually incorporated into Mocha now, but when I rewrote the boxing stuff in this branch I missed it.

I'm still not sure if this branch will actually fix the main problem we're seeing, but I'll let you know.

@InvisiblePixels InvisiblePixels deleted the people/sam/cocoascript-boxing-cleanup branch May 24, 2020 12:17
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

Successfully merging this pull request may close these issues.

4 participants