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

Implement JsGetModuleNamespace API fixes #3616 #4707

Merged
merged 1 commit into from
Feb 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/ChakraCore/ChakraCore.def
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ JsParseModuleSource
JsModuleEvaluation
JsSetModuleHostInfo
JsGetModuleHostInfo
JsGetModuleNamespace
JsInitializeJITServer

JsCreateSharedArrayBufferWithSharedContent
Expand Down
1 change: 1 addition & 0 deletions bin/ch/ChakraRtInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ bool ChakraRTInterface::LoadChakraDll(ArgInfo* argInfo, HINSTANCE *outLibrary)
m_jsApiHooks.pfJsrtSetModuleHostInfo = (JsAPIHooks::JsSetModuleHostInfoPtr)GetChakraCoreSymbol(library, "JsSetModuleHostInfo");
m_jsApiHooks.pfJsrtGetModuleHostInfo = (JsAPIHooks::JsGetModuleHostInfoPtr)GetChakraCoreSymbol(library, "JsGetModuleHostInfo");
m_jsApiHooks.pfJsrtModuleEvaluation = (JsAPIHooks::JsModuleEvaluationPtr)GetChakraCoreSymbol(library, "JsModuleEvaluation");
m_jsApiHooks.pfJsrtGetModuleNamespace = (JsAPIHooks::JsGetModuleNamespacePtr)GetChakraCoreSymbol(library, "JsGetModuleNamespace");
m_jsApiHooks.pfJsrtDiagStartDebugging = (JsAPIHooks::JsrtDiagStartDebugging)GetChakraCoreSymbol(library, "JsDiagStartDebugging");
m_jsApiHooks.pfJsrtDiagStopDebugging = (JsAPIHooks::JsrtDiagStopDebugging)GetChakraCoreSymbol(library, "JsDiagStopDebugging");
m_jsApiHooks.pfJsrtDiagGetSource = (JsAPIHooks::JsrtDiagGetSource)GetChakraCoreSymbol(library, "JsDiagGetSource");
Expand Down
3 changes: 3 additions & 0 deletions bin/ch/ChakraRtInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct JsAPIHooks
typedef JsErrorCode (WINAPI *JsInitializeModuleRecordPtr)(JsModuleRecord referencingModule, JsValueRef normalizedSpecifier, JsModuleRecord* moduleRecord);
typedef JsErrorCode (WINAPI *JsParseModuleSourcePtr)(JsModuleRecord requestModule, JsSourceContext sourceContext, byte* sourceText, unsigned int sourceLength, JsParseModuleSourceFlags sourceFlag, JsValueRef* exceptionValueRef);
typedef JsErrorCode (WINAPI *JsModuleEvaluationPtr)(JsModuleRecord requestModule, JsValueRef* result);
typedef JsErrorCode (WINAPI *JsGetModuleNamespacePtr)(JsModuleRecord requestModule, JsValueRef *moduleNamespace);
typedef JsErrorCode (WINAPI *JsSetModuleHostInfoPtr)(JsModuleRecord requestModule, JsModuleHostInfoKind moduleHostInfo, void* hostInfo);
typedef JsErrorCode (WINAPI *JsGetModuleHostInfoPtr)(JsModuleRecord requestModule, JsModuleHostInfoKind moduleHostInfo, void** hostInfo);
typedef JsErrorCode (WINAPI *JsrtCallFunctionPtr)(JsValueRef function, JsValueRef* arguments, unsigned short argumentCount, JsValueRef *result);
Expand Down Expand Up @@ -129,6 +130,7 @@ struct JsAPIHooks
JsParseModuleSourcePtr pfJsrtParseModuleSource;
JsInitializeModuleRecordPtr pfJsrtInitializeModuleRecord;
JsModuleEvaluationPtr pfJsrtModuleEvaluation;
JsGetModuleNamespacePtr pfJsrtGetModuleNamespace;
JsSetModuleHostInfoPtr pfJsrtSetModuleHostInfo;
JsGetModuleHostInfoPtr pfJsrtGetModuleHostInfo;
JsrtCallFunctionPtr pfJsrtCallFunction;
Expand Down Expand Up @@ -381,6 +383,7 @@ class ChakraRTInterface
return HOOK_JS_API(ParseModuleSource(requestModule, sourceContext, sourceText, sourceLength, sourceFlag, exceptionValueRef));
}
static JsErrorCode WINAPI JsModuleEvaluation(JsModuleRecord requestModule, JsValueRef* result) { return HOOK_JS_API(ModuleEvaluation(requestModule, result)); }
static JsErrorCode WINAPI JsGetModuleNamespace(JsModuleRecord requestModule, JsValueRef *moduleNamespace) { return HOOK_JS_API(GetModuleNamespace(requestModule, moduleNamespace)); }
static JsErrorCode WINAPI JsInitializeModuleRecord(JsModuleRecord referencingModule, JsValueRef normalizedSpecifier, JsModuleRecord* moduleRecord) {
return HOOK_JS_API(InitializeModuleRecord(referencingModule, normalizedSpecifier, moduleRecord));
}
Expand Down
62 changes: 62 additions & 0 deletions bin/ch/WScriptJsrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,67 @@ JsValueRef WScriptJsrt::LoadScriptFileHelper(JsValueRef callee, JsValueRef *argu
return returnValue;
}

JsValueRef __stdcall WScriptJsrt::GetModuleNamespace(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
{
JsErrorCode errorCode = JsNoError;
JsValueRef returnValue = JS_INVALID_REFERENCE;
LPCWSTR errorMessage = _u("");
char fullPath[_MAX_PATH];

if (argumentCount < 2)
{
errorCode = JsErrorInvalidArgument;
errorMessage = _u("Need an argument for WScript.GetModuleNamespace");
}
else
{
AutoString specifierStr(arguments[1]);
errorCode = specifierStr.GetError();

if (errorCode == JsNoError)
{
if (_fullpath(fullPath, specifierStr.GetString(), _MAX_PATH) == nullptr)
{
errorCode = JsErrorInvalidArgument;
}
else
{
auto moduleEntry = moduleRecordMap.find(fullPath);
if (moduleEntry == moduleRecordMap.end())
{
errorCode = JsErrorInvalidArgument;
errorMessage = _u("Need to supply a path for an already loaded module for WScript.GetModuleNamespace");
}
else
{
errorCode = ChakraRTInterface::JsGetModuleNamespace(moduleEntry->second, &returnValue);
if (errorCode == JsErrorModuleNotEvaluated)
{
errorMessage = _u("GetModuleNamespace called with un-evaluated module");
}
}
}
}
}

if (errorCode != JsNoError)
{
JsValueRef errorObject;
JsValueRef errorMessageString;

if (wcscmp(errorMessage, _u("")) == 0)
{
errorMessage = ConvertErrorCodeToMessage(errorCode);
}

ERROR_MESSAGE_TO_STRING(errCode, errorMessage, errorMessageString);

ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
ChakraRTInterface::JsSetException(errorObject);
}
return returnValue;
}

JsValueRef __stdcall WScriptJsrt::LoadScriptCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
{
return LoadScriptHelper(callee, isConstructCall, arguments, argumentCount, callbackState, false);
Expand Down Expand Up @@ -859,6 +920,7 @@ bool WScriptJsrt::Initialize()
IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadTextFile", LoadTextFileCallback));
IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Flag", FlagCallback));
IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "RegisterModuleSource", RegisterModuleSourceCallback));
IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "GetModuleNamespace", GetModuleNamespace));

// ToDo Remove
IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Edit", EmptyCallback));
Expand Down
1 change: 1 addition & 0 deletions bin/ch/WScriptJsrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class WScriptJsrt
static JsValueRef CALLBACK LoadScriptFileCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState);
static JsValueRef CALLBACK LoadScriptCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState);
static JsValueRef CALLBACK LoadModuleCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState);
static JsValueRef CALLBACK GetModuleNamespace(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState);
static JsValueRef CALLBACK SetTimeoutCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState);
static JsValueRef CALLBACK ClearTimeoutCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState);
static JsValueRef CALLBACK AttachCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState);
Expand Down
4 changes: 4 additions & 0 deletions lib/Jsrt/ChakraCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ typedef unsigned short uint16_t;
/// </summary>
JsNoWeakRefRequired,
/// <summary>
/// Module was not yet evaluated when JsGetModuleNamespace was called.
/// </summary>
JsErrorModuleNotEvaluated,
/// <summary>
/// Category of errors that relates to errors occurring within the engine itself.
/// </summary>
JsErrorCategoryEngine = 0x20000,
Expand Down
16 changes: 16 additions & 0 deletions lib/Jsrt/ChakraCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -1036,5 +1036,21 @@ CHAKRA_API
JsSetHostPromiseRejectionTracker(
_In_ JsHostPromiseRejectionTrackerCallback promiseRejectionTrackerCallback,
_In_opt_ void *callbackState);

/// <summary>
/// Provides the namespace object for a module.
/// </summary>
/// <remarks>
/// Requires an active script context and that the module has already been evaluated.
/// </remarks>
/// <param name="requestModule">The JsModuleRecord for which the namespace is being requested.</param>
/// <param name="moduleNamespace">A JsValueRef - the requested namespace object.</param>
/// <returns>
/// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.
/// </returns>
CHAKRA_API
JsGetModuleNamespace(
_In_ JsModuleRecord requestModule,
_Outptr_result_maybenull_ JsValueRef *moduleNamespace);
#endif // _CHAKRACOREBUILD
#endif // _CHAKRACORE_H_
17 changes: 17 additions & 0 deletions lib/Jsrt/Core/JsrtCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,20 @@ JsGetModuleHostInfo(
});
return errorCode;
}

CHAKRA_API JsGetModuleNamespace(_In_ JsModuleRecord requestModule, _Outptr_result_maybenull_ JsValueRef *moduleNamespace)
{
PARAM_NOT_NULL(moduleNamespace);
*moduleNamespace = nullptr;
if (!Js::SourceTextModuleRecord::Is(requestModule))
{
return JsErrorInvalidArgument;
}
Js::SourceTextModuleRecord* moduleRecord = Js::SourceTextModuleRecord::FromHost(requestModule);
if (!moduleRecord->WasEvaluated())
{
return JsErrorModuleNotEvaluated;
}
*moduleNamespace = static_cast<JsValueRef>(moduleRecord->GetNamespace());
return JsNoError;
}
8 changes: 4 additions & 4 deletions lib/Jsrt/Jsrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5336,10 +5336,10 @@ CHAKRA_API JsGetDataViewInfo(

CHAKRA_API JsSetHostPromiseRejectionTracker(_In_ JsHostPromiseRejectionTrackerCallback promiseRejectionTrackerCallback, _In_opt_ void *callbackState)
{
return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
scriptContext->GetLibrary()->SetNativeHostPromiseRejectionTrackerCallback((Js::JavascriptLibrary::HostPromiseRejectionTrackerCallback) promiseRejectionTrackerCallback, callbackState);
return JsNoError;
},
return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
scriptContext->GetLibrary()->SetNativeHostPromiseRejectionTrackerCallback((Js::JavascriptLibrary::HostPromiseRejectionTrackerCallback) promiseRejectionTrackerCallback, callbackState);
return JsNoError;
},
/*allowInObjectBeforeCollectCallback*/true);
}

Expand Down
82 changes: 82 additions & 0 deletions test/es6module/GetModuleNamespace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");

WScript.RegisterModuleSource("mod0.js", `
export const export1 = 5;
export default function export2 ()
{
return true;
}
export class export3
{

}
export async function export4 ()
{
return await null;
}
export let export5 = "exporting";
const notExported1 = "foo";
let notExported2 = "bar";
var notExported3 = 5;
`);

WScript.RegisterModuleSource("mod1.js",`
export let export1 = 10;
export default function export2 ()
{
return false;
}
export class export3
{

}
export async function export4 ()
{
return await null;
}
export const export5 = "exported";
export {export6} from "mod2.js";
`);

WScript.RegisterModuleSource("mod2.js",`
export function export6 ()
{
return true;
}
`);

let test1 = import("mod0.js").then(namespaceFromImport => {
let mod0Namespace = WScript.GetModuleNamespace("mod0.js");
assert.areEqual(mod0Namespace.export1, 5, "mod0: export1 should equal 5");
assert.isTrue(mod0Namespace.default(), "mod0: export2 should return true");
assert.areEqual(typeof mod0Namespace.export3.constructor, "function", "mod0: export3 should have constructor function");
assert.areEqual(mod0Namespace.export4.constructor.name, "AsyncFunction", "mod0: export4 should be an async function");
assert.areEqual(mod0Namespace.export5, "exporting", "mod0: export5 should be a string, exporting");
assert.isUndefined(mod0Namespace.notExported1, "Not exported module const should not be property of namespace");
assert.isUndefined(mod0Namespace.notExported2, "Not exported module let should not be property of namespace");
assert.isUndefined(mod0Namespace.notExported3, "Not exported module var should not be property of namespace");
assert.areEqual(namespaceFromImport, mod0Namespace, "ModuleNamespace object should match resolved value of import");
});

let test2 = import("mod1.js").then(namespaceFromImport => {
let mod1Namespace = WScript.GetModuleNamespace("mod1.js");
assert.areEqual(mod1Namespace.export1, 10);
assert.isFalse(mod1Namespace.default());
assert.isUndefined(mod1Namespace.export2, "mod1: Name of default export should be default.")
assert.areEqual(typeof mod1Namespace.export3.constructor, "function");
assert.areEqual(mod1Namespace.export4.constructor.name, "AsyncFunction");
assert.areEqual(mod1Namespace.export5, "exported");
assert.areEqual(mod1Namespace.export6(), true);
assert.areEqual(namespaceFromImport, mod1Namespace,"ModuleNamespace object should match resolved value of import");
});

assert.throws(()=>WScript.GetModuleNamespace("mod0.js"), Error, "Expected error for un-evaluated module", "GetModuleNamespace called with un-evaluated module");
assert.throws(()=>WScript.GetModuleNamespace("mod3.js", Error, "Expected error for un-loaded module", "Need to supply a path for an already loaded module for WScript.GetModuleNamespace"));
assert.throws(()=>WScript.GetModuleNamespace(), Error, "Expected error for no-argument", "Need an argument for WScript.GetModuleNamespace");

Promise.all([test1,test2]).then(()=>print("pass")).catch((e)=>print("fail: " + e));
7 changes: 7 additions & 0 deletions test/es6module/rlexe.xml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@
<tags>BugFix,exclude_sanitize_address</tags>
</default>
</test>
<test>
<default>
<files>GetModuleNamespace.js</files>
<compile-flags>-ESDynamicImport</compile-flags>
<tags>exclude_jshost,exclude_sanitize_address</tags>
</default>
</test>
<test>
<default>
<files>module-load-twice.js</files>
Expand Down