-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Add JSRT weak reference APIs #2948
Conversation
@jasongin, |
lib/Jsrt/Jsrt.cpp
Outdated
VALIDATE_JSREF(weakRef); | ||
|
||
return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { | ||
Memory::RecyclerWeakReference<char>* recyclerWeakReference = reinterpret_cast<Memory::RecyclerWeakReference<char>*>(weakRef); |
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.
Can we add a break on this line to make it easier to read?
lib/Jsrt/Jsrt.cpp
Outdated
@@ -2890,6 +2890,40 @@ CHAKRA_API JsSetPromiseContinuationCallback(_In_ JsPromiseContinuationCallback p | |||
/*allowInObjectBeforeCollectCallback*/true); | |||
} | |||
|
|||
CHAKRA_API JsCreateWeakReference( | |||
_In_ JsValueRef value, | |||
_Out_ JsWeakRef* weakRef) |
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.
weakRef [](start = 21, length = 7)
PARAM_NOT_NULL check for out parameters in both APIs
lib/Jsrt/Jsrt.cpp
Outdated
return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { | ||
Memory::RecyclerWeakReference<char>* recyclerWeakReference = reinterpret_cast<Memory::RecyclerWeakReference<char>*>(weakRef); | ||
*value = reinterpret_cast<JsValueRef>(recyclerWeakReference->Get()); | ||
return JsNoError; |
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.
Does it make sense to return a specific error code when the reference was already released? Having it return an invalid reference seems ok, I just wasn't sure whether this was consistent with other APIs.
/cc @liminzhu
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 would not consider it a failure when the weak-referenced value is not available, so I don't think it should return an error code then.
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.
That's true and consistent with other libraries, there just aren't many APIs in JSRT where the out param can be JS_INVALID_REFERENCE after a successful call. I think the documentation is pretty clear, so that should cover it.
lib/Jsrt/Jsrt.cpp
Outdated
@@ -2890,6 +2890,40 @@ CHAKRA_API JsSetPromiseContinuationCallback(_In_ JsPromiseContinuationCallback p | |||
/*allowInObjectBeforeCollectCallback*/true); | |||
} | |||
|
|||
CHAKRA_API JsCreateWeakReference( |
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.
JsCreateWeakReference [](start = 11, length = 21)
I think this API should not be callable during collection callbacks as this allocates 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'll add a check for that.
JsWeakRef weakRef; | ||
FAIL_CHECK(JsCreateWeakReference(valueRef, &weakRef)); | ||
|
||
FAIL_CHECK(JsGetWeakReferenceValue(weakRef, &valueRef)); |
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.
Would it make sense to fetch the value to a new reference, and check that valueRef == weakRefValue
?
lib/Jsrt/Jsrt.cpp
Outdated
|
||
Recycler* recycler = threadContext->GetRecycler(); | ||
Memory::RecyclerWeakReference<char>* recyclerWeakReference = | ||
recycler->CreateWeakReferenceHandle<char>(reinterpret_cast<char*>(value)); |
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.
CreateWeakReferenceHandle [](start = 22, length = 25)
Should it be ok to use FindOrCreateWeakReferenceHandle instead of CreateWeakReferenceHandle?
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 not sure. I think @boingoing actually wrote this code originally. Taylor can you comment on this?
lib/Jsrt/Jsrt.cpp
Outdated
@@ -2890,6 +2890,40 @@ CHAKRA_API JsSetPromiseContinuationCallback(_In_ JsPromiseContinuationCallback p | |||
/*allowInObjectBeforeCollectCallback*/true); | |||
} | |||
|
|||
CHAKRA_API JsCreateWeakReference( | |||
_In_ JsValueRef value, | |||
_Out_ JsWeakRef* weakRef) |
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.
weakRef [](start = 21, length = 7)
Initialize weakRef to nullptr
|
||
CHAKRA_API JsGetWeakReferenceValue( | ||
_In_ JsWeakRef weakRef, | ||
_Out_ JsValueRef* value) |
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.
value [](start = 22, length = 5)
Initialize value to JS_INVALID_REFERENCE
lib/Jsrt/Jsrt.cpp
Outdated
{ | ||
VALIDATE_JSREF(weakRef); | ||
|
||
return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { |
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.
Is GC deterministic? What would happen in a TTD scenario when the object backing a weak reference is collected at different points?
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 don't know enough about how TTD works to answer that. I'd appreciate input from someone else about how weak references should interact with TTD.
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.
@mrkmarron can hopefully offer an opinion when he's got the time
Looks like the OSX and Ubuntu static tests failed your freshly added test; after invoking the GC the reference wasn't invalidated. |
@dotnet-bot test Ubuntu ubuntu_linux_release please |
I see ubuntu_linux_debug_static failed the same way. I ran the test (and it passed) on Ubuntu with a release build. Maybe the GC behavior is different with a debug build? I'll try to repro. |
I confirmed the test passes with a Release build and fails with a Debug build. I assume because the GC has different configuration in a debug build. I don't know yet what to do about that. |
Is the test even in the right place? I just noticed there are other (more complete?) JSRT tests at |
@jasongin - That should be the right place to add jsrt native test. |
When I put the test into Why is there native test code in 2 places, separated for Windows and non-Windows platforms? |
@akroshg - do you know why? |
Why not add test in core\bin\NativeTests ? |
@akroshg I want to ensure the new APIs work on all supported platforms. Originally in this PR I had put tests under then |
They were written in different branches. the windows only depends on the catch framework and during that time the cross-plat was not picked up. However there were compilation and other sort of problems happened when we directly use the windows to crossplat which needed to be looked at. (It just we haven't got time to consolidate them yet). In reply to: 300545940 [](ancestors = 300545940) |
@ yes they are for windows only (although no effort made to consolidate them). NativeTest were put along with ch under the bin directory. When I did that I put there so that all application (test or product) will be found under bin folder. But it seems like it can be confusing. In reply to: 300549055 [](ancestors = 300549055) |
I pushed a couple commits to this PR, to address feedback above and move the test to Remaining issues are the question about |
Do APIs get shipped to Chakra when in |
This is necessary to implement the reference functions in the new Node.js addon API in Node-ChakraCore. Those reference APIs are used by native addons that hold a reference to JavaScript values that have associated native data, such as a typed array with external data, or a native class instance that is "wrapped" in a JavaScript object. The weak references are useful because often the native code only needs to access the value as long as some JS code is still holding it. In Node-V8, those APIs are implemented using a |
@jasongin exactly what I look for, thanks! Do you imagine an additional finalizer param for |
That would be redundant because |
What does everyone think? While these APIs should work fine in Chakra, I don't know any reason they will be really needed there. (There's no plan to implement N-API for Node-Chakra AFAIK.) |
@jasongin my argument - NAPI is still experimental and in case we need to change the new JSRT APIs for w/e reason it's a lot easier when they're just in ChakraCore. I want them in Chakra eventually ofc. In general I don't like API differences between Chakra and ChakraCore unless there's legitimate reason not to ship something to Chakra, but there's no need to rush for the reason you mentioned. My mental model is to 'stage' experimental APIs in ChakraCore and once they mature we push them in Chakra. |
- Move new APIs from ChakraCommon.h to ChakraCore.h, conditional on CHAKRACOREBUILD_ - Call FindOrCreateWeakReferenceHandle() instead of CreateWeakReferenceHandle()
I pushed another commit:
|
I think the TTD issue should not be blocking for now. These changes can only impact TTD if the new APIs are called, and in the short term that's only likely to be done via N-API in Node-ChakraCore, and N-API is still officially experimental. |
lib/Jsrt/JsrtCommonExports.inc
Outdated
@@ -103,6 +103,8 @@ | |||
JsGetRuntime | |||
JsIdle | |||
JsSetPromiseContinuationCallback | |||
JsCreateWeakReference | |||
JsGetWeakReferenceValue |
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.
Since you moved the headers to ChakraCore.h
, you should also move these lines below the #ifndef
below as well, I believe.
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.
Fixed!
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.
LGTM 👍
I think FindOrCreateWeakReferenceHandle is the right thing to do here. Not sure about the TTD impact, though.
Merge pull request #2948 from jasongin:weakref - Add a new typedef: `JsWeakRef` - Add two new APIs: `JsCreateWeakReference()`, `JsGetWeakReferenceValue()` - Add a native test for the new APIs The weak reference APIs are required for N-API in Node-ChakraCore. See nodejs/node-chakracore#238
Merge pull request #2948 from jasongin:weakref - Add a new typedef: `JsWeakRef` - Add two new APIs: `JsCreateWeakReference()`, `JsGetWeakReferenceValue()` - Add a native test for the new APIs The weak reference APIs are required for N-API in Node-ChakraCore. See nodejs/node-chakracore#238
Added API reference in wiki. Please update them if needed in the future. https://github.com/Microsoft/ChakraCore/wiki/JsWeakRef |
JsWeakRef
JsCreateWeakReference()
,JsGetWeakReferenceValue()
The weak reference APIs are required for N-API in Node-ChakraCore. See nodejs/node-chakracore#238