Skip to content

Commit

Permalink
Bug 1775424 - Part 2: Impl import.meta.resolve in js shell. r=jonco
Browse files Browse the repository at this point in the history
  • Loading branch information
allstarschh committed Aug 29, 2022
1 parent a9970aa commit acd03a2
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 8 deletions.
21 changes: 15 additions & 6 deletions js/src/jit-test/tests/modules/import-meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ assertEq(get(), import.meta);
assertEq("url" in import.meta, true);
assertEq(import.meta.url.endsWith("import-meta.js"), true);

assertEq("resolve" in import.meta, true);

assertEq(import.meta.resolve("./x"),
import.meta.url.replace("import-meta.js", "x"));

import getOtherMetaObject from "exportImportMeta.js";

let otherImportMeta = getOtherMetaObject();
Expand All @@ -30,11 +35,13 @@ assertEq(otherImportMeta.url.endsWith("exportImportMeta.js"), true);

assertEq(Object.isExtensible(import.meta), true);

var desc = Object.getOwnPropertyDescriptor(import.meta, "url");
assertEq(desc.writable, true);
assertEq(desc.enumerable, true);
assertEq(desc.configurable, true);
assertEq(desc.value, import.meta.url);
for (const name of Reflect.ownKeys(import.meta)) {
const desc = Object.getOwnPropertyDescriptor(import.meta, name);
assertEq(desc.writable, true);
assertEq(desc.enumerable, true);
assertEq(desc.configurable, true);
assertEq(desc.value, import.meta[name]);
}

// The import.meta object's prototype is null.
assertEq(Object.getPrototypeOf(import.meta), null);
Expand All @@ -47,12 +54,14 @@ assertEq(import.meta.newProp, 42);

let found = new Set(Reflect.ownKeys(import.meta));

assertEq(found.size, 2);
assertEq(found.size, 3);
assertEq(found.has("url"), true);
assertEq(found.has("newProp"), true);
assertEq(found.has("resolve"), true);

delete import.meta.url;
delete import.meta.newProp;
delete import.meta.resolve;

found = new Set(Reflect.ownKeys(import.meta));
assertEq(found.size, 0);
75 changes: 73 additions & 2 deletions js/src/shell/ModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "NamespaceImports.h"

#include "builtin/TestingUtility.h" // js::CreateScriptPrivate
#include "js/Conversions.h"
#include "js/MapAndSet.h"
#include "js/Modules.h"
#include "js/PropertyAndElement.h" // JS_DefineProperty, JS_GetProperty
Expand Down Expand Up @@ -84,6 +85,34 @@ bool ModuleLoader::GetImportMetaProperties(JSContext* cx,
return scx->moduleLoader->populateImportMeta(cx, privateValue, metaObject);
}

bool ModuleLoader::ImportMetaResolve(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue modulePrivate(
cx, js::GetFunctionNativeReserved(&args.callee(), ModulePrivateSlot));

// https://html.spec.whatwg.org/#hostgetimportmetaproperties
// Step 4.1. Set specifier to ? ToString(specifier).
//
// https://tc39.es/ecma262/#sec-tostring
RootedValue v(cx, args.get(ImportMetaResolveSpecifierArg));
RootedString specifier(cx, JS::ToString(cx, v));
if (!specifier) {
return false;
}

// Step 4.2, 4.3 are implemented in importMetaResolve.
ShellContext* scx = GetShellContext(cx);
RootedString url(cx);
if (!scx->moduleLoader->importMetaResolve(cx, modulePrivate, specifier,
&url)) {
return false;
}

// Step 4.4. Return the serialization of url.
args.rval().setString(url);
return true;
}

// static
bool ModuleLoader::ImportModuleDynamically(JSContext* cx,
JS::HandleValue referencingPrivate,
Expand Down Expand Up @@ -188,7 +217,35 @@ bool ModuleLoader::populateImportMeta(JSContext* cx,
}

RootedValue pathValue(cx, StringValue(path));
return JS_DefineProperty(cx, metaObject, "url", pathValue, JSPROP_ENUMERATE);
if (!JS_DefineProperty(cx, metaObject, "url", pathValue, JSPROP_ENUMERATE)) {
return false;
}

JSFunction* resolveFunc = js::DefineFunctionWithReserved(
cx, metaObject, "resolve", ImportMetaResolve, ImportMetaResolveNumArgs,
JSPROP_ENUMERATE);
if (!resolveFunc) {
return false;
}

RootedObject resolveFuncObj(cx, JS_GetFunctionObject(resolveFunc));
js::SetFunctionNativeReserved(resolveFuncObj, ModulePrivateSlot,
privateValue);

return true;
}

bool ModuleLoader::importMetaResolve(JSContext* cx,
JS::Handle<JS::Value> referencingPrivate,
JS::Handle<JSString*> specifier,
JS::MutableHandle<JSString*> urlOut) {
Rooted<JSLinearString*> path(cx, resolve(cx, specifier, referencingPrivate));
if (!path) {
return false;
}

urlOut.set(path);
return true;
}

bool ModuleLoader::dynamicImport(JSContext* cx,
Expand Down Expand Up @@ -308,6 +365,16 @@ JSLinearString* ModuleLoader::resolve(JSContext* cx,
return nullptr;
}

return resolve(cx, name, referencingInfo);
}

JSLinearString* ModuleLoader::resolve(JSContext* cx, HandleString specifier,
HandleValue referencingInfo) {
Rooted<JSLinearString*> name(cx, JS_EnsureLinearString(cx, specifier));
if (!name) {
return nullptr;
}

if (IsJavaScriptURL(name) || IsAbsolutePath(name)) {
return name;
}
Expand Down Expand Up @@ -362,7 +429,11 @@ JSLinearString* ModuleLoader::resolve(JSContext* cx,
return nullptr;
}

return JS_EnsureLinearString(cx, result);
Rooted<JSLinearString*> linear(cx, JS_EnsureLinearString(cx, result));
if (!linear) {
return nullptr;
}
return normalizePath(cx, linear);
}

JSObject* ModuleLoader::loadAndParse(JSContext* cx, HandleString pathArg) {
Expand Down
15 changes: 15 additions & 0 deletions js/src/shell/ModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class ModuleLoader {
HandleObject moduleRequest);
static bool GetImportMetaProperties(JSContext* cx, HandleValue privateValue,
HandleObject metaObject);
static bool ImportMetaResolve(JSContext* cx, unsigned argc, Value* vp);
static bool ImportModuleDynamically(JSContext* cx,
HandleValue referencingPrivate,
HandleObject moduleRequest,
Expand All @@ -48,6 +49,10 @@ class ModuleLoader {
HandleObject moduleRequest);
bool populateImportMeta(JSContext* cx, HandleValue privateValue,
HandleObject metaObject);
bool importMetaResolve(JSContext* cx,
JS::Handle<JS::Value> referencingPrivate,
JS::Handle<JSString*> specifier,
JS::MutableHandle<JSString*> urlOut);
bool dynamicImport(JSContext* cx, HandleValue referencingPrivate,
HandleObject moduleRequest, HandleObject promise);
bool doDynamicImport(JSContext* cx, HandleValue referencingPrivate,
Expand All @@ -62,6 +67,8 @@ class ModuleLoader {
HandleObject module);
JSLinearString* resolve(JSContext* cx, HandleObject moduleRequestArg,
HandleValue referencingInfo);
JSLinearString* resolve(JSContext* cx, HandleString specifier,
HandleValue referencingInfo);
bool getScriptPath(JSContext* cx, HandleValue privateValue,
MutableHandle<JSLinearString*> pathOut);
JSLinearString* normalizePath(JSContext* cx, Handle<JSLinearString*> path);
Expand All @@ -71,6 +78,14 @@ class ModuleLoader {
// The following are used for pinned atoms which do not need rooting.
JSAtom* loadPathStr = nullptr;
JSAtom* pathSeparatorStr = nullptr;

// The slot stored in ImportMetaResolve function.
enum { ModulePrivateSlot = 0, SlotCount };

// The number of args in ImportMetaResolve.
static const uint32_t ImportMetaResolveNumArgs = 1;
// The index of the 'specifier' argument in ImportMetaResolve.
static const uint32_t ImportMetaResolveSpecifierArg = 0;
} JS_HAZ_NON_GC_POINTER;

} // namespace shell
Expand Down

0 comments on commit acd03a2

Please sign in to comment.