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

Expose way for native modules to modify JSC context #5540

Closed
wants to merge 5 commits into from

Conversation

appden
Copy link
Contributor

@appden appden commented Jan 26, 2016

We at Realm are developing a native module that actually requires using the JavaScriptCore API to expose a custom object into the context. At the moment, we have been using swizzling in Objective-C and a patched version of React Native, but we obviously can't continue to do this when we release.

The new APIs in this PR were made to best suit the existing React Native APIs on each platform. They provide the necessary hooks for advanced native module authors to accomplish what we are doing without any hacks.

@facebook-github-bot
Copy link
Contributor

By analyzing the blame information on this pull request, we identified @jspahrsummers, @lexs and @mkonicek to be potential reviewers.

@facebook-github-bot facebook-github-bot added GH Review: review-needed CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. labels Jan 26, 2016
@facebook-github-bot
Copy link
Contributor

@appden updated the pull request.

This notification will be fired on the JS thread after a JSContext has been created and setup, but before the JS bundle is loaded. This allows for advanced native modules to add custom functionality (that isn't possible with the existing APIs) into the context that will be available when JS bundle loads.
This method will return a long that represents the C pointer to the JSGlobalContextRef pointer, or will return 0 when there is no JSC context (debugging through a WebSocket on Chrome). This pointer is only useful if passed back through the JNI and used with the JavaScriptCore C API.
This native module callback will be called on the JS thread after a ReactBridge instance has been created, but before the JS bundle is loaded. This allows for advanced native modules to add custom functionality (that isn't possible with the existing APIs) into the context that will be available when the JS bundle loads.
@facebook-github-bot
Copy link
Contributor

@appden updated the pull request.

@sophiebits
Copy link
Contributor

How does this interact with Chrome debugging? I imagine that your native module wouldn't work in that case? We've tried to avoid exposing details specific to any particular executor in order to give us more flexibility in the future to switch engines, etc.

@ide
Copy link
Contributor

ide commented Feb 6, 2016

@spicyj without knowing the specifics my sense is it's likely incompatible with Chrome debugging. That doesn't worry me a whole lot because the JSC debugger is getting better (slated for OS X 10.12) but your point about switching engines to something like V8 is a good one.

@javache
Copy link
Member

javache commented Feb 6, 2016

The iOS side of this PR looks reasonable to me, although I'd move the notification definition to RCTJSCExecutor.h, since you'd only want to have access to that symbol if you also depend on the JSC being used.

@appden
Copy link
Contributor Author

appden commented Feb 6, 2016

Thanks for taking the time to look at this!

@spicyj we have our own crazy solution for Chrome debugging that hopefully won't be needed for very long considering JSC debugging is coming along. I appreciate wanting future flexibility with changing JS engines, but if that ever happens, we can add an API that returns an enum describing the kind of context being returned, or otherwise alter the API so native modules can access the V8 API instead.

@javache I'll gladly move the notification to RCTJSCExecutor.h, if you prefer 👍

This address feedback from the PR since this notification is directly tied to using JSC.
@facebook-github-bot
Copy link
Contributor

@appden updated the pull request.

@vjeux
Copy link
Contributor

vjeux commented Feb 6, 2016

Could you explain why you want to expose the JSC context directly. What are you doing against it that you cannot do with the normal bridge?

@sahrens
Copy link
Contributor

sahrens commented Feb 6, 2016

Yes, why do you "require" a custom object?

@lexs
Copy link
Contributor

lexs commented Feb 6, 2016

The problem here is that you expose an implementation detail of RN (that we use JSC) to native modules. If you'd explain what you actually need the context for we might be able to build an abstraction for this.

@appden
Copy link
Contributor Author

appden commented Feb 6, 2016

@vjeux @sahrens @lexs
Realm objects and collections are live representations of data in the Realm database. Using the JavaScriptCore APIs allows for us to expose these live objects in JavaScript where every object property access, and every index/length access on collections, consults the underlying database. All of this must be synchronous and must be done lazily. For instance, queries are lazily constructed, meaning I can query a database of million objects and immediately get back a Results object which I can then further filter or instead access any object in that collection by its index.

I wouldn't go so far to say that the JS engine is an implementation detail. It's certainly not an API most native modules should have to deal with, but for Realm to feasibly be exposed into JS, it's necessary we have direct access to the JS engine APIs. If, for instance, React Native switched to V8 on Android, that would not be a major issue for us as long as we continued to have access to the V8 context so we could instead use the V8 version of our JS bindings.

I hope that helps to explain why we need this. 😄

@vjeux
Copy link
Contributor

vjeux commented Feb 7, 2016

I think that the best way forward here is to get in a meeting together with people involved and figure out what the next steps are, especially given the time constraint.

@mkonicek
Copy link
Contributor

mkonicek commented Feb 9, 2016

Realm objects and collections are live representations of data in the Realm database. Using the JavaScriptCore APIs allows for us to expose these live objects in JavaScript where every object property access, and every index/length access on collections, consults the underlying database. All of this must be synchronous and must be done lazily.

This means that a property read or write won't do I/O on the main JS thread but will update the in-memory db. The transaction has to be explicitly committed, correct?

@appden
Copy link
Contributor Author

appden commented Feb 9, 2016

This means that a property read or write won't do I/O on the main JS thread but will update the in-memory db. The transaction has to be explicitly committed, correct?

Since the database is a memory mapped file, I/O is handled at the kernel level (e.g. page faults). Realm is designed to perform very well on the "main" thread (in this case the JS thread) for most use cases, but some methods will optionally be asynchronous, such as for performing expensive queries. It is indeed transactional – all writes must be made inside a write transaction.

@astreet
Copy link
Contributor

astreet commented Feb 10, 2016

To be clear, the one thing you want to accomplish is install native, synchronous hooks to the VM, correct? I think we're going to come up with a better way to do this down the road, probably when we finish the rewrite of the Android bridge in C++. In the meantime, we will ship this, but be aware that it will be deprecated in the next 6 months-year. As such, I want to make sure these functions are properly documented making sure people understand this is a temporary escape hatch until we have a proper API.

@@ -82,6 +82,7 @@ private native void initialize(
public native void callFunction(int moduleId, int methodId, NativeArray arguments);
public native void invokeCallback(int callbackID, NativeArray arguments);
public native void setGlobalVariable(String propertyName, String jsonEncodedArgument);
public native long getJavaScriptContext();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name something convincingly scary like getJavaScriptContextNativePtrExperimental and document that this API will go away soon.

Renamed and documented it to be extra frightening.
@facebook-github-bot
Copy link
Contributor

@appden updated the pull request.

@mkonicek
Copy link
Contributor

Comments added, @astreet, @nicklockwood is this good to go? Once it's good just shipit :)

@facebook-github-bot
Copy link
Contributor

@appden updated the pull request.

@astreet
Copy link
Contributor

astreet commented Feb 11, 2016

hold onto your butts
@facebook-github-bot shipit

(I actually have a feeling this is going to end in an anti-climactic import failure :P)

@astreet
Copy link
Contributor

astreet commented Feb 11, 2016

I guess the github bot can't handle irrelevant chatter

@astreet
Copy link
Contributor

astreet commented Feb 11, 2016

@facebook-github-bot shipit

@facebook-github-bot
Copy link
Contributor

@appden updated the pull request.

@vjeux
Copy link
Contributor

vjeux commented Feb 11, 2016

@astreet the bot is currently broken unfortunately, see our internal post. @bestander and @mkonicek are looking into it

@facebook-github-bot
Copy link
Contributor

@appden updated the pull request.

1 similar comment
@facebook-github-bot
Copy link
Contributor

@appden updated the pull request.

@bestander
Copy link
Contributor

@facebook-github-bot shipit

@bestander
Copy link
Contributor

should be fixed now

@facebook-github-bot
Copy link
Contributor

Thanks for importing. If you are an FB employee go to https://our.intern.facebook.com/intern/opensource/github/pull_request/1560433314281179/int_phab to review.

@appden
Copy link
Contributor Author

appden commented Feb 15, 2016

@vjeux @astreet @mkonicek @nicklockwood would you mind updating us on the status of this merge?

@bestander
Copy link
Contributor

CPP error

react-native-github/ReactAndroid/src/main/jni/react/Bridge.cpp:61:10: error: 'm_jsExecutor' was not declared in this scope
   return m_jsExecutor->getJavaScriptContext();

@appden
Copy link
Contributor Author

appden commented Feb 15, 2016

@bestander sounds like an issue after merging with master because m_jsExecutor was renamed to m_mainExecutor. Shall I rebase this branch onto master, or can you fix that on your end?

@lexs
Copy link
Contributor

lexs commented Feb 15, 2016

I tried to fix this on the imported diff. It should land now. I'll check on
in a few minutes.

On Mon, 15 Feb 2016 18:34 Scott Kyle notifications@github.com wrote:

@bestander https://github.com/bestander sounds like an issue after
merging with master because m_jsExecutor was renamed to m_mainExecutor.
Shall I rebase this branch onto master, or can you fix that on your end?


Reply to this email directly or view it on GitHub
#5540 (comment)
.

@lexs
Copy link
Contributor

lexs commented Feb 15, 2016

This PR also broke an internal class that extended NativeModule, I've fixed that and will monitor. I'll try to make sure this lands tonight.

@lexs
Copy link
Contributor

lexs commented Feb 15, 2016

It landed with e5ba46c.

@lexs lexs closed this Feb 15, 2016
@appden
Copy link
Contributor Author

appden commented Feb 15, 2016

Thanks @lexs!

JSContext *context = strongSelf.context.context;
RCTInstallJSCProfiler(_bridge, context.JSGlobalContextRef);

[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptContextCreatedNotification
Copy link
Member

@javache javache Apr 27, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is under an #if RCT_DEV so notifications will never fire in production.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that was pretty major mistake on my part. I realized that a little while after this was merged. 😞

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll put up a fix 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks! 👯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.