-
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
Implement JsGetModuleNamespace API fixes #3616 #4707
Conversation
e2a68c3
to
fd54a47
Compare
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.
Another really valuable contribution!
@kfarnung since you just backported one change to 1.9 for use in Node, perhaps this should target 1.9 too? Also note the email I sent about Intl targeting master, so we may have to reconsider the release/branch structure for node in the near future.
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.
This is really nice, thank you for taking the time to tackle this one. We need to take the changes to move the code to JsrtCore.cpp, check for nullptr, etc. Overall, though, this looks very good and I don't think we'll have much trouble taking it.
@jackhorton already mentioned it but, yes, we should probably rebase this onto release/1.9. There is discussion internally about how to configure code going from ChakraCore into Node-ChakraCore but this change is stand-alone enough that it can probably land in release/1.9 and avoid that discussion entirely.
lib/Jsrt/ChakraCommon.h
Outdated
@@ -225,6 +225,10 @@ typedef unsigned short uint16_t; | |||
/// </summary> | |||
JsErrorModuleParsed, | |||
/// <summary> | |||
/// Module was not yet evaluated when JsGetModuleNamespace was called. | |||
/// </summary> | |||
JsErrorModuleNotEvaluated, |
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 if we'll be able to add this error code here since this enum is part of the Windows API surface. I'm not actually sure how fixed our enum values are, though. Might be safe if the new one is added at the end. Maybe @curtisman could answer?
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 this is just an enum
and not an enum class
, I believe the compiler simply aliases it to an integer type in both C and C++. So it should remain both source- and binary-compatible as long as the new constant is added to the end. Adding it to the middle as done here is indeed problematic as it causes everything after it to be renumbered.
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.
Correct. Adding it at the end will solve the problem
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've moved it to the end of the section it's in - as it's the section for incorrect usage of API e.g. wrong parameters - I believe the numbering is restarted for each section (as the section headings have explicit values so this should be ok?
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.
Seems like this location works. Our new code is using a value which was previously unused and no other values in the enum are affected. I think @curtisman was implying to add to the end of the enum in his comment but if he's onboard with this we should be good.
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 didn't notice the start of the next section with an explicit value.
Yep. Where you have now at the end of the section is good. Thanks.
lib/Jsrt/Jsrt.cpp
Outdated
/*allowInObjectBeforeCollectCallback*/true); | ||
} | ||
|
||
CHAKRA_API JsGetModuleNamespace(_In_ JsModuleRecord requestModule, _Outptr_result_maybenull_ JsValueRef *moduleNamespace) |
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 believe this API should live in JsrtCore.cpp instead of Jsrt.cpp. If it's here it needs to be surrounded by #ifdef _CHAKRACOREBUILD
but we could avoid that entirely if it's just moved over into that other file where the other module API live anyway.
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.
It was already inside #ifdef _CHAKRACOREBUILD but now moved to JsrtCore.cpp instead.
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.
Sorry, I didn't see the _CHAKRACOREBUILD macro but suppose it must be there because of the preceding core-only API. Thanks for moving it, anyway, I think locating this API near the other module ones is a good idea.
lib/Jsrt/Jsrt.cpp
Outdated
return JsErrorInvalidArgument; | ||
} | ||
Js::SourceTextModuleRecord* moduleRecord = Js::SourceTextModuleRecord::FromHost(requestModule); | ||
if(!moduleRecord->WasEvaluated()) |
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.
Nitpick: space between if and (
lib/Jsrt/Jsrt.cpp
Outdated
{ | ||
return JsErrorModuleNotEvaluated; | ||
} | ||
*moduleNamespace = (JsValueRef) moduleRecord->GetNamespace(); |
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.
Before dereferencing moduleNamespace
make sure it's not null. PARAM_NOT_NULL(moduleNamespace);
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.
Also, this is an _Out_
parameter so you should initialize it (*moduleNamespace = nullptr;
) at the beginning of this function after verifying it is not null. We should do this before returning via other paths so that this variable is always initialized.
bin/ch/WScriptJsrt.cpp
Outdated
JsValueRef errorObject; | ||
JsValueRef errorMessageString; | ||
|
||
if (wcscmp(errorMessage, _u("")) == 0) { |
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.
Nitpick: { character at end of this line should be on new line below.
test/es6module/GetModuleNamespace.js
Outdated
assert.areEqual(mod0Namespace.export5, "exporting"); | ||
}); | ||
|
||
let test2 = import("mod1.js").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.
Does the dynamic import statement return a promise resolved with the module namespace object? If it does you could pass it to the then handler and assert that it's strictly equal to the result of GetModuleNamespace
, right?
import("mod0.js").then(ns => {
//…
assert.areEqual(ns, mod0Namespace);
}
test/es6module/GetModuleNamespace.js
Outdated
}); | ||
|
||
assert.throws(()=>WScript.GetModuleNamespace("mod0.js")); | ||
assert.throws(()=>WScript.GetModuleNamespace("mod3.js")); |
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.
Add the error case where GetModuleNamespace
is called with no arguments.
test/es6module/GetModuleNamespace.js
Outdated
assert.areEqual(mod1Namespace.export4.constructor.name, "AsyncFunction"); | ||
}); | ||
|
||
assert.throws(()=>WScript.GetModuleNamespace("mod0.js")); |
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 it possible to add a test for the JsErrorModuleNotEvaluated
case explicitly? Does this line reliably test that?
@boingoing I think I've addressed everything other than rebasing to 1.9. I've commented above on a couple of points. I think my test cases may be excessive/over the top I was trying to test that every type of export works BUT considering I'm also now testing against the result of import() as long as import() isn't broken half the cases are irrelevant. (That said it uses the same internal mechanism as import()...) I assume the best way to rebase to 1.9 would be to use a whole new branch and hence a new PR? If so probably best to agree the shape of the commit/pass reviews here now we've started then I can cherrypick to a new branch and open a new PR for the final test/merge. |
@rhuanjl Just leave it pointing to master. We have other changes in master that we'll eventually want in node-chakracore so we'll have to cut a new branch anyway. |
lib/Jsrt/Core/JsrtCore.cpp
Outdated
{ | ||
return JsErrorModuleNotEvaluated; | ||
} | ||
*moduleNamespace = (JsValueRef) moduleRecord->GetNamespace(); |
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.
(JsValueRef) [](start = 23, length = 12)
I prefer explicit casting operators like static_cast or reinterpret_cast because their behavior is much clearer than C-style casts.
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, thanks for addressing my feedback.
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 thanks @rhuanjl ! |
304133a
to
8d58dc2
Compare
lib/Jsrt/Core/JsrtCore.cpp
Outdated
{ | ||
return JsErrorModuleNotEvaluated; | ||
} | ||
*moduleNamespace = static_cast <JsValueRef>(moduleRecord->GetNamespace()); |
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.
Tiny nitpick: don't put a space between static_cast and the <
8d58dc2
to
ee9daa6
Compare
OK I think everything's done, let me know if you do want it rebased to 1.9, I've left it on master for now as per the comment from @kfarnung. I note that I think modules in node-chakracore will take quite a lot of work on the chakra-shim side in addition to this - so probably no reason to fast track this to node-chakracore as it won't be able to use it without significant additional effort. |
@rhuanjl We'll continue on and merge this to master, don't worry about porting it to release/1.9. Sorry about the confusion. Thanks for another great contribution, I'll kick off the internal testing and try to marshal it through. |
Merge pull request #4707 from rhuanjl:moduleNamespace Implement a new Jsrt API to get a Module Namespace from an evaluated module record. As discussed in #3616 This is intended for use by any embedder who wishes to access module exports from native code e.g. to use one as an entry point - I note that node's implementation of ESModules with v8 uses an equivalent v8 facility and so this is likely one of the required steps towards implementing ESModules in node-chakracore. For testing purposes only a WScript method has been added to ch that wraps this method to allow fetching a namespace object from within Javascript - this has then been used to create a test case. *cc* @liminzhu @boingoing
Implement a new Jsrt API to get a Module Namespace from an evaluated module record. As discussed in #3616
This is intended for use by any embedder who wishes to access module exports from native code e.g. to use one as an entry point - I note that node's implementation of ESModules with v8 uses an equivalent v8 facility and so this is likely one of the required steps towards implementing ESModules in node-chakracore.
For testing purposes only a WScript method has been added to ch that wraps this method to allow fetching a namespace object from within Javascript - this has then been used to create a test case.
cc @liminzhu @boingoing