Implement JsGetModuleNamespace API fixes #3616#4707
Implement JsGetModuleNamespace API fixes #3616#4707chakrabot merged 1 commit intochakra-core:masterfrom
Conversation
e2a68c3 to
fd54a47
Compare
jackhorton
left a comment
There was a problem hiding this comment.
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.
boingoing
left a comment
There was a problem hiding this comment.
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.
| /// <summary> | ||
| /// Module was not yet evaluated when JsGetModuleNamespace was called. | ||
| /// </summary> | ||
| JsErrorModuleNotEvaluated, |
There was a problem hiding this comment.
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.
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.
Correct. Adding it at the end will solve the problem
There was a problem hiding this comment.
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.
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.
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.
| /*allowInObjectBeforeCollectCallback*/true); | ||
| } | ||
|
|
||
| CHAKRA_API JsGetModuleNamespace(_In_ JsModuleRecord requestModule, _Outptr_result_maybenull_ JsValueRef *moduleNamespace) |
There was a problem hiding this comment.
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.
It was already inside #ifdef _CHAKRACOREBUILD but now moved to JsrtCore.cpp instead.
There was a problem hiding this comment.
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.
| return JsErrorInvalidArgument; | ||
| } | ||
| Js::SourceTextModuleRecord* moduleRecord = Js::SourceTextModuleRecord::FromHost(requestModule); | ||
| if(!moduleRecord->WasEvaluated()) |
There was a problem hiding this comment.
Nitpick: space between if and (
| { | ||
| return JsErrorModuleNotEvaluated; | ||
| } | ||
| *moduleNamespace = (JsValueRef) moduleRecord->GetNamespace(); |
There was a problem hiding this comment.
Before dereferencing moduleNamespace make sure it's not null. PARAM_NOT_NULL(moduleNamespace);
There was a problem hiding this comment.
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.
| JsValueRef errorObject; | ||
| JsValueRef errorMessageString; | ||
|
|
||
| if (wcscmp(errorMessage, _u("")) == 0) { |
There was a problem hiding this comment.
Nitpick: { character at end of this line should be on new line below.
| assert.areEqual(mod0Namespace.export5, "exporting"); | ||
| }); | ||
|
|
||
| let test2 = import("mod1.js").then(()=>{ |
There was a problem hiding this comment.
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);
}| }); | ||
|
|
||
| assert.throws(()=>WScript.GetModuleNamespace("mod0.js")); | ||
| assert.throws(()=>WScript.GetModuleNamespace("mod3.js")); |
There was a problem hiding this comment.
Add the error case where GetModuleNamespace is called with no arguments.
| assert.areEqual(mod1Namespace.export4.constructor.name, "AsyncFunction"); | ||
| }); | ||
|
|
||
| assert.throws(()=>WScript.GetModuleNamespace("mod0.js")); |
There was a problem hiding this comment.
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. |
| { | ||
| return JsErrorModuleNotEvaluated; | ||
| } | ||
| *moduleNamespace = (JsValueRef) moduleRecord->GetNamespace(); |
There was a problem hiding this comment.
(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.
boingoing
left a comment
There was a problem hiding this comment.
LGTM, thanks for addressing my feedback.
|
LGTM thanks @rhuanjl ! |
304133a to
8d58dc2
Compare
| { | ||
| return JsErrorModuleNotEvaluated; | ||
| } | ||
| *moduleNamespace = static_cast <JsValueRef>(moduleRecord->GetNamespace()); |
There was a problem hiding this comment.
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