Skip to content

Commit b52af78

Browse files
committed
Implement import.meta
The import.meta proposal has reached stage 3. See details: https://github.com/tc39/proposal-import-meta This special name is a meta-property which binds to an object in module code. The import.meta object is unique per-module. Each module's import.meta object is filled-out with properties provided by the host. The object itself is lazily-created and an empty object with a null prototype by default. When loading import.meta for a module, we ask the host to provide a set of properties for the object and allow the host to do other setup of the import.meta object it might need to do. There are two host API provided for in the proposal: HostGetImportMetaProperties and HostFinalizeImportMeta. I've plumbed these callbacks in so hosts can implement them.
1 parent 2751a86 commit b52af78

31 files changed

+481
-30
lines changed

bin/NativeTests/JsRTApiTest.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2201,6 +2201,16 @@ namespace JsRTApiTest
22012201
return JsNoError;
22022202
}
22032203

2204+
static JsErrorCode CALLBACK Succes_HFIMC(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef importMetaVar)
2205+
{
2206+
return JsNoError;
2207+
}
2208+
2209+
static JsErrorCode CALLBACK Succes_HGIMPC(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef importMetaVar)
2210+
{
2211+
return JsNoError;
2212+
}
2213+
22042214
void ModuleSuccessTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
22052215
{
22062216
JsModuleRecord requestModule = JS_INVALID_REFERENCE;
@@ -2212,6 +2222,8 @@ namespace JsRTApiTest
22122222
REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleCallback, Success_FIMC) == JsNoError);
22132223
REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleFromScriptCallback, Success_FIMC) == JsNoError);
22142224
REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_NotifyModuleReadyCallback, Succes_NMRC) == JsNoError);
2225+
REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_HostFinalizeImportMetaCallback, Succes_HFIMC) == JsNoError);
2226+
REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_HostGetImportMetaPropertiesCallback, Succes_HGIMPC) == JsNoError);
22152227

22162228
JsValueRef errorObject = JS_INVALID_REFERENCE;
22172229
const char* fileContent = "import {x} from 'foo.js'";

bin/ch/WScriptJsrt.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,9 +612,19 @@ JsErrorCode WScriptJsrt::InitializeModuleInfo(JsValueRef specifier, JsModuleReco
612612
{
613613
errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_NotifyModuleReadyCallback, (void*)WScriptJsrt::NotifyModuleReadyCallback);
614614

615-
if (errorCode == JsNoError && moduleRecord != nullptr)
615+
if (errorCode == JsNoError)
616616
{
617-
errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_HostDefined, specifier);
617+
errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_HostFinalizeImportMetaCallback, (void*)WScriptJsrt::HostFinalizeImportMetaCallback);
618+
619+
if (errorCode == JsNoError)
620+
{
621+
errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_HostGetImportMetaPropertiesCallback, (void*)WScriptJsrt::HostGetImportMetaPropertiesCallback);
622+
623+
if (errorCode == JsNoError && moduleRecord != nullptr)
624+
{
625+
errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_HostDefined, specifier);
626+
}
627+
}
618628
}
619629
}
620630
}
@@ -2159,6 +2169,28 @@ JsErrorCode WScriptJsrt::NotifyModuleReadyCallback(_In_opt_ JsModuleRecord refer
21592169
return JsNoError;
21602170
}
21612171

2172+
JsErrorCode __stdcall WScriptJsrt::HostFinalizeImportMetaCallback(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef importMetaVar)
2173+
{
2174+
return JsNoError;
2175+
}
2176+
2177+
JsErrorCode __stdcall WScriptJsrt::HostGetImportMetaPropertiesCallback(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef importMetaVar)
2178+
{
2179+
if (importMetaVar != nullptr)
2180+
{
2181+
JsValueRef specifier = JS_INVALID_REFERENCE;
2182+
ChakraRTInterface::JsGetModuleHostInfo(referencingModule, JsModuleHostInfo_HostDefined, &specifier);
2183+
2184+
JsPropertyIdRef urlPropId;
2185+
if (JsNoError == CreatePropertyIdFromString("url", &urlPropId))
2186+
{
2187+
ChakraRTInterface::JsSetProperty(importMetaVar, urlPropId, specifier, false);
2188+
}
2189+
}
2190+
2191+
return JsNoError;
2192+
}
2193+
21622194
void WScriptJsrt::PromiseContinuationCallback(JsValueRef task, void *callbackState)
21632195
{
21642196
Assert(task != JS_INVALID_REFERENCE);

bin/ch/WScriptJsrt.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class WScriptJsrt
6565
static JsErrorCode FetchImportedModule(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord);
6666
static JsErrorCode FetchImportedModuleFromScript(_In_ DWORD_PTR dwReferencingSourceContext, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord);
6767
static JsErrorCode NotifyModuleReadyCallback(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar);
68+
static JsErrorCode CALLBACK HostFinalizeImportMetaCallback(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef importMetaVar);
69+
static JsErrorCode CALLBACK HostGetImportMetaPropertiesCallback(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef importMetaVar);
6870
static JsErrorCode InitializeModuleCallbacks();
6971
static void CALLBACK PromiseContinuationCallback(JsValueRef task, void *callbackState);
7072
static void CALLBACK PromiseRejectionTrackerCallback(JsValueRef promise, JsValueRef reason, bool handled, void *callbackState);

lib/Backend/JnHelperMethodList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ HELPERCALLCHK(LdHomeObjProto, Js::JavascriptOperators::OP_LdHomeObjPro
532532
HELPERCALLCHK(LdFuncObjProto, Js::JavascriptOperators::OP_LdFuncObjProto, AttrCanNotBeReentrant)
533533

534534
HELPERCALLCHK(ImportCall, Js::JavascriptOperators::OP_ImportCall, 0)
535+
HELPERCALLCHK(LdImportMeta, Js::JavascriptOperators::OP_LdImportMeta, 0)
535536
HELPERCALLCHK(NewAsyncFromSyncIterator, Js::JavascriptOperators::OP_NewAsyncFromSyncIterator, AttrCanNotBeReentrant)
536537

537538
HELPERCALLCHK(AsyncYieldIsReturn, Js::JavascriptOperators::OP_AsyncYieldIsReturn, AttrCanNotBeReentrant)

lib/Backend/Lower.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,6 +2531,16 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
25312531
this->GenerateCheckForCallFlagNew(instr);
25322532
break;
25332533

2534+
case Js::OpCode::LdImportMeta:
2535+
{
2536+
IR::Opnd *src1Opnd = instr->UnlinkSrc1();
2537+
2538+
LoadScriptContext(instr);
2539+
m_lowererMD.LoadHelperArgument(instr, src1Opnd);
2540+
m_lowererMD.ChangeToHelperCall(instr, IR::HelperLdImportMeta);
2541+
break;
2542+
}
2543+
25342544
case Js::OpCode::StFuncExpr:
25352545
// object.propid = src
25362546
LowerStFld(instr, IR::HelperOp_StFunctionExpression, IR::HelperOp_StFunctionExpression, false);

lib/Common/ConfigFlagsList.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ PHASE(All)
702702
#define DEFAULT_CONFIG_ES7ValuesEntries (true)
703703
#define DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors (true)
704704
#define DEFAULT_CONFIG_ESDynamicImport (false)
705+
#define DEFAULT_CONFIG_ESImportMeta (true)
705706
#define DEFAULT_CONFIG_ESExportNsAs (true)
706707
#define DEFAULT_CONFIG_ES2018AsyncIteration (false)
707708

@@ -1228,6 +1229,9 @@ FLAGR(Boolean, ESHashbang, "Enable Hashbang syntax", DEFAULT_CONFIG_ESHashbang)
12281229
// ES Symbol.prototype.description flag
12291230
FLAGR(Boolean, ESSymbolDescription, "Enable Symbol.prototype.description", DEFAULT_CONFIG_ESSymbolDescription)
12301231

1232+
// ES import.meta keyword meta-property
1233+
FLAGR(Boolean, ESImportMeta, "Enable import.meta keyword", DEFAULT_CONFIG_ESImportMeta)
1234+
12311235
//ES globalThis flag
12321236
FLAGR(Boolean, ESGlobalThis, "Enable globalThis", DEFAULT_CONFIG_ESGlobalThis)
12331237

lib/Jsrt/ChakraCore.h

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,15 @@ typedef enum JsModuleHostInfoKind
111111
/// <summary>
112112
/// URL for use in error stack traces and debugging.
113113
/// </summary>
114-
JsModuleHostInfo_Url = 0x6
114+
JsModuleHostInfo_Url = 0x6,
115+
/// <summary>
116+
/// Callback for getting the import.meta object properties.
117+
/// </summary>
118+
JsModuleHostInfo_HostGetImportMetaPropertiesCallback = 0x7,
119+
/// <summary>
120+
/// Callback for finalizing the import.meta object.
121+
/// </summary>
122+
JsModuleHostInfo_HostFinalizeImportMetaCallback = 0x8
115123
} JsModuleHostInfoKind;
116124

117125
/// <summary>
@@ -187,6 +195,38 @@ typedef JsErrorCode(CHAKRA_CALLBACK * FetchImportedModuleFromScriptCallBack)(_In
187195
/// </returns>
188196
typedef JsErrorCode(CHAKRA_CALLBACK * NotifyModuleReadyCallback)(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar);
189197

198+
/// <summary>
199+
/// User implemented callback to allow for host to finalize import.meta object.
200+
/// </summary>
201+
/// <remarks>
202+
/// This callback is an "escape hatch" for hosts which need to do some extraordinary operations on the import.meta
203+
/// object to prepare it for script.
204+
/// The callback is invoked on the current runtime execution thread, therefore execution is blocked until the
205+
/// callback completes.
206+
/// </remarks>
207+
/// <param name="referencingModule">The referencing module that is loading an import.meta object.</param>
208+
/// <param name="importMetaVar">The object which will be returned to script for the referencing module.</param>
209+
/// <returns>
210+
/// Returns a JsErrorCode - note, the return value is ignored.
211+
/// </returns>
212+
typedef JsErrorCode(CHAKRA_CALLBACK * HostFinalizeImportMetaCallback)(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef importMetaVar);
213+
214+
/// <summary>
215+
/// User implemented callback to fill in module properties for the import.meta object.
216+
/// </summary>
217+
/// <remarks>
218+
/// This callback allows the host to fill module details for the referencing module in the import.meta object
219+
/// loaded by script.
220+
/// The callback is invoked on the current runtime execution thread, therefore execution is blocked until the
221+
/// callback completes.
222+
/// </remarks>
223+
/// <param name="referencingModule">The referencing module that is loading an import.meta object.</param>
224+
/// <param name="importMetaVar">The object which will be returned to script for the referencing module.</param>
225+
/// <returns>
226+
/// Returns a JsErrorCode - note, the return value is ignored.
227+
/// </returns>
228+
typedef JsErrorCode(CHAKRA_CALLBACK * HostGetImportMetaPropertiesCallback)(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef importMetaVar);
229+
190230
/// <summary>
191231
/// A structure containing information about a native function callback.
192232
/// </summary>

lib/Jsrt/Core/JsrtContextCore.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,40 @@ HRESULT ChakraCoreHostScriptContext::NotifyHostAboutModuleReady(Js::ModuleRecord
159159
return E_INVALIDARG;
160160
}
161161

162+
HRESULT ChakraCoreHostScriptContext::HostGetImportMetaProperties(Js::ModuleRecordBase* referencingModule, Js::Var importMetaObject)
163+
{
164+
if (hostGetImportMetaPropertiesCallback == nullptr)
165+
{
166+
return E_INVALIDARG;
167+
}
168+
{
169+
AUTO_NO_EXCEPTION_REGION;
170+
JsErrorCode errorCode = hostGetImportMetaPropertiesCallback(referencingModule, importMetaObject);
171+
if (errorCode == JsNoError)
172+
{
173+
return NOERROR;
174+
}
175+
}
176+
return E_INVALIDARG;
177+
}
178+
179+
HRESULT ChakraCoreHostScriptContext::HostFinalizeImportMeta(Js::ModuleRecordBase* referencingModule, Js::Var importMetaObject)
180+
{
181+
if (hostFinalizeImportMetaCallback == nullptr)
182+
{
183+
return E_INVALIDARG;
184+
}
185+
{
186+
AUTO_NO_EXCEPTION_REGION;
187+
JsErrorCode errorCode = hostFinalizeImportMetaCallback(referencingModule, importMetaObject);
188+
if (errorCode == JsNoError)
189+
{
190+
return NOERROR;
191+
}
192+
}
193+
return E_INVALIDARG;
194+
}
195+
162196
ChakraCoreStreamWriter::~ChakraCoreStreamWriter()
163197
{
164198
HeapDelete(m_serializerCore);

lib/Jsrt/Core/JsrtContextCore.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,11 @@ class ChakraCoreHostScriptContext sealed : public HostScriptContext
101101
public:
102102
ChakraCoreHostScriptContext(Js::ScriptContext* scriptContext)
103103
: HostScriptContext(scriptContext),
104+
fetchImportedModuleCallback(nullptr),
105+
fetchImportedModuleFromScriptCallback(nullptr),
104106
notifyModuleReadyCallback(nullptr),
105-
fetchImportedModuleCallback(nullptr)
107+
hostFinalizeImportMetaCallback(nullptr),
108+
hostGetImportMetaPropertiesCallback(nullptr)
106109
{
107110
}
108111
~ChakraCoreHostScriptContext()
@@ -250,6 +253,9 @@ class ChakraCoreHostScriptContext sealed : public HostScriptContext
250253

251254
HRESULT NotifyHostAboutModuleReady(Js::ModuleRecordBase* referencingModule, Js::Var exceptionVar) override;
252255

256+
HRESULT HostGetImportMetaProperties(Js::ModuleRecordBase* referencingModule, Js::Var importMetaObject) override;
257+
HRESULT HostFinalizeImportMeta(Js::ModuleRecordBase* referencingModule, Js::Var importMetaObject) override;
258+
253259
void SetNotifyModuleReadyCallback(NotifyModuleReadyCallback notifyCallback) { this->notifyModuleReadyCallback = notifyCallback; }
254260
NotifyModuleReadyCallback GetNotifyModuleReadyCallback() const { return this->notifyModuleReadyCallback; }
255261

@@ -259,6 +265,12 @@ class ChakraCoreHostScriptContext sealed : public HostScriptContext
259265
void SetFetchImportedModuleFromScriptCallback(FetchImportedModuleFromScriptCallBack fetchCallback) { this->fetchImportedModuleFromScriptCallback = fetchCallback; }
260266
FetchImportedModuleFromScriptCallBack GetFetchImportedModuleFromScriptCallback() const { return this->fetchImportedModuleFromScriptCallback; }
261267

268+
void SetHostFinalizeImportMetaCallback(HostFinalizeImportMetaCallback finalizeCallback) { this->hostFinalizeImportMetaCallback = finalizeCallback; }
269+
HostFinalizeImportMetaCallback GetHostFinalizeImportMetaCallback() const { return this->hostFinalizeImportMetaCallback; }
270+
271+
void SetHostGetImportMetaPropertiesCallback(HostGetImportMetaPropertiesCallback getCallback) { this->hostGetImportMetaPropertiesCallback = getCallback; }
272+
HostGetImportMetaPropertiesCallback GetHostGetImportMetaPropertiesCallback() const { return this->hostGetImportMetaPropertiesCallback; }
273+
262274
#if DBG_DUMP || defined(PROFILE_EXEC) || defined(PROFILE_MEM)
263275
void EnsureParentInfo(Js::ScriptContext* scriptContext = NULL) override
264276
{
@@ -273,7 +285,6 @@ class ChakraCoreHostScriptContext sealed : public HostScriptContext
273285
FetchImportedModuleCallBack fetchImportedModuleCallback;
274286
FetchImportedModuleFromScriptCallBack fetchImportedModuleFromScriptCallback;
275287
NotifyModuleReadyCallback notifyModuleReadyCallback;
288+
HostFinalizeImportMetaCallback hostFinalizeImportMetaCallback;
289+
HostGetImportMetaPropertiesCallback hostGetImportMetaPropertiesCallback;
276290
};
277-
278-
279-

lib/Jsrt/Core/JsrtCore.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@ JsSetModuleHostInfo(
158158
{
159159
if (moduleHostInfo != JsModuleHostInfo_FetchImportedModuleCallback &&
160160
moduleHostInfo != JsModuleHostInfo_FetchImportedModuleFromScriptCallback &&
161-
moduleHostInfo != JsModuleHostInfo_NotifyModuleReadyCallback)
161+
moduleHostInfo != JsModuleHostInfo_NotifyModuleReadyCallback &&
162+
moduleHostInfo != JsModuleHostInfo_HostFinalizeImportMetaCallback &&
163+
moduleHostInfo != JsModuleHostInfo_HostGetImportMetaPropertiesCallback)
162164
{
163165
return JsErrorInvalidArgument;
164166
}
@@ -191,6 +193,12 @@ JsSetModuleHostInfo(
191193
case JsModuleHostInfo_NotifyModuleReadyCallback:
192194
currentContext->GetHostScriptContext()->SetNotifyModuleReadyCallback(reinterpret_cast<NotifyModuleReadyCallback>(hostInfo));
193195
break;
196+
case JsModuleHostInfo_HostFinalizeImportMetaCallback:
197+
currentContext->GetHostScriptContext()->SetHostFinalizeImportMetaCallback(reinterpret_cast<HostFinalizeImportMetaCallback>(hostInfo));
198+
break;
199+
case JsModuleHostInfo_HostGetImportMetaPropertiesCallback:
200+
currentContext->GetHostScriptContext()->SetHostGetImportMetaPropertiesCallback(reinterpret_cast<HostGetImportMetaPropertiesCallback>(hostInfo));
201+
break;
194202
case JsModuleHostInfo_Url:
195203
moduleRecord->SetModuleUrl(hostInfo);
196204
break;
@@ -238,6 +246,12 @@ JsGetModuleHostInfo(
238246
case JsModuleHostInfo_NotifyModuleReadyCallback:
239247
*hostInfo = reinterpret_cast<void*>(currentContext->GetHostScriptContext()->GetNotifyModuleReadyCallback());
240248
break;
249+
case JsModuleHostInfo_HostFinalizeImportMetaCallback:
250+
*hostInfo = reinterpret_cast<void*>(currentContext->GetHostScriptContext()->GetHostFinalizeImportMetaCallback());
251+
break;
252+
case JsModuleHostInfo_HostGetImportMetaPropertiesCallback:
253+
*hostInfo = reinterpret_cast<void*>(currentContext->GetHostScriptContext()->GetHostGetImportMetaPropertiesCallback());
254+
break;
241255
case JsModuleHostInfo_Url:
242256
*hostInfo = reinterpret_cast<void*>(moduleRecord->GetModuleUrl());
243257
break;

0 commit comments

Comments
 (0)